* [Write documentation](#write-documentation)
* [Develop](#develop)
* [Improve the website](#improve-the-website)
- * [Troubleshooting](#troubleshooting)
- * [Tutorials](#tutorials)
## Translate
[the steps](/support/doc/dependencies.md)
to install the dependencies.
-Then clone the sources and install node modules:
+Fork the github repository,
+and then clone the sources and install node modules:
```
-$ git clone https://github.com/Chocobozzz/PeerTube
+$ git clone https://github.com/YOUR_GITHUB_USERNAME/PeerTube
$ cd PeerTube
$ yarn install --pure-lockfile
```
### Server side
-You can find a documentation of the server code/architecture [here](/support/doc/development/server/code.md).
+You can find a documentation of the server code/architecture [here](https://docs.joinpeertube.org/#/contribute-architecture?id=server-code).
To develop on the server-side:
### Client side
-You can find a documentation of the server code/architecture
-[here](/support/doc/development/client/code.md).
+You can find a documentation of the client code/architecture
+[here](https://docs.joinpeertube.org/#/contribute-architecture?id=client-code).
To develop on the client side:
Instance configurations are in `config/test-{1,2,3,4,5,6}.yaml`.
Note that only instance 2 has transcoding enabled.
-
-### Troubleshooting
-
-Please check out the issues and [list of common errors](https://docs.joinpeertube.org/lang/en/devdocs/troubleshooting.html).
-
-### Tutorials
-
-Please check out the related section in the [development documentation](https://docs.joinpeertube.org/lang/en/devdocs/index.html#tutorials). Contribute tutorials at [framagit.org/framasoft/peertube/documentation](https://framagit.org/framasoft/peertube/documentation).
# NPM instalation
/node_modules/
+/server/tools/node_modules
*npm-debug.log
# Testing
- CC=gcc-4.9 CXX=g++-4.9 yarn install
before_script:
- - wget --no-check-certificate "https://download.cpy.re/ffmpeg/ffmpeg-release-4.0.2-64bit-static.tar.xz"
- - tar xf ffmpeg-release-4.0.2-64bit-static.tar.xz
+ - wget --no-check-certificate "https://download.cpy.re/ffmpeg/ffmpeg-release-4.0.3-64bit-static.tar.xz"
+ - tar xf ffmpeg-release-4.0.3-64bit-static.tar.xz
- mkdir -p $HOME/bin
- cp ffmpeg-*/{ffmpeg,ffprobe} $HOME/bin
- export PATH=$HOME/bin:$PATH
+++ /dev/null
-# Architecture
-
-## Vocabulary
-
- - **Fediverse:** several servers following one another, several users
- following each other. Designates federated communities in general.
- - **Vidiverse:** same as Fediverse, but federating videos specifically.
- - **Instance:** a server which runs PeerTube in the fediverse.
- - **Origin instance:** the instance on which the video was uploaded and which
- is seeding (through the WebSeed protocol) the video.
- - **Cache instance:** an instance that decided to make available a WebSeed
- of its own for a video originating from another instance. It sends a `ptCache`
- activity to notify the origin instance, which will then update its list of
- WebSeeds for the video.
- - **Following:** the action of a PeerTube instance which will follow another
- instance (subscribe to its videos).
-
-## Base
-
-### Communications
- * All the communication between the instances are signed with [Linked Data
- Signatures](https://w3c-dvcg.github.io/ld-signatures/) with the private key
- of the account that authored the action.
- * We use the [ActivityPub](https://www.w3.org/TR/activitypub/) protocol (only
- server-server for now). Object models could be found in
- [shared/models/activitypub
- directory](/shared/models/activitypub).
- * All the requests are retried several times if they fail.
-
-### Instance
- * An instance has a websocket tracker which is responsible for all videos
- uploaded by its users.
- * An instance has an administrator that can follow other instances.
- * An instance can be configured to follow back automatically.
- * An instance can blacklist other instances (only used in "follow back"
- mode).
- * An instance cannot choose which other instances follow it, but it can
- decide to **reject all** followers.
- * After having uploaded a video, the instance seeds it (WebSeed protocol).
- * If a user wants to watch a video, they ask its instance the magnet URI and
- the frontend adds the torrent (with WebTorrent), creates the HTML5 video
- player and streams the file into it.
- * A user watching a video seeds it too (BitTorrent). Thus another user who is
- watching the same video can get the data from the origin server and other
- users watching it.
### Maintenance
- * Improve REST API documentation: https://docs.joinpeertube.org/api.html ([@rigelk](https://github.com/rigelk))
- * Add basic ActivityPub documentation: https://docs.joinpeertube.org/lang/en/devdocs/federation.html ([@rigelk](https://github.com/rigelk))
+ * Improve REST API documentation ([@rigelk](https://github.com/rigelk))
+ * Add basic ActivityPub documentation ([@rigelk](https://github.com/rigelk))
* Add CLI option to run PeerTube without client ([@rigelk](https://github.com/rigelk))
* Add manpage to peertube CLI ([@rigelk](https://github.com/rigelk))
* Make backups of files in optimize-old-videos script ([@Nutomic](https://github.com/nutomic))
### Maintenance
- * Improve REST API documentation: https://docs.joinpeertube.org/api.html ([@rigelk](https://github.com/rigelk))
- * Add basic ActivityPub documentation: https://docs.joinpeertube.org/lang/en/devdocs/federation.html ([@rigelk](https://github.com/rigelk))
+ * Improve REST API documentation ([@rigelk](https://github.com/rigelk))
+ * Add basic ActivityPub documentation ([@rigelk](https://github.com/rigelk))
* Add CLI option to run PeerTube without client ([@rigelk](https://github.com/rigelk))
* Add manpage to peertube CLI ([@rigelk](https://github.com/rigelk))
* Make backups of files in optimize-old-videos script ([@Nutomic](https://github.com/nutomic))
### Features
- * Video redundancy system (experimental, see [the doc](https://docs.joinpeertube.org/lang/en/devdocs/architecture.html#redundancy-between-instances))
+ * Video redundancy system (experimental)
* Add peertube script (see [the doc](/support/doc/tools.md#cli-wrapper)) ([@rigelk](https://github.com/rigelk))
* Improve download modal ([@rigelk](https://github.com/rigelk))
* Add redirect after login ([@BO41](https://github.com/BO41))
Yes, the origin server always seeds videos uploaded on it thanks to
[Webseed](http://www.bittorrent.org/beps/bep_0019.html).
-It can also be helped by other servers using [redundancy](https://docs.joinpeertube.org/lang/en/devdocs/architecture.html#redundancy-between-instances).
+It can also be helped by other servers using [redundancy](https://docs.joinpeertube.org/#/contribute-architecture?id=redundancy-between-instances).
## What is WebSeed?
<h3 align="right">Communities that help each other</h3>
<p align="right">
-In addition to visitors using WebTorrent to share the load among them, instances can help each other by caching one another's videos. This way even small instances have a way to show content to a wider audience, as they will be shouldered by friend instances (more about that in our <a href="https://docs.joinpeertube.org/lang/en/devdocs/architecture.html#redundancy-between-instances">redundancy guide</a>).
+In addition to visitors using WebTorrent to share the load among them, instances can help each other by caching one another's videos. This way even small instances have a way to show content to a wider audience, as they will be shouldered by friend instances (more about that in our <a href="https://docs.joinpeertube.org/#/contribute-architecture?id=redundancy-between-instances">redundancy guide</a>).
</p>
<p align="right">
Content creators can get help from their viewers in the simplest way possible: a support button showing a message linking to their donation accounts or really anything else. No more pay-per-view and advertisements that hurt visitors and <strike>incentivize</strike> alter creativity (more about that in our <a href="./FAQ.md">FAQ</a>).
* **yarn >= 1.x**
* **FFmpeg >= 3.x**
-See the [production guide](/support/doc/production.md), which is the recommended way.
+See the [production guide](/support/doc/production.md), which is the recommended way to install or upgrade PeerTube. For hardware requirements, see [Should I have a big server to run PeerTube?](https://github.com/Chocobozzz/PeerTube/blob/develop/FAQ.md#should-i-have-a-big-server-to-run-peertube) in the FAQ.
-See the [community packages](https://docs.joinpeertube.org/lang/en/docs/install.html), which cover various platforms (including [YunoHost](https://install-app.yunohost.org/?app=peertube) and [Docker](/support/doc/docker.md)).
+See the [community packages](https://docs.joinpeertube.org/#/install-unofficial), which cover various platforms (including [YunoHost](https://install-app.yunohost.org/?app=peertube) and [Docker](/support/doc/docker.md)).
:book: Documentation
----------------------------------------------------------------
### User documentation
-See the [user documentation](https://docs.joinpeertube.org/lang/en/userdocs/).
+See the [user documentation](https://docs.joinpeertube.org/#/use-setup-account).
### Admin documentation
See [how to create your own instance](#package-create-your-own-instance).
-See the more general [admin documentation](https://docs.joinpeertube.org/lang/en/docs/).
+See the more general [admin documentation](https://docs.joinpeertube.org/#/admin-following-instances).
#### Tools
### Technical documentation
-See the [architecture blueprint](https://docs.joinpeertube.org/lang/en/devdocs/architecture.html) for a more detailed explanation of the architectural choices.
+See the [architecture blueprint](https://docs.joinpeertube.org/#/contribute-architecture) for a more detailed explanation of the architectural choices.
See our REST API documentation:
* OpenAPI 3.0.0 schema: [/support/doc/api/openapi.yaml](/support/doc/api/openapi.yaml)
- * Spec explorer: [docs.joinpeertube.org/api.html](http://docs.joinpeertube.org/api.html)
+ * Spec explorer: [docs.joinpeertube.org/#/api-rest-reference.html](https://docs.joinpeertube.org/#/api-rest-reference.html)
-See our [ActivityPub documentation](https://docs.joinpeertube.org/lang/en/devdocs/federation.html).
+See our [ActivityPub documentation](https://docs.joinpeertube.org/#/api-activitypub).
:heart: Supports of our crowdfunding
----------------------------------------------------------------
--- /dev/null
+<div class="row" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()">
+ <div class="col-xl-6 col-md-12">
+ <div i18n class="subtitle">Followers</div>
+
+ <div i18n class="no-results" *ngIf="followersPagination.totalItems === 0">This instance does not have followers.</div>
+
+ <a *ngFor="let follower of followers" [href]="buildLink(follower)" target="_blank" rel="noopener noreferrer">
+ {{ follower }}
+ </a>
+ </div>
+
+ <div class="col-xl-6 col-md-12">
+ <div i18n class="subtitle">Followings</div>
+
+ <div i18n class="no-results" *ngIf="followingsPagination.totalItems === 0">This instance does not have followings.</div>
+
+ <a *ngFor="let following of followings" [href]="buildLink(following)" target="_blank" rel="noopener noreferrer">
+ {{ following }}
+ </a>
+ </div>
+
+</div>
--- /dev/null
+@import '_variables';
+@import '_mixins';
+
+.subtitle {
+ font-size: 18px;
+ font-weight: $font-semibold;
+ margin-bottom: 20px;
+}
+
+a {
+ display: block;
+ width: fit-content;
+ margin-top: 3px;
+}
--- /dev/null
+import { Component, OnInit } from '@angular/core'
+import { FollowService } from '@app/shared/instance/follow.service'
+import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
+import { Notifier } from '@app/core'
+import { RestService } from '@app/shared'
+import { SortMeta } from 'primeng/api'
+
+@Component({
+ selector: 'my-about-follows',
+ templateUrl: './about-follows.component.html',
+ styleUrls: [ './about-follows.component.scss' ]
+})
+
+export class AboutFollowsComponent implements OnInit {
+ followers: string[] = []
+ followings: string[] = []
+
+ followersPagination: ComponentPagination = {
+ currentPage: 1,
+ itemsPerPage: 40,
+ totalItems: null
+ }
+
+ followingsPagination: ComponentPagination = {
+ currentPage: 1,
+ itemsPerPage: 40,
+ totalItems: null
+ }
+
+ sort: SortMeta = {
+ field: 'createdAt',
+ order: -1
+ }
+
+ constructor (
+ private restService: RestService,
+ private notifier: Notifier,
+ private followService: FollowService
+ ) { }
+
+ ngOnInit () {
+ this.loadMoreFollowers()
+
+ this.loadMoreFollowings()
+ }
+
+ onNearOfBottom () {
+ this.onNearOfFollowersBottom()
+
+ this.onNearOfFollowingsBottom()
+ }
+
+ onNearOfFollowersBottom () {
+ if (!hasMoreItems(this.followersPagination)) return
+
+ this.followersPagination.currentPage += 1
+ this.loadMoreFollowers()
+ }
+
+ onNearOfFollowingsBottom () {
+ if (!hasMoreItems(this.followingsPagination)) return
+
+ this.followingsPagination.currentPage += 1
+ this.loadMoreFollowings()
+ }
+
+ buildLink (host: string) {
+ return window.location.protocol + '//' + host
+ }
+
+ private loadMoreFollowers () {
+ const pagination = this.restService.componentPaginationToRestPagination(this.followersPagination)
+
+ this.followService.getFollowers(pagination, this.sort)
+ .subscribe(
+ resultList => {
+ const newFollowers = resultList.data.map(r => r.follower.host)
+ this.followers = this.followers.concat(newFollowers)
+
+ this.followersPagination.totalItems = resultList.total
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+
+ private loadMoreFollowings () {
+ const pagination = this.restService.componentPaginationToRestPagination(this.followingsPagination)
+
+ this.followService.getFollowing(pagination, this.sort)
+ .subscribe(
+ resultList => {
+ const newFollowings = resultList.data.map(r => r.following.host)
+ this.followings = this.followings.concat(newFollowings)
+
+ this.followingsPagination.totalItems = resultList.total
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+
+}
import { AboutComponent } from './about.component'
import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component'
import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component'
+import { AboutFollowsComponent } from '@app/+about/about-follows/about-follows.component'
const aboutRoutes: Routes = [
{
title: 'About PeerTube'
}
}
+ },
+ {
+ path: 'follows',
+ component: AboutFollowsComponent,
+ data: {
+ meta: {
+ title: 'About follows'
+ }
+ }
}
]
}
<a i18n routerLink="instance" routerLinkActive="active" class="title-page">Instance</a>
<a i18n routerLink="peertube" routerLinkActive="active" class="title-page">PeerTube</a>
+
+ <a i18n routerLink="follows" routerLinkActive="active" class="title-page">Follows</a>
</div>
</div>
<div class="margin-content">
<router-outlet></router-outlet>
</div>
-</div>
\ No newline at end of file
+</div>
import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component'
import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component'
import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component'
+import { AboutFollowsComponent } from '@app/+about/about-follows/about-follows.component'
@NgModule({
imports: [
AboutComponent,
AboutInstanceComponent,
AboutPeertubeComponent,
+ AboutFollowsComponent,
ContactAdminModalComponent
],
-<div *ngIf="account" class="row">
- <a
- *ngFor="let videoChannel of videoChannels" [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]"
- class="video-channel" i18n-title title="See this video channel"
- >
- <img [src]="videoChannel.avatarUrl" alt="Avatar" />
-
- <div class="video-channel-display-name">{{ videoChannel.displayName }}</div>
- <div i18n class="video-channel-followers">{{ videoChannel.followersCount }} subscribers</div>
- </a>
-</div>
\ No newline at end of file
+<div class="margin-content">
+
+ <div class="no-results" i18n *ngIf="channelPagination.totalItems === 0">This account does not have channels.</div>
+
+ <div class="channels" myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true">
+ <div class="section channel" *ngFor="let videoChannel of videoChannels">
+ <div class="section-title">
+ <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" i18n-title title="See this video channel">
+ <img [src]="videoChannel.avatarUrl" alt="Avatar" />
+
+ <div>{{ videoChannel.displayName }}</div>
+ <div i18n class="followers">{{ videoChannel.followersCount }} subscribers</div>
+ </a>
+
+ <my-subscribe-button [videoChannel]="videoChannel"></my-subscribe-button>
+ </div>
+
+ <my-video-miniature *ngFor="let video of getVideosOf(videoChannel)" [video]="video" [user]="user" [displayVideoActions]="false"></my-video-miniature>
+ </div>
+ </div>
+</div>
@import '_variables';
@import '_mixins';
+@import '_miniature';
-.row {
- justify-content: center;
+.margin-content {
+ @include adapt-margin-content-width;
}
-a.video-channel {
- @include disable-default-a-behaviour;
+.section {
+ @include miniature-rows;
- display: inline-block;
- text-align: center;
- color: var(--mainForegroundColor);
- margin: 10px 30px;
+ padding-top: 0 !important;
- img {
- @include avatar(80px);
-
- margin-bottom: 10px;
- }
-
- .video-channel-display-name {
- font-size: 20px;
- font-weight: $font-bold;
+ .section-title {
+ align-items: center;
}
-
- .video-channel-followers {
- font-size: 15px;
- }
-}
\ No newline at end of file
+}
import { Account } from '@app/shared/account/account.model'
import { AccountService } from '@app/shared/account/account.service'
import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
-import { flatMap, map, tap } from 'rxjs/operators'
-import { Subscription } from 'rxjs'
+import { concatMap, map, switchMap, tap } from 'rxjs/operators'
+import { from, Subscription } from 'rxjs'
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
+import { Video } from '@app/shared/video/video.model'
+import { AuthService } from '@app/core'
+import { VideoService } from '@app/shared/video/video.service'
+import { VideoSortField } from '@app/shared/video/sort-field.type'
+import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
@Component({
selector: 'my-account-video-channels',
export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
account: Account
videoChannels: VideoChannel[] = []
+ videos: { [id: number]: Video[] } = {}
+
+ channelPagination: ComponentPagination = {
+ currentPage: 1,
+ itemsPerPage: 2
+ }
+
+ videosPagination: ComponentPagination = {
+ currentPage: 1,
+ itemsPerPage: 12
+ }
+ videosSort: VideoSortField = '-publishedAt'
private accountSub: Subscription
constructor (
- protected route: ActivatedRoute,
+ private route: ActivatedRoute,
+ private authService: AuthService,
private accountService: AccountService,
- private videoChannelService: VideoChannelService
+ private videoChannelService: VideoChannelService,
+ private videoService: VideoService
) { }
+ get user () {
+ return this.authService.getUser()
+ }
+
ngOnInit () {
// Parent get the account for us
this.accountSub = this.accountService.accountLoaded
- .pipe(
- tap(account => this.account = account),
- flatMap(account => this.videoChannelService.listAccountVideoChannels(account)),
- map(res => res.data)
- )
- .subscribe(videoChannels => this.videoChannels = videoChannels)
+ .subscribe(account => {
+ this.account = account
+
+ this.loadMoreChannels()
+ })
}
ngOnDestroy () {
if (this.accountSub) this.accountSub.unsubscribe()
}
+
+ loadMoreChannels () {
+ this.videoChannelService.listAccountVideoChannels(this.account, this.channelPagination)
+ .pipe(
+ tap(res => this.channelPagination.totalItems = res.total),
+ switchMap(res => from(res.data)),
+ concatMap(videoChannel => {
+ return this.videoService.getVideoChannelVideos(videoChannel, this.videosPagination, this.videosSort)
+ .pipe(map(data => ({ videoChannel, videos: data.videos })))
+ })
+ )
+ .subscribe(({ videoChannel, videos }) => {
+ this.videoChannels.push(videoChannel)
+
+ this.videos[videoChannel.id] = videos
+ })
+ }
+
+ getVideosOf (videoChannel: VideoChannel) {
+ return this.videos[ videoChannel.id ] || []
+ }
+
+ onNearOfBottom () {
+ if (!hasMoreItems(this.channelPagination)) return
+
+ this.channelPagination.currentPage += 1
+
+ this.loadMoreChannels()
+ }
}
private accountSub: Subscription
constructor (
+ protected i18n: I18n,
protected router: Router,
protected serverService: ServerService,
protected route: ActivatedRoute,
protected notifier: Notifier,
protected confirmService: ConfirmService,
protected screenService: ScreenService,
- private i18n: I18n,
private accountService: AccountService,
private videoService: VideoService
) {
super()
-
- this.titlePage = this.i18n('Published videos')
}
ngOnInit () {
children: [
{
path: '',
- redirectTo: 'videos',
+ redirectTo: 'video-channels',
pathMatch: 'full'
},
{
</div>
<div class="links">
- <a i18n routerLink="videos" routerLinkActive="active" class="title-page">Videos</a>
-
<a i18n routerLink="video-channels" routerLinkActive="active" class="title-page">Video channels</a>
+ <a i18n routerLink="videos" routerLinkActive="active" class="title-page">Videos</a>
+
<a i18n routerLink="about" routerLinkActive="active" class="title-page">About</a>
</div>
</div>
import { SharedModule } from '../shared'
import { AdminRoutingModule } from './admin-routing.module'
import { AdminComponent } from './admin.component'
-import { FollowersListComponent, FollowingAddComponent, FollowsComponent, FollowService } from './follows'
+import { FollowersListComponent, FollowingAddComponent, FollowsComponent } from './follows'
import { FollowingListComponent } from './follows/following-list/following-list.component'
import { UserCreateComponent, UserListComponent, UserPasswordComponent, UsersComponent, UserUpdateComponent } from './users'
import {
],
providers: [
- FollowService,
RedundancyService,
JobService,
LogsService,
></my-peertube-checkbox>
</div>
+ <div class="form-group">
+ <my-peertube-checkbox
+ inputName="transcodingAllowAudioFiles" formControlName="allowAudioFiles"
+ i18n-labelText labelText="Allow audio files upload"
+ i18n-helpHtml helpHtml="Allow your users to upload audio files that will be merged with the preview file on upload"
+ ></my-peertube-checkbox>
+ </div>
+
<div class="form-group">
<label i18n for="transcodingThreads">Transcoding threads</label>
<div class="peertube-select-container">
enabled: null,
threads: this.customConfigValidatorsService.TRANSCODING_THREADS,
allowAdditionalExtensions: null,
+ allowAudioFiles: null,
resolutions: {}
},
autoBlacklist: {
import { SortMeta } from 'primeng/primeng'
import { ActorFollow } from '../../../../../../shared/models/actors/follow.model'
import { RestPagination, RestTable } from '../../../shared'
-import { FollowService } from '../shared'
+import { FollowService } from '@app/shared/instance/follow.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({
import { Notifier } from '@app/core'
import { ConfirmService } from '../../../core'
import { validateHost } from '../../../shared'
-import { FollowService } from '../shared'
+import { FollowService } from '@app/shared/instance/follow.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({
import { ActorFollow } from '../../../../../../shared/models/actors/follow.model'
import { ConfirmService } from '../../../core/confirm/confirm.service'
import { RestPagination, RestTable } from '../../../shared'
-import { FollowService } from '../shared'
+import { FollowService } from '@app/shared/instance/follow.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({
export * from './following-add'
export * from './followers-list'
export * from './following-list'
-export * from './shared'
export * from './follows.component'
export * from './follows.routes'
+++ /dev/null
-export * from './follow.service'
export abstract class UserEdit extends FormReactive {
videoQuotaOptions: { value: string, label: string }[] = []
videoQuotaDailyOptions: { value: string, label: string }[] = []
- roles = Object.keys(USER_ROLE_LABELS).map(key => ({ value: key.toString(), label: USER_ROLE_LABELS[key] }))
+ roles = Object.keys(USER_ROLE_LABELS)
+ .map(key => ({ value: key.toString(), label: USER_ROLE_LABELS[key] }))
username: string
userId: number
const transcodingConfig = this.serverService.getConfig().transcoding
const resolutions = transcodingConfig.enabledResolutions
- const higherResolution = VideoResolution.H_1080P
+ const higherResolution = VideoResolution.H_4K
let multiplier = 0
for (const resolution of resolutions) {
videosHistoryEnabled: boolean
constructor (
+ protected i18n: I18n,
protected router: Router,
protected serverService: ServerService,
protected route: ActivatedRoute,
protected userService: UserService,
protected notifier: Notifier,
protected screenService: ScreenService,
- protected i18n: I18n,
private confirmService: ConfirmService,
private videoService: VideoService,
private userHistoryService: UserHistoryService
</div>
</div>
+ <div class="form-group" *ngIf="isBulkUpdateVideosDisplayed()">
+ <my-peertube-checkbox
+ inputName="bulkVideosSupportUpdate" formControlName="bulkVideosSupportUpdate"
+ i18n-labelText labelText="Overwrite support field of all videos of this channel"
+ ></my-peertube-checkbox>
+ </div>
+
<input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid">
</form>
// FIXME: We need this method so angular does not complain in the child template
onAvatarChange (formData: FormData) { /* empty */ }
+
+ // Should be implemented by the child
+ isBulkUpdateVideosDisplayed () {
+ return false
+ }
}
videoChannelToUpdate: VideoChannel
private paramsSub: Subscription
+ private oldSupportField: string
constructor (
protected formValidatorService: FormValidatorService,
this.buildForm({
'display-name': this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME,
description: this.videoChannelValidatorsService.VIDEO_CHANNEL_DESCRIPTION,
- support: this.videoChannelValidatorsService.VIDEO_CHANNEL_SUPPORT
+ support: this.videoChannelValidatorsService.VIDEO_CHANNEL_SUPPORT,
+ bulkVideosSupportUpdate: null
})
this.paramsSub = this.route.params.subscribe(routeParams => {
videoChannelToUpdate => {
this.videoChannelToUpdate = videoChannelToUpdate
+ this.oldSupportField = videoChannelToUpdate.support
+
this.form.patchValue({
'display-name': videoChannelToUpdate.displayName,
description: videoChannelToUpdate.description,
const videoChannelUpdate: VideoChannelUpdate = {
displayName: body['display-name'],
description: body.description || null,
- support: body.support || null
+ support: body.support || null,
+ bulkVideosSupportUpdate: body.bulkVideosSupportUpdate || false
}
this.videoChannelService.updateVideoChannel(this.videoChannelToUpdate.name, videoChannelUpdate).subscribe(
getFormButtonTitle () {
return this.i18n('Update')
}
+
+ isBulkUpdateVideosDisplayed () {
+ if (this.oldSupportField === undefined) return false
+
+ return this.oldSupportField !== this.form.value['support']
+ }
}
import { VideoPlaylistValidatorsService } from '@app/shared'
import { VideoPlaylistCreate } from '@shared/models/videos/playlist/video-playlist-create.model'
import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
-import { VideoConstant } from '@shared/models'
import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model'
import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils'
})
export class MyAccountVideoPlaylistCreateComponent extends MyAccountVideoPlaylistEdit implements OnInit {
error: string
- videoPlaylistPrivacies: VideoConstant<VideoPlaylistPrivacy>[] = []
constructor (
protected formValidatorService: FormValidatorService,
})
populateAsyncUserVideoChannels(this.authService, this.userVideoChannels)
+ .catch(err => console.error('Cannot populate user video channels.', err))
this.serverService.videoPlaylistPrivaciesLoaded.subscribe(
() => {
</div>
<div class="form-group">
- <my-image-upload
- i18n-inputLabel inputLabel="Upload thumbnail" inputName="thumbnailfile" formControlName="thumbnailfile"
- previewWidth="200px" previewHeight="110px"
- ></my-image-upload>
+ <label i18n>Playlist thumbnail</label>
+
+ <my-preview-upload
+ i18n-inputLabel inputLabel="Edit" inputName="thumbnailfile" formControlName="thumbnailfile"
+ previewWidth="223px" previewHeight="122px"
+ ></my-preview-upload>
</div>
</div>
</div>
import { FormReactive } from '@app/shared'
-import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
-import { ServerService } from '@app/core'
import { VideoPlaylist } from '@shared/models/videos/playlist/video-playlist.model'
+import { VideoConstant, VideoPlaylistPrivacy } from '@shared/models'
export abstract class MyAccountVideoPlaylistEdit extends FormReactive {
// Declare it here to avoid errors in create template
videoPlaylistToUpdate: VideoPlaylist
userVideoChannels: { id: number, label: string }[] = []
+ videoPlaylistPrivacies: VideoConstant<VideoPlaylistPrivacy>[] = []
abstract isCreation (): boolean
abstract getFormButtonTitle (): string
import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
import { VideoPlaylistValidatorsService } from '@app/shared'
import { VideoPlaylistUpdate } from '@shared/models/videos/playlist/video-playlist-update.model'
-import { VideoConstant } from '@shared/models'
-import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model'
import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
+import { delayWhen, map, switchMap } from 'rxjs/operators'
@Component({
selector: 'my-account-video-playlist-update',
export class MyAccountVideoPlaylistUpdateComponent extends MyAccountVideoPlaylistEdit implements OnInit, OnDestroy {
error: string
videoPlaylistToUpdate: VideoPlaylist
- videoPlaylistPrivacies: VideoConstant<VideoPlaylistPrivacy>[] = []
private paramsSub: Subscription
})
populateAsyncUserVideoChannels(this.authService, this.userVideoChannels)
-
- this.paramsSub = this.route.params.subscribe(routeParams => {
- const videoPlaylistId = routeParams['videoPlaylistId']
-
- this.videoPlaylistService.getVideoPlaylist(videoPlaylistId).subscribe(
- videoPlaylistToUpdate => {
- this.videoPlaylistToUpdate = videoPlaylistToUpdate
-
- this.hydrateFormFromPlaylist()
-
- this.serverService.videoPlaylistPrivaciesLoaded.subscribe(
- () => {
- this.videoPlaylistPrivacies = this.serverService.getVideoPlaylistPrivacies()
- .filter(p => {
- // If the playlist is not private, we cannot put it in private anymore
- return this.videoPlaylistToUpdate.privacy.id === VideoPlaylistPrivacy.PRIVATE ||
- p.id !== VideoPlaylistPrivacy.PRIVATE
- })
- }
- )
- },
-
- err => this.error = err.message
- )
- })
+ .catch(err => console.error('Cannot populate user video channels.', err))
+
+ this.paramsSub = this.route.params
+ .pipe(
+ map(routeParams => routeParams['videoPlaylistId']),
+ switchMap(videoPlaylistId => this.videoPlaylistService.getVideoPlaylist(videoPlaylistId)),
+ delayWhen(() => this.serverService.videoPlaylistPrivaciesLoaded)
+ )
+ .subscribe(
+ videoPlaylistToUpdate => {
+ this.videoPlaylistPrivacies = this.serverService.getVideoPlaylistPrivacies()
+ this.videoPlaylistToUpdate = videoPlaylistToUpdate
+
+ this.hydrateFormFromPlaylist()
+ },
+
+ err => this.error = err.message
+ )
}
ngOnDestroy () {
<my-edit-button [routerLink]="[ '/videos', 'update', video.uuid ]"></my-edit-button>
<my-button i18n-label label="Change ownership"
- className="action-button-change-ownership"
+ className="action-button-change-ownership grey-button"
icon="im-with-her"
(click)="changeOwnership($event, video)"
></my-button>
--- /dev/null
+<section class="container">
+ <header>
+ <ng-container *ngFor="let step of steps; let i = index; let isLast = last;">
+ <div
+ class="step-info" [ngClass]="{ active: selectedIndex === i, completed: isCompleted(step) }"
+ (click)="onClick(i)"
+ >
+ <div class="step-index">
+ <ng-container *ngIf="!isCompleted(step)">{{ i + 1 }}</ng-container>
+ <my-global-icon *ngIf="isCompleted(step)" iconName="tick"></my-global-icon>
+ </div>
+
+ <div class="step-label">{{ step.label }}</div>
+ </div>
+
+ <!-- Do no display if this is the last child -->
+ <div *ngIf="!isLast" class="connector"></div>
+ </ng-container>
+ </header>
+
+ <div [style.display]="selected ? 'block' : 'none'">
+ <ng-container [ngTemplateOutlet]="selected.content"></ng-container>
+ </div>
+
+</section>
--- /dev/null
+@import '_variables';
+@import '_mixins';
+
+$grey-color: #9CA3AB;
+$index-block-height: 32px;
+
+header {
+ display: flex;
+ justify-content: space-between;
+ font-size: 15px;
+ margin-bottom: 30px;
+
+ .step-info {
+ color: $grey-color;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: $index-block-height;
+
+ .step-index {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: $index-block-height;
+ height: $index-block-height;
+ border-radius: 100px;
+ border: 2px solid $grey-color;
+ margin-bottom: 10px;
+
+ my-global-icon {
+ @include apply-svg-color(var(--mainBackgroundColor));
+
+ width: 22px;
+ height: 22px;
+ }
+ }
+
+ .step-label {
+ width: max-content;
+ }
+
+ &.active,
+ &.completed {
+ .step-index {
+ border-color: var(--mainColor);
+ background-color: var(--mainColor);
+ color: var(--mainBackgroundColor);
+ }
+
+ .step-label {
+ color: var(--mainColor);
+ }
+ }
+
+ &.completed {
+ cursor: pointer;
+ }
+ }
+
+ .connector {
+ flex: auto;
+ margin: $index-block-height/2 10px 0 10px;
+ height: 2px;
+ background-color: $grey-color;
+ }
+}
--- /dev/null
+import { Component } from '@angular/core'
+import { CdkStep, CdkStepper } from '@angular/cdk/stepper'
+
+@Component({
+ selector: 'my-custom-stepper',
+ templateUrl: './custom-stepper.component.html',
+ styleUrls: [ './custom-stepper.component.scss' ],
+ providers: [ { provide: CdkStepper, useExisting: CustomStepperComponent } ]
+})
+export class CustomStepperComponent extends CdkStepper {
+
+ onClick (index: number): void {
+ this.selectedIndex = index
+ }
+
+ isCompleted (step: CdkStep) {
+ return step.stepControl && step.stepControl.dirty && step.stepControl.valid
+ }
+}
import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'
import { MetaGuard } from '@ngx-meta/core'
-import { SignupComponent } from './signup.component'
+import { RegisterComponent } from './register.component'
import { ServerConfigResolver } from '@app/core/routing/server-config-resolver.service'
+import { UnloggedGuard } from '@app/core/routing/unlogged-guard.service'
-const signupRoutes: Routes = [
+const registerRoutes: Routes = [
{
- path: 'signup',
- component: SignupComponent,
- canActivate: [ MetaGuard ],
+ path: '',
+ component: RegisterComponent,
+ canActivate: [ MetaGuard, UnloggedGuard ],
data: {
meta: {
- title: 'Signup'
+ title: 'Register'
}
},
resolve: {
]
@NgModule({
- imports: [ RouterModule.forChild(signupRoutes) ],
+ imports: [ RouterModule.forChild(registerRoutes) ],
exports: [ RouterModule ]
})
-export class SignupRoutingModule {}
+export class RegisterRoutingModule {}
--- /dev/null
+<form role="form" [formGroup]="form">
+
+ <div class="channel-explanations">
+ <p i18n>
+ A channel is an entity in which you upload your videos. Creating several of them helps you to organize and separate your content.<br />
+ For example, you could decide to have a channel to publish your piano concerts, and another channel in which you publish your videos talking about ecology.
+ </p>
+
+ <p>
+ Other users can decide to subscribe any channel they want, to be notified when you publish a new video.
+ </p>
+ </div>
+
+ <div class="form-group">
+ <label for="name" i18n>Channel name</label>
+
+ <div class="input-group">
+ <input
+ type="text" id="name" i18n-placeholder placeholder="Example: my_super_channel"
+ formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }"
+ >
+ <div class="input-group-append">
+ <span class="input-group-text">@{{ instanceHost }}</span>
+ </div>
+ </div>
+
+ <div *ngIf="formErrors.name" class="form-error">
+ {{ formErrors.name }}
+ </div>
+
+ <div *ngIf="isSameThanUsername()" class="form-error" i18n>
+ Channel name cannot be the same than your account name. You can click on the first step to update your account name.
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="displayName" i18n>Channel display name</label>
+
+ <div class="input-group">
+ <input
+ type="text" id="displayName"
+ formControlName="displayName" [ngClass]="{ 'input-error': formErrors['displayName'] }"
+ >
+ </div>
+
+ <div *ngIf="formErrors.displayName" class="form-error">
+ {{ formErrors.displayName }}
+ </div>
+ </div>
+</form>
--- /dev/null
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
+import { AuthService } from '@app/core'
+import { FormReactive, VideoChannelValidatorsService } from '@app/shared'
+import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
+import { FormGroup } from '@angular/forms'
+
+@Component({
+ selector: 'my-register-step-channel',
+ templateUrl: './register-step-channel.component.html',
+ styleUrls: [ './register.component.scss' ]
+})
+export class RegisterStepChannelComponent extends FormReactive implements OnInit {
+ @Input() username: string
+ @Output() formBuilt = new EventEmitter<FormGroup>()
+
+ constructor (
+ protected formValidatorService: FormValidatorService,
+ private authService: AuthService,
+ private videoChannelValidatorsService: VideoChannelValidatorsService
+ ) {
+ super()
+ }
+
+ get instanceHost () {
+ return window.location.host
+ }
+
+ isSameThanUsername () {
+ return this.username && this.username === this.form.value['name']
+ }
+
+ ngOnInit () {
+ this.buildForm({
+ name: this.videoChannelValidatorsService.VIDEO_CHANNEL_NAME,
+ displayName: this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME
+ })
+
+ setTimeout(() => this.formBuilt.emit(this.form))
+ }
+}
--- /dev/null
+<form role="form" [formGroup]="form">
+
+ <div class="form-group">
+ <label for="username" i18n>Username</label>
+
+ <div class="input-group">
+ <input
+ type="text" id="username" i18n-placeholder placeholder="Example: jane_doe"
+ formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }"
+ >
+ <div class="input-group-append">
+ <span class="input-group-text">@{{ instanceHost }}</span>
+ </div>
+ </div>
+
+ <div *ngIf="formErrors.username" class="form-error">
+ {{ formErrors.username }}
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="email" i18n>Email</label>
+ <input
+ type="text" id="email" i18n-placeholder placeholder="Email"
+ formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }"
+ >
+ <div *ngIf="formErrors.email" class="form-error">
+ {{ formErrors.email }}
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="password" i18n>Password</label>
+ <input
+ type="password" id="password" i18n-placeholder placeholder="Password"
+ formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
+ >
+ <div *ngIf="formErrors.password" class="form-error">
+ {{ formErrors.password }}
+ </div>
+ </div>
+
+ <div class="form-group form-group-terms">
+ <my-peertube-checkbox
+ inputName="terms" formControlName="terms"
+ i18n-labelHtml
+ labelHtml="I am at least 16 years old and agree to the <a href='/about/instance#terms-section' target='_blank'rel='noopener noreferrer'>Terms</a> of this instance"
+ ></my-peertube-checkbox>
+
+ <div *ngIf="formErrors.terms" class="form-error">
+ {{ formErrors.terms }}
+ </div>
+ </div>
+</form>
--- /dev/null
+import { Component, EventEmitter, OnInit, Output } from '@angular/core'
+import { AuthService } from '@app/core'
+import { FormReactive, UserValidatorsService } from '@app/shared'
+import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
+import { FormGroup } from '@angular/forms'
+
+@Component({
+ selector: 'my-register-step-user',
+ templateUrl: './register-step-user.component.html',
+ styleUrls: [ './register.component.scss' ]
+})
+export class RegisterStepUserComponent extends FormReactive implements OnInit {
+ @Output() formBuilt = new EventEmitter<FormGroup>()
+
+ constructor (
+ protected formValidatorService: FormValidatorService,
+ private authService: AuthService,
+ private userValidatorsService: UserValidatorsService
+ ) {
+ super()
+ }
+
+ get instanceHost () {
+ return window.location.host
+ }
+
+ ngOnInit () {
+ this.buildForm({
+ username: this.userValidatorsService.USER_USERNAME,
+ password: this.userValidatorsService.USER_PASSWORD,
+ email: this.userValidatorsService.USER_EMAIL,
+ terms: this.userValidatorsService.USER_TERMS
+ })
+
+ setTimeout(() => this.formBuilt.emit(this.form))
+ }
+}
--- /dev/null
+<div class="margin-content">
+
+ <div i18n class="title-page title-page-single">
+ Create an account
+ </div>
+
+ <my-signup-success *ngIf="signupDone" [message]="success"></my-signup-success>
+ <div *ngIf="info" class="alert alert-info">{{ info }}</div>
+
+ <div class="wrapper" *ngIf="!signupDone">
+ <div>
+ <my-custom-stepper linear *ngIf="!signupDone">
+ <cdk-step [stepControl]="formStepUser" i18n-label label="User information">
+ <my-register-step-user (formBuilt)="onUserFormBuilt($event)"></my-register-step-user>
+
+ <button i18n cdkStepperNext [disabled]="!formStepUser || !formStepUser.valid">Next</button>
+ </cdk-step>
+
+ <cdk-step [stepControl]="formStepChannel" i18n-label label="Channel information">
+ <my-register-step-channel (formBuilt)="onChannelFormBuilt($event)" [username]="getUsername()"></my-register-step-channel>
+
+ <button i18n cdkStepperNext (click)="signup()"
+ [disabled]="!formStepChannel || !formStepChannel.valid || hasSameChannelAndAccountNames()"
+ >
+ Create my account
+ </button>
+ </cdk-step>
+
+ <cdk-step i18n-label label="Done" editable="false">
+ <div *ngIf="error" class="alert alert-danger">{{ error }}</div>
+ </cdk-step>
+ </my-custom-stepper>
+ </div>
+
+ <div>
+ <label i18n>Features found on this instance</label>
+ <my-instance-features-table></my-instance-features-table>
+ </div>
+ </div>
+
+</div>
@import '_variables';
@import '_mixins';
+.alert {
+ font-size: 15px;
+ text-align: center;
+}
+
+.wrapper {
+ display: flex;
+ justify-content: space-between;
+ flex-wrap: wrap;
+
+ & > div {
+ margin-bottom: 40px;
+ width: 450px;
+
+ @media screen and (max-width: 500px) {
+ width: auto;
+ }
+ }
+}
+
my-instance-features-table {
display: block;
margin-bottom: 40px;
}
-form {
- margin: 0 60px 40px 0;
-}
-
.form-group-terms {
margin: 30px 0;
}
input:not([type=submit]) {
@include peertube-input-text(400px);
+
display: block;
- &#username {
- width: auto;
+ &#username,
+ &#name {
+ width: auto !important;
flex-grow: 1;
}
}
-input[type=submit] {
+input[type=submit],
+button {
@include peertube-button;
@include orange-button;
}
--- /dev/null
+import { Component } from '@angular/core'
+import { AuthService, Notifier, RedirectService, ServerService } from '@app/core'
+import { UserService, UserValidatorsService } from '@app/shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
+import { UserRegister } from '@shared/models/users/user-register.model'
+import { FormGroup } from '@angular/forms'
+
+@Component({
+ selector: 'my-register',
+ templateUrl: './register.component.html',
+ styleUrls: [ './register.component.scss' ]
+})
+export class RegisterComponent {
+ info: string = null
+ error: string = null
+ success: string = null
+ signupDone = false
+
+ formStepUser: FormGroup
+ formStepChannel: FormGroup
+
+ constructor (
+ private authService: AuthService,
+ private userValidatorsService: UserValidatorsService,
+ private notifier: Notifier,
+ private userService: UserService,
+ private serverService: ServerService,
+ private redirectService: RedirectService,
+ private i18n: I18n
+ ) {
+ }
+
+ get requiresEmailVerification () {
+ return this.serverService.getConfig().signup.requiresEmailVerification
+ }
+
+ hasSameChannelAndAccountNames () {
+ return this.getUsername() === this.getChannelName()
+ }
+
+ getUsername () {
+ if (!this.formStepUser) return undefined
+
+ return this.formStepUser.value['username']
+ }
+
+ getChannelName () {
+ if (!this.formStepChannel) return undefined
+
+ return this.formStepChannel.value['name']
+ }
+
+ onUserFormBuilt (form: FormGroup) {
+ this.formStepUser = form
+ }
+
+ onChannelFormBuilt (form: FormGroup) {
+ this.formStepChannel = form
+ }
+
+ signup () {
+ this.error = null
+
+ const body: UserRegister = Object.assign(this.formStepUser.value, { channel: this.formStepChannel.value })
+
+ this.userService.signup(body).subscribe(
+ () => {
+ this.signupDone = true
+
+ if (this.requiresEmailVerification) {
+ this.info = this.i18n('Now please check your emails to verify your account and complete signup.')
+ return
+ }
+
+ // Auto login
+ this.authService.login(body.username, body.password)
+ .subscribe(
+ () => {
+ this.success = this.i18n('You are now logged in as {{username}}!', { username: body.username })
+ },
+
+ err => this.error = err.message
+ )
+ },
+
+ err => this.error = err.message
+ )
+ }
+}
--- /dev/null
+import { NgModule } from '@angular/core'
+import { RegisterRoutingModule } from './register-routing.module'
+import { RegisterComponent } from './register.component'
+import { SharedModule } from '@app/shared'
+import { CdkStepperModule } from '@angular/cdk/stepper'
+import { RegisterStepChannelComponent } from './register-step-channel.component'
+import { RegisterStepUserComponent } from './register-step-user.component'
+import { CustomStepperComponent } from './custom-stepper.component'
+import { SignupSharedModule } from '@app/+signup/shared/signup-shared.module'
+
+@NgModule({
+ imports: [
+ RegisterRoutingModule,
+ SharedModule,
+ CdkStepperModule,
+ SignupSharedModule
+ ],
+
+ declarations: [
+ RegisterComponent,
+ CustomStepperComponent,
+ RegisterStepChannelComponent,
+ RegisterStepUserComponent
+ ],
+
+ exports: [
+ RegisterComponent
+ ],
+
+ providers: [
+ ]
+})
+export class RegisterModule { }
Verify account email confirmation
</div>
- <div i18n *ngIf="success; else verificationError">
- Your email has been verified and you may now login. Redirecting...
- </div>
+ <my-signup-success i18n *ngIf="success; else verificationError" message="Your email has been verified and you may now login.">
+ </my-signup-success>
+
<ng-template #verificationError>
<div>
<span i18n>An error occurred. </span>
.subscribe(
() => {
this.success = true
- setTimeout(() => {
- this.router.navigate([ '/login' ])
- }, 2000)
},
err => {
import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'
-
import { MetaGuard } from '@ngx-meta/core'
-
-import { VerifyAccountEmailComponent } from '@app/+verify-account/verify-account-email/verify-account-email.component'
-import {
- VerifyAccountAskSendEmailComponent
-} from '@app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component'
+import { VerifyAccountEmailComponent } from './verify-account-email/verify-account-email.component'
+import { VerifyAccountAskSendEmailComponent } from './verify-account-ask-send-email/verify-account-ask-send-email.component'
const verifyAccountRoutes: Routes = [
{
--- /dev/null
+import { NgModule } from '@angular/core'
+import { VerifyAccountRoutingModule } from './verify-account-routing.module'
+import { VerifyAccountEmailComponent } from './verify-account-email/verify-account-email.component'
+import { VerifyAccountAskSendEmailComponent } from './verify-account-ask-send-email/verify-account-ask-send-email.component'
+import { SharedModule } from '@app/shared'
+import { SignupSharedModule } from '@app/+signup/shared/signup-shared.module'
+
+@NgModule({
+ imports: [
+ VerifyAccountRoutingModule,
+ SharedModule,
+ SignupSharedModule
+ ],
+
+ declarations: [
+ VerifyAccountEmailComponent,
+ VerifyAccountAskSendEmailComponent
+ ],
+
+ exports: [],
+
+ providers: []
+})
+export class VerifyAccountModule {
+}
--- /dev/null
+import { NgModule } from '@angular/core'
+import { SignupSuccessComponent } from '../shared/signup-success.component'
+import { SharedModule } from '@app/shared'
+
+@NgModule({
+ imports: [
+ SharedModule
+ ],
+
+ declarations: [
+ SignupSuccessComponent
+ ],
+
+ exports: [
+ SignupSuccessComponent
+ ],
+
+ providers: [
+ ]
+})
+export class SignupSharedModule { }
--- /dev/null
+<!-- Thanks: Amit Singh Sansoya from https://codepen.io/amit3200/pen/zWMJOO -->
+
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 130.2 130.2">
+ <circle class="path circle" fill="none" stroke="#73AF55" stroke-width="6" stroke-miterlimit="10" cx="65.1" cy="65.1" r="62.1"/>
+ <polyline class="path check" fill="none" stroke="#73AF55" stroke-width="6" stroke-linecap="round" stroke-miterlimit="10" points="100.2,40.2 51.5,88.8 29.8,67.5 "/>
+</svg>
+
+<p class="bottom-message">Welcome on PeerTube!</p>
+
+<div *ngIf="message" class="alert alert-success">
+ <p>{{ message }}</p>
+
+ <p i18n>
+ If you need help to use PeerTube, you can take a look to the <a href="https://docs.joinpeertube.org/#/use-setup-account" target="_blank" rel="noopener noreferrer">documentation</a>.
+ </p>
+</div>
--- /dev/null
+svg {
+ width: 100px;
+ display: block;
+ margin: 40px auto 0;
+}
+
+.path {
+ stroke-dasharray: 1000;
+ stroke-dashoffset: 0;
+
+ &.circle {
+ -webkit-animation: dash .9s ease-in-out;
+ animation: dash .9s ease-in-out;
+ }
+
+ &.line {
+ stroke-dashoffset: 1000;
+ -webkit-animation: dash .9s .35s ease-in-out forwards;
+ animation: dash .9s .35s ease-in-out forwards;
+ }
+
+ &.check {
+ stroke-dashoffset: -100;
+ -webkit-animation: dash-check .9s .35s ease-in-out forwards;
+ animation: dash-check .9s .35s ease-in-out forwards;
+ }
+}
+
+.bottom-message {
+ text-align: center;
+ margin: 20px 0 60px;
+ font-size: 1.25em;
+ color: #73AF55;
+}
+
+.alert {
+ font-size: 15px;
+ text-align: center;
+}
+
+
+@-webkit-keyframes dash {
+ 0% {
+ stroke-dashoffset: 1000;
+ }
+ 100% {
+ stroke-dashoffset: 0;
+ }
+}
+
+@keyframes dash {
+ 0% {
+ stroke-dashoffset: 1000;
+ }
+ 100% {
+ stroke-dashoffset: 0;
+ }
+}
+
+@-webkit-keyframes dash-check {
+ 0% {
+ stroke-dashoffset: -100;
+ }
+ 100% {
+ stroke-dashoffset: 900;
+ }
+}
+
+@keyframes dash-check {
+ 0% {
+ stroke-dashoffset: -100;
+ }
+ 100% {
+ stroke-dashoffset: 900;
+ }
+}
--- /dev/null
+import { Component, Input } from '@angular/core'
+
+@Component({
+ selector: 'my-signup-success',
+ templateUrl: './signup-success.component.html',
+ styleUrls: [ './signup-success.component.scss' ]
+})
+export class SignupSuccessComponent {
+ @Input() message: string
+}
+++ /dev/null
-export * from '@app/+verify-account/verify-account-routing.module'
-export * from '@app/+verify-account/verify-account.module'
+++ /dev/null
-import { NgModule } from '@angular/core'
-
-import { VerifyAccountRoutingModule } from '@app/+verify-account/verify-account-routing.module'
-import { VerifyAccountEmailComponent } from '@app/+verify-account/verify-account-email/verify-account-email.component'
-import {
- VerifyAccountAskSendEmailComponent
-} from '@app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component'
-import { SharedModule } from '@app/shared'
-
-@NgModule({
- imports: [
- VerifyAccountRoutingModule,
- SharedModule
- ],
-
- declarations: [
- VerifyAccountEmailComponent,
- VerifyAccountAskSendEmailComponent
- ],
-
- exports: [
- ],
-
- providers: [
- ]
-})
-export class VerifyAccountModule { }
import { Subscription } from 'rxjs'
import { Notifier } from '@app/core'
import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
-import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
+import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
@Component({
}
onNearOfBottom () {
- // Last page
- if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return
+ if (!hasMoreItems(this.pagination)) return
this.pagination.currentPage += 1
this.loadVideoPlaylists()
private videoChannelSub: Subscription
constructor (
+ protected i18n: I18n,
protected router: Router,
protected serverService: ServerService,
protected route: ActivatedRoute,
protected notifier: Notifier,
protected confirmService: ConfirmService,
protected screenService: ScreenService,
- private i18n: I18n,
private videoChannelService: VideoChannelService,
private videoService: VideoService
) {
},
{
path: 'verify-account',
- loadChildren: './+verify-account/verify-account.module#VerifyAccountModule'
+ loadChildren: './+signup/+verify-account/verify-account.module#VerifyAccountModule'
},
{
path: 'accounts',
path: 'about',
loadChildren: './+about/about.module#AboutModule'
},
+ {
+ path: 'signup',
+ loadChildren: './+signup/+register/register.module#RegisterModule'
+ },
{
path: '',
component: AppComponent // Avoid 404, app component will redirect dynamically
import { LoginModule } from './login'
import { AvatarNotificationComponent, LanguageChooserComponent, MenuComponent } from './menu'
import { SharedModule } from './shared'
-import { SignupModule } from './signup'
import { VideosModule } from './videos'
import { buildFileLocale, getCompleteLocale, isDefaultLocale } from '../../../shared/models/i18n'
import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
CoreModule,
LoginModule,
ResetPasswordModule,
- SignupModule,
SearchModule,
SharedModule,
VideosModule,
import { MessageService } from 'primeng/api'
import { UserNotificationSocket } from '@app/core/notification/user-notification-socket.service'
import { ServerConfigResolver } from './routing/server-config-resolver.service'
+import { UnloggedGuard } from '@app/core/routing/unlogged-guard.service'
@NgModule({
imports: [
ThemeService,
LoginGuard,
UserRightGuard,
+ UnloggedGuard,
+
RedirectService,
Notifier,
MessageService,
}
redirectToPreviousRoute () {
- if (this.previousUrl) return this.router.navigateByUrl(this.previousUrl)
+ const exceptions = [
+ '/verify-account'
+ ]
+
+ if (this.previousUrl) {
+ const isException = exceptions.find(e => this.previousUrl.startsWith(e))
+ if (!isException) return this.router.navigateByUrl(this.previousUrl)
+ }
return this.redirectToHomepage()
}
--- /dev/null
+import { Injectable } from '@angular/core'
+import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router'
+import { AuthService } from '../auth/auth.service'
+import { RedirectService } from './redirect.service'
+
+@Injectable()
+export class UnloggedGuard implements CanActivate, CanActivateChild {
+
+ constructor (
+ private router: Router,
+ private auth: AuthService,
+ private redirectService: RedirectService
+ ) {}
+
+ canActivate (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
+ if (this.auth.isLoggedIn() === false) return true
+
+ this.redirectService.redirectToHomepage()
+ return false
+ }
+
+ canActivateChild (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
+ return this.canActivate(route, state)
+ }
+}
export abstract class Actor implements ActorServer {
id: number
- uuid: string
url: string
name: string
host: string
protected constructor (hash: ActorServer) {
this.id = hash.id
- this.uuid = hash.uuid
this.url = hash.url
this.name = hash.name
this.host = hash.host
@include peertube-button-link;
@include button-with-icon(21px, 0, -2px);
- font-weight: $font-semibold;
- color: $grey-foreground-color;
- background-color: $grey-background-color;
-
- &:hover {
- background-color: $grey-background-hover-color;
- }
-
- my-global-icon {
- @include apply-svg-color($grey-foreground-color);
+ // FIXME: Firefox does not apply global .orange-button icon color
+ &.orange-button {
+ @include apply-svg-color(#fff)
}
}
export class ButtonComponent {
@Input() label = ''
- @Input() className: string = undefined
+ @Input() className = 'grey-button'
@Input() icon: GlobalIconName = undefined
@Input() title: string = undefined
-<span class="action-button action-button-delete" [title]="title" role="button">
+<span class="action-button action-button-delete grey-button" [title]="title" role="button">
<my-global-icon iconName="delete"></my-global-icon>
<span class="button-label" *ngIf="label">{{ label }}</span>
-<a class="action-button action-button-edit" [routerLink]="routerLink" i18n-title title="Edit">
+<a class="action-button action-button-edit grey-button" [routerLink]="routerLink" i18n-title title="Edit">
<my-global-icon iconName="edit"></my-global-icon>
<span class="button-label" *ngIf="label">{{ label }}</span>
input {
@include peertube-checkbox(1px);
-
- width: 10px;
- margin-right: 10px;
}
}
<div class="root">
- <div class="button-file">
+ <div class="button-file" [ngClass]="{ 'with-icon': !!icon }">
+ <my-global-icon *ngIf="icon" [iconName]="icon"></my-global-icon>
+
<span>{{ inputLabel }}</span>
+
<input
type="file"
[name]="inputName" [id]="inputName" [accept]="extensions"
/>
</div>
- <div i18n class="file-constraints">(extensions: {{ allowedExtensionsMessage }}, max size: {{ maxFileSize | bytes }})</div>
-
<div class="filename" *ngIf="displayFilename === true && filename">{{ filename }}</div>
</div>
.button-file {
@include peertube-button-file(auto);
+ @include grey-button;
- min-width: 190px;
- }
-
- .file-constraints {
- margin-left: 5px;
- font-size: 13px;
+ &.with-icon {
+ @include button-with-icon;
+ }
}
.filename {
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
import { Notifier } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
+import { GlobalIconName } from '@app/shared/images/global-icon.component'
@Component({
selector: 'my-reactive-file',
@Input() extensions: string[] = []
@Input() maxFileSize: number
@Input() displayFilename = false
+ @Input() icon: GlobalIconName
@Output() fileChanged = new EventEmitter<Blob>()
+++ /dev/null
-<div class="root">
- <my-reactive-file
- [inputName]="inputName" [inputLabel]="inputLabel" [extensions]="videoImageExtensions" [maxFileSize]="maxVideoImageSize"
- (fileChanged)="onFileChanged($event)"
- ></my-reactive-file>
-
- <img *ngIf="imageSrc" [ngStyle]="{ width: previewWidth, height: previewHeight }" [src]="imageSrc" class="preview" />
- <div *ngIf="!imageSrc" [ngStyle]="{ width: previewWidth, height: previewHeight }" class="preview no-image"></div>
-</div>
+++ /dev/null
-@import '_variables';
-@import '_mixins';
-
-.root {
- height: auto;
- display: flex;
- align-items: center;
-
- .preview {
- border: 2px solid grey;
- border-radius: 4px;
- margin-left: 50px;
-
- &.no-image {
- background-color: #ececec;
- }
- }
-}
--- /dev/null
+<div class="root">
+ <div class="preview-container">
+ <my-reactive-file
+ [inputName]="inputName" [inputLabel]="inputLabel" [extensions]="videoImageExtensions" [maxFileSize]="maxVideoImageSize"
+ icon="edit" (fileChanged)="onFileChanged($event)"
+ ></my-reactive-file>
+
+ <img *ngIf="imageSrc" [ngStyle]="{ width: previewWidth, height: previewHeight }" [src]="imageSrc" class="preview" />
+ <div *ngIf="!imageSrc" [ngStyle]="{ width: previewWidth, height: previewHeight }" class="preview no-image"></div>
+ </div>
+
+ <div i18n class="file-constraints">(extensions: {{ allowedExtensionsMessage }}, max size: {{ maxVideoImageSize | bytes }})</div>
+</div>
--- /dev/null
+@import '_variables';
+@import '_mixins';
+
+.root {
+ height: auto;
+ display: flex;
+ flex-direction: column;
+
+ .preview-container {
+ position: relative;
+
+ my-reactive-file {
+ position: absolute;
+ bottom: 10px;
+ left: 10px;
+ }
+
+ .preview {
+ border: 2px solid grey;
+ border-radius: 4px;
+
+ &.no-image {
+ background-color: #ececec;
+ }
+ }
+ }
+}
-import { Component, forwardRef, Input } from '@angular/core'
+import { Component, forwardRef, Input, OnInit } from '@angular/core'
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'
import { ServerService } from '@app/core'
@Component({
- selector: 'my-image-upload',
- styleUrls: [ './image-upload.component.scss' ],
- templateUrl: './image-upload.component.html',
+ selector: 'my-preview-upload',
+ styleUrls: [ './preview-upload.component.scss' ],
+ templateUrl: './preview-upload.component.html',
providers: [
{
provide: NG_VALUE_ACCESSOR,
- useExisting: forwardRef(() => ImageUploadComponent),
+ useExisting: forwardRef(() => PreviewUploadComponent),
multi: true
}
]
})
-export class ImageUploadComponent implements ControlValueAccessor {
+export class PreviewUploadComponent implements OnInit, ControlValueAccessor {
@Input() inputLabel: string
@Input() inputName: string
@Input() previewWidth: string
@Input() previewHeight: string
imageSrc: SafeResourceUrl
+ allowedExtensionsMessage = ''
private file: File
return this.serverService.getConfig().video.image.size.max
}
+ ngOnInit () {
+ this.allowedExtensionsMessage = this.videoImageExtensions.join(', ')
+ }
+
onFileChanged (file: File) {
this.file = file
import { Injectable } from '@angular/core'
import { SortMeta } from 'primeng/primeng'
import { Observable } from 'rxjs'
-import { ActorFollow, ResultList } from '../../../../../../shared'
-import { environment } from '../../../../environments/environment'
-import { RestExtractor, RestPagination, RestService } from '../../../shared'
+import { ActorFollow, ResultList } from '@shared/index'
+import { environment } from '../../../environments/environment'
+import { RestExtractor, RestPagination, RestService } from '../rest'
@Injectable()
export class FollowService {
- private static BASE_APPLICATION_URL = environment.apiUrl + '/api/v1/server'
+ private static BASE_APPLICATION_URL = 'https://peertube2.cpy.re' + '/api/v1/server'
constructor (
private authHttp: HttpClient,
import { ConfirmComponent } from '@app/shared/confirm/confirm.component'
import { SmallLoaderComponent } from '@app/shared/misc/small-loader.component'
import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
-import { ImageUploadComponent } from '@app/shared/images/image-upload.component'
+import { PreviewUploadComponent } from '@app/shared/images/preview-upload.component'
import { GlobalIconComponent } from '@app/shared/images/global-icon.component'
import { VideoPlaylistMiniatureComponent } from '@app/shared/video-playlist/video-playlist-miniature.component'
import { VideoAddToPlaylistComponent } from '@app/shared/video-playlist/video-add-to-playlist.component'
import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component'
import { VideoReportComponent } from '@app/shared/video/modals/video-report.component'
import { ClipboardModule } from 'ngx-clipboard'
+import { FollowService } from '@app/shared/instance/follow.service'
@NgModule({
imports: [
ConfirmComponent,
GlobalIconComponent,
- ImageUploadComponent
+ PreviewUploadComponent
],
exports: [
ConfirmComponent,
GlobalIconComponent,
- ImageUploadComponent,
+ PreviewUploadComponent,
NumberFormatterPipe,
ObjectLengthPipe,
UserNotificationService,
+ FollowService,
+
I18n
]
})
import { SortMeta } from 'primeng/api'
import { BytesPipe } from 'ngx-pipes'
import { I18n } from '@ngx-translate/i18n-polyfill'
+import { UserRegister } from '@shared/models/users/user-register.model'
@Injectable()
export class UserService {
.pipe(catchError(err => this.restExtractor.handleError(err)))
}
- signup (userCreate: UserCreate) {
+ signup (userCreate: UserRegister) {
return this.authHttp.post(UserService.BASE_USERS_URL + 'register', userCreate)
.pipe(
map(this.restExtractor.extractDataBool),
import { Injectable } from '@angular/core'
import { Observable, ReplaySubject } from 'rxjs'
import { RestExtractor } from '../rest/rest-extractor.service'
-import { HttpClient } from '@angular/common/http'
+import { HttpClient, HttpParams } from '@angular/common/http'
import { VideoChannel as VideoChannelServer, VideoChannelCreate, VideoChannelUpdate } from '../../../../../shared/models/videos'
import { AccountService } from '../account/account.service'
import { ResultList } from '../../../../../shared'
import { environment } from '../../../environments/environment'
import { Account } from '@app/shared/account/account.model'
import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
+import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
+import { RestService } from '@app/shared/rest'
@Injectable()
export class VideoChannelService {
constructor (
private authHttp: HttpClient,
+ private restService: RestService,
private restExtractor: RestExtractor
) { }
)
}
- listAccountVideoChannels (account: Account): Observable<ResultList<VideoChannel>> {
- return this.authHttp.get<ResultList<VideoChannelServer>>(AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/video-channels')
+ listAccountVideoChannels (account: Account, componentPagination?: ComponentPagination): Observable<ResultList<VideoChannel>> {
+ const pagination = componentPagination
+ ? this.restService.componentPaginationToRestPagination(componentPagination)
+ : { start: 0, count: 20 }
+
+ let params = new HttpParams()
+ params = this.restService.addRestGetParams(params, pagination)
+
+ const url = AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/video-channels'
+ return this.authHttp.get<ResultList<VideoChannelServer>>(url, { params })
.pipe(
map(res => VideoChannelService.extractVideoChannels(res)),
catchError(err => this.restExtractor.handleError(err))
</div>
</div>
- <my-feed [syndicationItems]="syndicationItems"></my-feed>
+ <my-feed *ngIf="titlePage" [syndicationItems]="syndicationItems"></my-feed>
<div class="moderation-block" *ngIf="displayModerationBlock">
<my-peertube-checkbox
myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true"
class="videos"
>
- <my-video-miniature
- *ngFor="let video of videos; trackBy: videoById" [video]="video" [user]="user" [ownerDisplayType]="ownerDisplayType"
- [displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions"
- (videoBlacklisted)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)"
- >
- </my-video-miniature>
+ <ng-container *ngFor="let video of videos; trackBy: videoById;">
+ <div class="date-title" *ngIf="getCurrentGroupedDateLabel(video)">
+ {{ getCurrentGroupedDateLabel(video) }}
+ </div>
+
+ <my-video-miniature
+ [video]="video" [user]="user" [ownerDisplayType]="ownerDisplayType"
+ [displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions"
+ (videoBlacklisted)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)"
+ >
+ </my-video-miniature>
+ </ng-container>
</div>
</div>
}
}
-.margin-content {
- width: $video-miniature-width * 6;
- margin: auto !important;
-
- @media screen and (max-width: 1800px) {
- width: $video-miniature-width * 5;
- }
+.date-title {
+ font-size: 16px;
+ font-weight: $font-semibold;
+ margin-bottom: 20px;
+ margin-top: -10px;
+ padding-top: 20px;
- @media screen and (max-width: 1800px - $video-miniature-width) {
- width: $video-miniature-width * 4;
+ &:not(:first-child) {
+ border-top: 1px solid $separator-border-color;
}
+}
- @media screen and (max-width: 1800px - (2* $video-miniature-width)) {
- width: $video-miniature-width * 3;
- }
-
- @media screen and (max-width: 1800px - (3* $video-miniature-width)) {
- width: $video-miniature-width * 2;
- }
-
- @media screen and (max-width: 500px) {
- width: auto;
- margin: 0 !important;
-
- .videos {
- @include video-miniature-small-screen;
- }
- }
+.margin-content {
+ @include adapt-margin-content-width;
}
import { Syndication } from '@app/shared/video/syndication.model'
import { Notifier, ServerService } from '@app/core'
import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
+import { I18n } from '@ngx-translate/i18n-polyfill'
+import { isLastMonth, isLastWeek, isToday, isYesterday } from '@shared/core-utils/miscs/date'
+
+enum GroupDate {
+ UNKNOWN = 0,
+ TODAY = 1,
+ YESTERDAY = 2,
+ LAST_WEEK = 3,
+ LAST_MONTH = 4,
+ OLDER = 5
+}
export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableForReuseHook {
pagination: ComponentPagination = {
displayModerationBlock = false
titleTooltip: string
displayVideoActions = true
+ groupByDate = false
disabled = false
protected abstract serverService: ServerService
protected abstract screenService: ScreenService
protected abstract router: Router
+ protected abstract i18n: I18n
abstract titlePage: string
private resizeSubscription: Subscription
private angularState: number
+ private groupedDateLabels: { [id in GroupDate]: string }
+ private groupedDates: { [id: number]: GroupDate } = {}
+
abstract getVideosObservable (page: number): Observable<{ videos: Video[], totalVideos: number }>
abstract generateSyndicationList (): void
}
ngOnInit () {
+ this.groupedDateLabels = {
+ [GroupDate.UNKNOWN]: null,
+ [GroupDate.TODAY]: this.i18n('Today'),
+ [GroupDate.YESTERDAY]: this.i18n('Yesterday'),
+ [GroupDate.LAST_WEEK]: this.i18n('Last week'),
+ [GroupDate.LAST_MONTH]: this.i18n('Last month'),
+ [GroupDate.OLDER]: this.i18n('Older')
+ }
+
// Subscribe to route changes
const routeParams = this.route.snapshot.queryParams
this.loadRouteParams(routeParams)
this.pagination.totalItems = totalVideos
this.videos = this.videos.concat(videos)
+ if (this.groupByDate) this.buildGroupedDateLabels()
+
this.onMoreVideos()
},
this.videos = this.videos.filter(v => v.id !== video.id)
}
+ buildGroupedDateLabels () {
+ let currentGroupedDate: GroupDate = GroupDate.UNKNOWN
+
+ for (const video of this.videos) {
+ const publishedDate = video.publishedAt
+
+ if (currentGroupedDate <= GroupDate.TODAY && isToday(publishedDate)) {
+ if (currentGroupedDate === GroupDate.TODAY) continue
+
+ currentGroupedDate = GroupDate.TODAY
+ this.groupedDates[ video.id ] = currentGroupedDate
+ continue
+ }
+
+ if (currentGroupedDate <= GroupDate.YESTERDAY && isYesterday(publishedDate)) {
+ if (currentGroupedDate === GroupDate.YESTERDAY) continue
+
+ currentGroupedDate = GroupDate.YESTERDAY
+ this.groupedDates[ video.id ] = currentGroupedDate
+ continue
+ }
+
+ if (currentGroupedDate <= GroupDate.LAST_WEEK && isLastWeek(publishedDate)) {
+ if (currentGroupedDate === GroupDate.LAST_WEEK) continue
+
+ currentGroupedDate = GroupDate.LAST_WEEK
+ this.groupedDates[ video.id ] = currentGroupedDate
+ continue
+ }
+
+ if (currentGroupedDate <= GroupDate.LAST_MONTH && isLastMonth(publishedDate)) {
+ if (currentGroupedDate === GroupDate.LAST_MONTH) continue
+
+ currentGroupedDate = GroupDate.LAST_MONTH
+ this.groupedDates[ video.id ] = currentGroupedDate
+ continue
+ }
+
+ if (currentGroupedDate <= GroupDate.OLDER) {
+ if (currentGroupedDate === GroupDate.OLDER) continue
+
+ currentGroupedDate = GroupDate.OLDER
+ this.groupedDates[ video.id ] = currentGroupedDate
+ }
+ }
+ }
+
+ getCurrentGroupedDateLabel (video: Video) {
+ if (this.groupByDate === false) return undefined
+
+ return this.groupedDateLabels[this.groupedDates[video.id]]
+ }
+
// On videos hook for children that want to do something
protected onMoreVideos () { /* empty */ }
import { Component, ElementRef, ViewChild } from '@angular/core'
import { VideoDetails } from '../../../shared/video/video-details.model'
-import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
+import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { Notifier } from '@app/core'
resolutionId: number | string = -1
video: VideoDetails
+ activeModal: NgbActiveModal
constructor (
private notifier: Notifier,
show (video: VideoDetails) {
this.video = video
- const m = this.modalService.open(this.modal)
- m.result.then(() => this.onClose())
- .catch(() => this.onClose())
+ this.activeModal = this.modalService.open(this.modal)
this.resolutionId = this.video.files[0].resolution.id
}
download () {
window.location.assign(this.getLink())
+ this.activeModal.close()
}
getLink () {
-import { UserRight, VideoConstant, VideoDetails as VideoDetailsServerModel, VideoFile, VideoState } from '../../../../../shared'
-import { AuthUser } from '../../core'
+import { VideoConstant, VideoDetails as VideoDetailsServerModel, VideoFile, VideoState } from '../../../../../shared'
import { Video } from '../../shared/video/video.model'
import { Account } from '@app/shared/account/account.model'
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
const originallyPublishedAt = new Date(values['originallyPublishedAt'])
this.originallyPublishedAt = originallyPublishedAt.toISOString()
}
+
+ // Use the same file than the preview for the thumbnail
+ if (this.previewfile) {
+ this.thumbnailfile = this.previewfile
+ }
}
toFormPatch () {
account: {
id: number
- uuid: string
name: string
displayName: string
url: string
channel: {
id: number
- uuid: string
name: string
displayName: string
url: string
import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive'
import { VideoSortField } from '@app/shared/video/sort-field.type'
import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
+import { I18n } from '@ngx-translate/i18n-polyfill'
export type SelectionType = { [ id: number ]: boolean }
globalButtonsTemplate: TemplateRef<any>
constructor (
+ protected i18n: I18n,
protected router: Router,
protected route: ActivatedRoute,
protected notifier: Notifier,
+++ /dev/null
-export * from './signup-routing.module'
-export * from './signup.component'
-export * from './signup.module'
+++ /dev/null
-<div class="margin-content">
-
- <div i18n class="title-page title-page-single">
- Create an account
- </div>
-
- <div *ngIf="info" class="alert alert-info">{{ info }}</div>
- <div *ngIf="error" class="alert alert-danger">{{ error }}</div>
-
- <div class="d-flex justify-content-left flex-wrap">
- <form role="form" (ngSubmit)="signup()" [formGroup]="form">
- <div class="form-group">
- <label for="username" i18n>Username</label>
-
- <div class="input-group">
- <input
- type="text" id="username" i18n-placeholder placeholder="Example: jane_doe"
- formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }"
- >
- <div class="input-group-append">
- <span class="input-group-text">@{{ instanceHost }}</span>
- </div>
- </div>
-
- <div *ngIf="formErrors.username" class="form-error">
- {{ formErrors.username }}
- </div>
- </div>
-
- <div class="form-group">
- <label for="email" i18n>Email</label>
- <input
- type="text" id="email" i18n-placeholder placeholder="Email"
- formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }"
- >
- <div *ngIf="formErrors.email" class="form-error">
- {{ formErrors.email }}
- </div>
- </div>
-
- <div class="form-group">
- <label for="password" i18n>Password</label>
- <input
- type="password" id="password" i18n-placeholder placeholder="Password"
- formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
- >
- <div *ngIf="formErrors.password" class="form-error">
- {{ formErrors.password }}
- </div>
- </div>
-
- <div class="form-group form-group-terms">
- <my-peertube-checkbox
- inputName="terms" formControlName="terms"
- i18n-labelHtml labelHtml="I am at least 16 years old and agree to the <a href='/about/instance#terms-section' target='_blank'rel='noopener noreferrer'>Terms</a> of this instance"
- ></my-peertube-checkbox>
-
- <div *ngIf="formErrors.terms" class="form-error">
- {{ formErrors.terms }}
- </div>
- </div>
-
- <input type="submit" i18n-value value="Signup" [disabled]="!form.valid || signupDone">
- </form>
-
- <div>
- <label i18n>Features found on this instance</label>
- <my-instance-features-table></my-instance-features-table>
- </div>
- </div>
-
-</div>
+++ /dev/null
-import { Component, OnInit } from '@angular/core'
-import { AuthService, Notifier, RedirectService, ServerService } from '@app/core'
-import { UserCreate } from '../../../../shared'
-import { FormReactive, UserService, UserValidatorsService } from '../shared'
-import { I18n } from '@ngx-translate/i18n-polyfill'
-import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
-
-@Component({
- selector: 'my-signup',
- templateUrl: './signup.component.html',
- styleUrls: [ './signup.component.scss' ]
-})
-export class SignupComponent extends FormReactive implements OnInit {
- info: string = null
- error: string = null
- signupDone = false
-
- constructor (
- protected formValidatorService: FormValidatorService,
- private authService: AuthService,
- private userValidatorsService: UserValidatorsService,
- private notifier: Notifier,
- private userService: UserService,
- private serverService: ServerService,
- private redirectService: RedirectService,
- private i18n: I18n
- ) {
- super()
- }
-
- get instanceHost () {
- return window.location.host
- }
-
- get requiresEmailVerification () {
- return this.serverService.getConfig().signup.requiresEmailVerification
- }
-
- ngOnInit () {
- this.buildForm({
- username: this.userValidatorsService.USER_USERNAME,
- password: this.userValidatorsService.USER_PASSWORD,
- email: this.userValidatorsService.USER_EMAIL,
- terms: this.userValidatorsService.USER_TERMS
- })
- }
-
- signup () {
- this.error = null
-
- const userCreate: UserCreate = this.form.value
-
- this.userService.signup(userCreate).subscribe(
- () => {
- this.signupDone = true
-
- if (this.requiresEmailVerification) {
- this.info = this.i18n('Welcome! Now please check your emails to verify your account and complete signup.')
- return
- }
-
- // Auto login
- this.authService.login(userCreate.username, userCreate.password)
- .subscribe(
- () => {
- this.notifier.success(this.i18n('You are now logged in as {{username}}!', { username: userCreate.username }))
-
- this.redirectService.redirectToHomepage()
- },
-
- err => this.error = err.message
- )
- },
-
- err => this.error = err.message
- )
- }
-}
+++ /dev/null
-import { NgModule } from '@angular/core'
-
-import { SignupRoutingModule } from './signup-routing.module'
-import { SignupComponent } from './signup.component'
-import { SharedModule } from '../shared'
-
-@NgModule({
- imports: [
- SignupRoutingModule,
- SharedModule
- ],
-
- declarations: [
- SignupComponent
- ],
-
- exports: [
- SignupComponent
- ],
-
- providers: [
- ]
-})
-export class SignupModule { }
<ng-template ngbTabContent>
<div class="row advanced-settings">
<div class="col-md-12 col-xl-8">
- <div class="form-group">
- <my-image-upload
- i18n-inputLabel inputLabel="Upload thumbnail" inputName="thumbnailfile" formControlName="thumbnailfile"
- previewWidth="200px" previewHeight="110px"
- ></my-image-upload>
- </div>
<div class="form-group">
- <my-image-upload
- i18n-inputLabel inputLabel="Upload preview" inputName="previewfile" formControlName="previewfile"
+ <label i18n for="previewfile">Video preview</label>
+
+ <my-preview-upload
+ i18n-inputLabel inputLabel="Edit" inputName="previewfile" formControlName="previewfile"
previewWidth="360px" previewHeight="200px"
- ></my-image-upload>
+ ></my-preview-upload>
</div>
<div class="form-group">
import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model'
import { removeElementFromArray } from '@app/shared/misc/utils'
import { VideoConstant, VideoPrivacy } from '../../../../../../shared'
+import { VideoService } from '@app/shared/video/video.service'
@Component({
selector: 'my-video-edit',
@Input() form: FormGroup
@Input() formErrors: { [ id: string ]: string } = {}
@Input() validationMessages: FormReactiveValidationMessages = {}
- @Input() videoPrivacies: VideoConstant<VideoPrivacy>[] = []
@Input() userVideoChannels: { id: number, label: string, support: string }[] = []
@Input() schedulePublicationPossible = true
@Input() videoCaptions: (VideoCaptionEdit & { captionPath?: string })[] = []
// So that it can be accessed in the template
readonly SPECIAL_SCHEDULED_PRIVACY = VideoEdit.SPECIAL_SCHEDULED_PRIVACY
+ videoPrivacies: VideoConstant<VideoPrivacy>[] = []
videoCategories: VideoConstant<number>[] = []
videoLicences: VideoConstant<number>[] = []
videoLanguages: VideoConstant<string>[] = []
private formValidatorService: FormValidatorService,
private videoValidatorsService: VideoValidatorsService,
private videoCaptionService: VideoCaptionService,
+ private videoService: VideoService,
private route: ActivatedRoute,
private router: Router,
private notifier: Notifier,
language: this.videoValidatorsService.VIDEO_LANGUAGE,
description: this.videoValidatorsService.VIDEO_DESCRIPTION,
tags: null,
- thumbnailfile: null,
previewfile: null,
support: this.videoValidatorsService.VIDEO_SUPPORT,
schedulePublicationAt: this.videoValidatorsService.VIDEO_SCHEDULE_PUBLICATION_AT,
this.videoLicences = this.serverService.getVideoLicences()
this.videoLanguages = this.serverService.getVideoLanguages()
+ const privacies = this.serverService.getVideoPrivacies()
+ this.videoPrivacies = this.videoService.explainedPrivacyLabels(privacies)
+
this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id)
this.ngZone.runOutsideAngular(() => {
<form [hidden]="!hasImportedVideo" novalidate [formGroup]="form">
<my-video-edit
[form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions" [schedulePublicationPossible]="false"
- [validationMessages]="validationMessages" [videoPrivacies]="explainedVideoPrivacies" [userVideoChannels]="userVideoChannels"
+ [validationMessages]="validationMessages" [userVideoChannels]="userVideoChannels"
></my-video-edit>
<div class="submit-container">
previewUrl: null
}))
- this.explainedVideoPrivacies = this.videoService.explainedPrivacyLabels(this.videoPrivacies)
this.hydrateFormFromVideo()
},
<form [hidden]="!hasImportedVideo" novalidate [formGroup]="form">
<my-video-edit
[form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions" [schedulePublicationPossible]="false"
- [validationMessages]="validationMessages" [videoPrivacies]="explainedVideoPrivacies" [userVideoChannels]="userVideoChannels"
+ [validationMessages]="validationMessages" [userVideoChannels]="userVideoChannels"
></my-video-edit>
<div class="submit-container">
export abstract class VideoSend extends FormReactive implements OnInit {
userVideoChannels: { id: number, label: string, support: string }[] = []
videoPrivacies: VideoConstant<VideoPrivacy>[] = []
- explainedVideoPrivacies: VideoConstant<VideoPrivacy>[] = []
videoCaptions: VideoCaptionEdit[] = []
firstStepPrivacyId = 0
</select>
</div>
</div>
+
+ <ng-container *ngIf="isUploadingAudioFile">
+ <div class="form-group audio-preview">
+ <label i18n for="previewfileUpload">Video background image</label>
+
+ <div i18n class="audio-image-info">
+ Image that will be merged with your audio file.
+ <br />
+ The chosen image will be definitive and cannot be modified.
+ </div>
+
+ <my-preview-upload
+ i18n-inputLabel inputLabel="Edit" inputName="previewfileUpload" [(ngModel)]="previewfileUpload"
+ previewWidth="360px" previewHeight="200px"
+ ></my-preview-upload>
+ </div>
+
+ <div class="form-group upload-audio-button">
+ <my-button className="orange-button" i18n-label [label]="getAudioUploadLabel()" icon="upload" (click)="uploadFirstStep(true)"></my-button>
+ </div>
+ </ng-container>
</div>
</div>
<form [hidden]="!isUploadingVideo" novalidate [formGroup]="form">
<my-video-edit
[form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions"
- [validationMessages]="validationMessages" [videoPrivacies]="explainedVideoPrivacies" [userVideoChannels]="userVideoChannels"
+ [validationMessages]="validationMessages" [userVideoChannels]="userVideoChannels"
[waitTranscodingEnabled]="waitTranscodingEnabled"
></my-video-edit>
@import 'variables';
@import 'mixins';
-.first-step-block .form-group-channel {
- margin-bottom: 20px;
- margin-top: 35px;
+.first-step-block {
+
+ .form-group-channel {
+ margin-bottom: 20px;
+ margin-top: 35px;
+ }
+
+ .audio-image-info {
+ margin-bottom: 10px;
+ }
+
+ .audio-preview {
+ margin: 30px 0;
+ }
}
.upload-progress-cancel {
userVideoQuotaUsed = 0
userVideoQuotaUsedDaily = 0
+ isUploadingAudioFile = false
isUploadingVideo = false
isUpdatingVideo = false
+
videoUploaded = false
videoUploadObservable: Subscription = null
videoUploadPercents = 0
id: 0,
uuid: ''
}
+
waitTranscodingEnabled = true
+ previewfileUpload: File
error: string
}
}
+ getVideoFile () {
+ return this.videofileInput.nativeElement.files[0]
+ }
+
+ getAudioUploadLabel () {
+ const videofile = this.getVideoFile()
+ if (!videofile) return this.i18n('Upload')
+
+ return this.i18n('Upload {{videofileName}}', { videofileName: videofile.name })
+ }
+
fileChange () {
this.uploadFirstStep()
}
}
}
- uploadFirstStep () {
- const videofile = this.videofileInput.nativeElement.files[0]
+ uploadFirstStep (clickedOnButton = false) {
+ const videofile = this.getVideoFile()
if (!videofile) return
- // Check global user quota
- const bytePipes = new BytesPipe()
- const videoQuota = this.authService.getUser().videoQuota
- if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) {
- const msg = this.i18n(
- 'Your video quota is exceeded with this video (video size: {{videoSize}}, used: {{videoQuotaUsed}}, quota: {{videoQuota}})',
- {
- videoSize: bytePipes.transform(videofile.size, 0),
- videoQuotaUsed: bytePipes.transform(this.userVideoQuotaUsed, 0),
- videoQuota: bytePipes.transform(videoQuota, 0)
- }
- )
- this.notifier.error(msg)
- return
- }
+ if (!this.checkGlobalUserQuota(videofile)) return
+ if (!this.checkDailyUserQuota(videofile)) return
- // Check daily user quota
- const videoQuotaDaily = this.authService.getUser().videoQuotaDaily
- if (videoQuotaDaily !== -1 && (this.userVideoQuotaUsedDaily + videofile.size) > videoQuotaDaily) {
- const msg = this.i18n(
- 'Your daily video quota is exceeded with this video (video size: {{videoSize}}, used: {{quotaUsedDaily}}, quota: {{quotaDaily}})',
- {
- videoSize: bytePipes.transform(videofile.size, 0),
- quotaUsedDaily: bytePipes.transform(this.userVideoQuotaUsedDaily, 0),
- quotaDaily: bytePipes.transform(videoQuotaDaily, 0)
- }
- )
- this.notifier.error(msg)
+ if (clickedOnButton === false && this.isAudioFile(videofile.name)) {
+ this.isUploadingAudioFile = true
return
}
formData.append('channelId', '' + channelId)
formData.append('videofile', videofile)
+ if (this.previewfileUpload) {
+ formData.append('previewfile', this.previewfileUpload)
+ formData.append('thumbnailfile', this.previewfileUpload)
+ }
+
this.isUploadingVideo = true
this.firstStepDone.emit(name)
name,
privacy,
nsfw,
- channelId
+ channelId,
+ previewfile: this.previewfileUpload
})
- this.explainedVideoPrivacies = this.videoService.explainedPrivacyLabels(this.videoPrivacies)
-
this.videoUploadObservable = this.videoService.uploadVideo(formData).subscribe(
event => {
if (event.type === HttpEventType.UploadProgress) {
}
)
}
+
+ private checkGlobalUserQuota (videofile: File) {
+ const bytePipes = new BytesPipe()
+
+ // Check global user quota
+ const videoQuota = this.authService.getUser().videoQuota
+ if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) {
+ const msg = this.i18n(
+ 'Your video quota is exceeded with this video (video size: {{videoSize}}, used: {{videoQuotaUsed}}, quota: {{videoQuota}})',
+ {
+ videoSize: bytePipes.transform(videofile.size, 0),
+ videoQuotaUsed: bytePipes.transform(this.userVideoQuotaUsed, 0),
+ videoQuota: bytePipes.transform(videoQuota, 0)
+ }
+ )
+ this.notifier.error(msg)
+
+ return false
+ }
+
+ return true
+ }
+
+ private checkDailyUserQuota (videofile: File) {
+ const bytePipes = new BytesPipe()
+
+ // Check daily user quota
+ const videoQuotaDaily = this.authService.getUser().videoQuotaDaily
+ if (videoQuotaDaily !== -1 && (this.userVideoQuotaUsedDaily + videofile.size) > videoQuotaDaily) {
+ const msg = this.i18n(
+ 'Your daily video quota is exceeded with this video (video size: {{videoSize}}, used: {{quotaUsedDaily}}, quota: {{quotaDaily}})',
+ {
+ videoSize: bytePipes.transform(videofile.size, 0),
+ quotaUsedDaily: bytePipes.transform(this.userVideoQuotaUsedDaily, 0),
+ quotaDaily: bytePipes.transform(videoQuotaDaily, 0)
+ }
+ )
+ this.notifier.error(msg)
+
+ return false
+ }
+
+ return true
+ }
+
+ private isAudioFile (filename: string) {
+ return filename.endsWith('.mp3') || filename.endsWith('.flac') || filename.endsWith('.ogg')
+ }
}
<my-video-edit
[form]="form" [formErrors]="formErrors" [schedulePublicationPossible]="schedulePublicationPossible"
- [validationMessages]="validationMessages" [videoPrivacies]="explainedVideoPrivacies" [userVideoChannels]="userVideoChannels"
+ [validationMessages]="validationMessages" [userVideoChannels]="userVideoChannels"
[videoCaptions]="videoCaptions" [waitTranscodingEnabled]="waitTranscodingEnabled"
></my-video-edit>
import { ActivatedRoute, Router } from '@angular/router'
import { LoadingBarService } from '@ngx-loading-bar/core'
import { Notifier } from '@app/core'
-import { VideoConstant, VideoPrivacy } from '../../../../../shared/models/videos'
import { ServerService } from '../../core'
import { FormReactive } from '../../shared'
import { VideoEdit } from '../../shared/video/video-edit.model'
video: VideoEdit
isUpdatingVideo = false
- videoPrivacies: VideoConstant<VideoPrivacy>[] = []
- explainedVideoPrivacies: VideoConstant<VideoPrivacy>[] = []
userVideoChannels: { id: number, label: string, support: string }[] = []
schedulePublicationPossible = false
videoCaptions: VideoCaptionEdit[] = []
ngOnInit () {
this.buildForm({})
- this.serverService.videoPrivaciesLoaded
- .subscribe(() => this.videoPrivacies = this.serverService.getVideoPrivacies())
-
this.route.data
.pipe(map(data => data.videoData))
.subscribe(({ video, videoChannels, videoCaptions }) => {
this.userVideoChannels = videoChannels
this.videoCaptions = videoCaptions
- // We cannot set private a video that was not private
- if (this.video.privacy !== VideoPrivacy.PRIVATE) {
- this.videoPrivacies = this.videoPrivacies.filter(p => p.id !== VideoPrivacy.PRIVATE)
- } else { // We can schedule video publication only if it it is private
- this.schedulePublicationPossible = this.video.privacy === VideoPrivacy.PRIVATE
- }
-
- this.explainedVideoPrivacies = this.videoService.explainedPrivacyLabels(this.videoPrivacies)
-
const videoFiles = (video as VideoDetails).files
if (videoFiles.length > 1) { // Already transcoded
this.waitTranscodingEnabled = false
import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component'
import { MetaService } from '@ngx-meta/core'
import { Notifier, ServerService } from '@app/core'
-import { forkJoin, Subscription } from 'rxjs'
+import { forkJoin, Observable, Subscription } from 'rxjs'
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
import { UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '../../../../../shared'
import { AuthService, ConfirmService } from '../../core'
setLike () {
if (this.isUserLoggedIn() === false) return
- if (this.userRating === 'like') {
- // Already liked this video
- this.setRating('none')
- } else {
- this.setRating('like')
- }
+
+ // Already liked this video
+ if (this.userRating === 'like') this.setRating('none')
+ else this.setRating('like')
}
setDislike () {
if (this.isUserLoggedIn() === false) return
- if (this.userRating === 'dislike') {
- // Already disliked this video
- this.setRating('none')
- } else {
- this.setRating('dislike')
- }
+
+ // Already disliked this video
+ if (this.userRating === 'dislike') this.setRating('none')
+ else this.setRating('dislike')
}
showMoreDescription () {
)
.subscribe(([ video, captionsResult ]) => {
const queryParams = this.route.snapshot.queryParams
- const startTime = queryParams.start
- const stopTime = queryParams.stop
- const subtitle = queryParams.subtitle
- const playerMode = queryParams.mode
- this.onVideoFetched(video, captionsResult.data, { startTime, stopTime, subtitle, playerMode })
+ const urlOptions = {
+ startTime: queryParams.start,
+ stopTime: queryParams.stop,
+ subtitle: queryParams.subtitle,
+ playerMode: queryParams.mode
+ }
+
+ this.onVideoFetched(video, captionsResult.data, urlOptions)
.catch(err => this.handleError(err))
})
}
private updateVideoDescription (description: string) {
this.video.description = description
this.setVideoDescriptionHTML()
+ .catch(err => console.error(err))
}
private async setVideoDescriptionHTML () {
captions: videoCaptions.length !== 0,
peertubeLink: false,
- videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE ? this.videoService.getVideoViewUrl(this.video.uuid) : null,
+ videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE
+ ? this.videoService.getVideoViewUrl(this.video.uuid)
+ : null,
embedUrl: this.video.embedUrl,
language: this.localeId,
}
private setRating (nextRating: UserVideoRateType) {
- let method
- switch (nextRating) {
- case 'like':
- method = this.videoService.setVideoLike
- break
- case 'dislike':
- method = this.videoService.setVideoDislike
- break
- case 'none':
- method = this.videoService.unsetVideoLike
- break
+ const ratingMethods: { [id in UserVideoRateType]: (id: number) => Observable<any> } = {
+ like: this.videoService.setVideoLike,
+ dislike: this.videoService.setVideoDislike,
+ none: this.videoService.unsetVideoLike
}
- method.call(this.videoService, this.video.id)
+ ratingMethods[nextRating].call(this.videoService, this.video.id)
.subscribe(
() => {
// Update the video like attribute
private flushPlayer () {
// Remove player if it exists
if (this.player) {
- this.player.dispose()
- this.player = undefined
+ try {
+ this.player.dispose()
+ this.player = undefined
+ } catch (err) {
+ console.error('Cannot dispose player.', err)
+ }
}
}
private initHotkeys () {
this.hotkeys = [
- new Hotkey('shift+l', (event: KeyboardEvent): boolean => {
+ new Hotkey('shift+l', () => {
this.setLike()
return false
}, undefined, this.i18n('Like the video')),
- new Hotkey('shift+d', (event: KeyboardEvent): boolean => {
+
+ new Hotkey('shift+d', () => {
this.setDislike()
return false
}, undefined, this.i18n('Dislike the video')),
- new Hotkey('shift+s', (event: KeyboardEvent): boolean => {
- this.subscribeButton.subscribed ?
- this.subscribeButton.unsubscribe() :
- this.subscribeButton.subscribe()
+
+ new Hotkey('shift+s', () => {
+ this.subscribeButton.subscribed ? this.subscribeButton.unsubscribe() : this.subscribeButton.subscribe()
return false
}, undefined, this.i18n('Subscribe to the account'))
]
filter: VideoFilter = 'local'
constructor (
+ protected i18n: I18n,
protected router: Router,
protected serverService: ServerService,
protected route: ActivatedRoute,
protected notifier: Notifier,
protected authService: AuthService,
protected screenService: ScreenService,
- private i18n: I18n,
private videoService: VideoService
) {
super()
<div class="no-results" i18n *ngIf="notResults">No results.</div>
<div class="section" *ngFor="let object of overview.categories">
- <div class="section-title" i18n>
+ <div class="section-title">
<a routerLink="/search" [queryParams]="{ categoryOneOf: [ object.category.id ] }">{{ object.category.label }}</a>
</div>
</div>
<div class="section" *ngFor="let object of overview.tags">
- <div class="section-title" i18n>
+ <div class="section-title">
<a routerLink="/search" [queryParams]="{ tagsOneOf: [ object.tag ] }">#{{ object.tag }}</a>
</div>
</div>
<div class="section channel" *ngFor="let object of overview.channels">
- <div class="section-title" i18n>
+ <div class="section-title">
<a [routerLink]="[ '/video-channels', buildVideoChannelBy(object) ]">
<img [src]="buildVideoChannelAvatarUrl(object)" alt="Avatar" />
@import '_mixins';
@import '_miniature';
-.section {
- max-height: 500px; // 2 rows max
- overflow: hidden;
- padding-top: 10px;
-
- &:first-child {
- padding-top: 30px;
- }
-
- my-video-miniature {
- text-align: left;
- }
-}
-
-.section-title {
- font-size: 24px;
- font-weight: $font-semibold;
- margin-bottom: 10px;
-
- a {
- &:hover, &:focus:not(.focus-visible), &:active {
- text-decoration: none;
- outline: none;
- }
-
- color: var(--mainForegroundColor);
- }
+.margin-content {
+ @include adapt-margin-content-width;
}
-.channel {
- .section-title a {
- display: flex;
- width: fit-content;
- align-items: center;
-
- img {
- @include avatar(28px);
-
- margin-right: 8px;
- }
- }
-}
-
-@media screen and (max-width: 500px) {
- .margin-content {
- margin: 0 !important;
- }
-
- .section-title {
- font-size: 17px;
- }
-
- .section {
- max-height: initial;
- overflow: initial;
-
- @include video-miniature-small-screen;
- }
+.section {
+ @include miniature-rows;
}
export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy {
titlePage: string
sort: VideoSortField = '-publishedAt'
+ groupByDate = true
constructor (
+ protected i18n: I18n,
protected route: ActivatedRoute,
protected serverService: ServerService,
protected router: Router,
protected notifier: Notifier,
protected authService: AuthService,
protected screenService: ScreenService,
- private i18n: I18n,
private videoService: VideoService
) {
super()
defaultSort: VideoSortField = '-trending'
constructor (
+ protected i18n: I18n,
protected router: Router,
protected serverService: ServerService,
protected route: ActivatedRoute,
protected notifier: Notifier,
protected authService: AuthService,
protected screenService: ScreenService,
- private i18n: I18n,
private videoService: VideoService
) {
super()
titlePage: string
sort = '-publishedAt' as VideoSortField
ownerDisplayType: OwnerDisplayType = 'auto'
+ groupByDate = true
constructor (
+ protected i18n: I18n,
protected router: Router,
protected serverService: ServerService,
protected route: ActivatedRoute,
protected notifier: Notifier,
protected authService: AuthService,
protected screenService: ScreenService,
- private i18n: I18n,
private videoService: VideoService
) {
super()
videojs(options.common.playerElement, videojsOptions, function (this: any) {
const player = this
- player.tech_.one('error', () => self.maybeFallbackToWebTorrent(mode, player, options))
- player.one('error', () => self.maybeFallbackToWebTorrent(mode, player, options))
+ let alreadyFallback = false
+
+ player.tech_.one('error', () => {
+ if (!alreadyFallback) self.maybeFallbackToWebTorrent(mode, player, options)
+ alreadyFallback = true
+ })
+
+ player.one('error', () => {
+ if (!alreadyFallback) self.maybeFallbackToWebTorrent(mode, player, options)
+ alreadyFallback = true
+ })
self.addContextMenu(mode, player, options.common.embedUrl)
}
}
}
+
+@mixin miniature-rows {
+ max-height: 540px; // 2 rows max
+ overflow: hidden;
+ padding-top: 10px;
+
+ &:first-child {
+ padding-top: 30px;
+ }
+
+ my-video-miniature {
+ text-align: left;
+ }
+
+ .section-title {
+ font-size: 24px;
+ font-weight: $font-semibold;
+ margin-bottom: 30px;
+ display: flex;
+ justify-content: space-between;
+
+ a {
+ &:hover, &:focus:not(.focus-visible), &:active {
+ text-decoration: none;
+ outline: none;
+ }
+
+ color: var(--mainForegroundColor);
+ }
+ }
+
+ &.channel {
+ .section-title {
+ a {
+ display: flex;
+ width: fit-content;
+ align-items: center;
+
+ img {
+ @include avatar(28px);
+
+ margin-right: 8px;
+ }
+ }
+
+ .followers {
+ color: $grey-foreground-color;
+ font-weight: normal;
+ font-size: 14px;
+ margin-left: 10px;
+ position: relative;
+ top: 2px;
+ }
+ }
+ }
+
+ @media screen and (max-width: $mobile-view) {
+ max-height: initial;
+ overflow: initial;
+
+ @include video-miniature-small-screen;
+
+ .section-title {
+ font-size: 17px;
+ }
+ }
+}
+
+@mixin adapt-margin-content-width {
+ width: $video-miniature-width * 6;
+ margin: auto !important;
+
+ @media screen and (max-width: 1800px) {
+ width: $video-miniature-width * 5;
+ }
+
+ @media screen and (max-width: 1800px - $video-miniature-width) {
+ width: $video-miniature-width * 4;
+ }
+
+ @media screen and (max-width: 1800px - (2* $video-miniature-width)) {
+ width: $video-miniature-width * 3;
+ }
+
+ @media screen and (max-width: 1800px - (3* $video-miniature-width)) {
+ width: $video-miniature-width * 2;
+ }
+
+ @media screen and (max-width: 500px) {
+ width: auto;
+ margin: 0 !important;
+
+ .videos {
+ @include video-miniature-small-screen;
+ }
+ }
+}
}
@mixin peertube-checkbox ($border-width) {
- display: none;
+ opacity: 0;
+ position: absolute;
+
+ &:focus + span {
+ outline: 1px solid #1e5180;
+ }
& + span {
position: relative;
ca_file: null # Used for self signed certificates
from_address: 'admin@example.com'
+email:
+ body:
+ signature: "PeerTube"
+ object:
+ prefix: "[PeerTube]"
+
# From the project root directory
storage:
tmp: 'storage/tmp/' # Used to download data (imports etc), store uploaded files before processing...
enabled: true
# Allow your users to upload .mkv, .mov, .avi, .flv videos
allow_additional_extensions: true
+ # If a user uploads an audio file, PeerTube will create a video by merging the preview file and the audio file
+ allow_audio_files: true
threads: 1
resolutions: # Only created if the original video has a higher resolution, uses more storage!
240p: false
480p: false
720p: false
1080p: false
+ 2160p: false
# /!\ EXPERIMENTAL /!\
# /!\ Requires ffmpeg >= 4
# Generate HLS playlists and fragmented MP4 files. Better playback than with WebTorrent:
enabled: true
# Allow your users to upload .mkv, .mov, .avi, .flv videos
allow_additional_extensions: true
+ # If a user uploads an audio file, PeerTube will create a video by merging the preview file and the audio file
+ allow_audio_files: true
threads: 1
resolutions: # Only created if the original video has a higher resolution, uses more storage!
240p: false
480p: false
720p: false
1080p: false
+ 2160p: false
# /!\ EXPERIMENTAL /!\
# /!\ Requires ffmpeg >= 4
# Generate HLS playlists and fragmented MP4 files. Better playback than with WebTorrent:
transcoding:
enabled: true
allow_additional_extensions: true
+ allow_audio_files: true
transcoding:
enabled: true
allow_additional_extensions: false
+ allow_audio_files: false
threads: 2
resolutions:
240p: true
480p: true
720p: true
1080p: true
+ 2160p: true
hls:
enabled: true
"scripts": {
"e2e": "scripty",
"e2e:local": "scripty",
+ "setup:cli": "scripty",
"build": "SCRIPTY_PARALLEL=true scripty",
"build:server": "scripty",
"build:client": "scripty",
},
"dependencies": {
"apicache": "^1.4.0",
- "application-config": "^1.0.1",
- "async": "^2.0.0",
+ "async": "^3.0.1",
"async-lru": "^1.1.1",
- "bcrypt": "3.0.5",
+ "bcrypt": "3.0.6",
"bittorrent-tracker": "^9.0.0",
"bluebird": "^3.5.0",
"body-parser": "^1.12.4",
"bytes": "^3.0.0",
"cli-table": "^0.3.1",
"commander": "^2.13.0",
- "concurrently": "^4.0.1",
"config": "^3.0.0",
"cookie-parser": "^1.4.3",
"cors": "^2.8.1",
"deep-object-diff": "^1.1.0",
"express": "^4.12.4",
"express-oauth-server": "^2.0.0",
- "express-rate-limit": "^3.1.0",
+ "express-rate-limit": "^4.0.4",
"express-validator": "^5.0.0",
"flat": "^4.1.0",
"fluent-ffmpeg": "^2.1.0",
- "fs-extra": "^7.0.0",
+ "fs-extra": "^8.0.1",
"helmet": "^3.12.1",
"http-signature": "^1.2.0",
- "ip-anonymize": "^0.0.6",
+ "ip-anonymize": "^0.1.0",
"ipaddr.js": "1.9.0",
"is-cidr": "^3.0.0",
"iso-639-3": "^1.0.1",
"reflect-metadata": "^0.1.12",
"request": "^2.81.0",
"scripty": "^1.5.0",
- "sequelize": "5.7.4",
+ "sequelize": "5.8.7",
"sequelize-typescript": "1.0.0-beta.2",
"sharp": "^0.22.0",
"sitemap": "^2.1.0",
"socket.io": "^2.2.0",
"srt-to-vtt": "^1.1.2",
- "summon-install": "^0.4.3",
"useragent": "^2.3.0",
"uuid": "^3.1.0",
- "validator": "^10.2.0",
+ "validator": "^11.0.0",
"webfinger.js": "^2.6.6",
"webtorrent": "^0.103.0",
"winston": "3.2.1",
- "ws": "^6.0.0",
- "youtube-dl": "^1.12.2"
+ "ws": "^7.0.0",
+ "youtube-dl": "^2.0.0"
},
"devDependencies": {
"@types/apicache": "^1.2.0",
- "@types/async": "^2.0.40",
+ "@types/async": "^3.0.0",
"@types/async-lock": "^1.1.0",
"@types/bcrypt": "^3.0.0",
"@types/bluebird": "3.5.21",
"@types/express": "^4.0.35",
"@types/express-rate-limit": "^3.3.0",
"@types/fluent-ffmpeg": "^2.1.8",
- "@types/fs-extra": "^5.0.4",
+ "@types/fs-extra": "^7.0.0",
"@types/libxmljs": "^0.18.0",
"@types/lodash": "^4.14.64",
"@types/magnet-uri": "^5.1.1",
"@types/morgan": "^1.7.32",
"@types/multer": "^1.3.3",
"@types/node": "^10.0.8",
- "@types/nodemailer": "^4.3.1",
+ "@types/nodemailer": "^6.2.0",
"@types/oauth2-server": "^3.0.8",
"@types/pem": "^1.9.3",
"@types/redis": "^2.8.5",
"chai": "^4.1.1",
"chai-json-schema": "^1.5.0",
"chai-xml": "^0.3.2",
- "husky": "^1.0.0-rc.4",
+ "concurrently": "^4.1.0",
+ "husky": "^2.4.0",
"libxmljs": "0.19.5",
"lint-staged": "^8.0.4",
"maildev": "^1.0.0-rc3",
- "marked-man": "^0.4.2",
+ "marked-man": "^0.6.0",
"mocha": "^6.0.0",
+ "mocha-parallel-tests": "^2.1.0",
"nodemon": "^1.18.6",
"sass-lint": "^1.12.1",
"source-map-support": "^0.5.0",
"supertest": "^4.0.2",
"swagger-cli": "^2.2.0",
- "ts-node": "8.0.3",
+ "ts-node": "8.2.0",
"tslint": "^5.7.0",
"tslint-config-standard": "^8.0.1",
"typescript": "^3.4.3",
"scripty": {
"silent": true
},
- "summon": {
- "silent": true
- },
"sasslintConfig": "client/.sass-lint.yml"
}
}
dropRedis () {
- redis-cli KEYS "bull-localhost:900$1*" | grep -v empty | xargs --no-run-if-empty redis-cli DEL
- redis-cli KEYS "redis-localhost:900$1*" | grep -v empty | xargs --no-run-if-empty redis-cli DEL
+ port=$((9000+$1))
+
+ redis-cli KEYS "bull-localhost:$port*" | grep -v empty | xargs --no-run-if-empty redis-cli DEL
+ redis-cli KEYS "redis-localhost:$port*" | grep -v empty | xargs --no-run-if-empty redis-cli DEL
+ redis-cli KEYS "*redis-localhost:$port-" | grep -v empty | xargs --no-run-if-empty redis-cli DEL
}
seq=$(seq 1 6)
import { VideoModel } from '../server/models/video/video'
import { initDatabaseModels } from '../server/initializers'
import { JobQueue } from '../server/lib/job-queue'
+import { VideoTranscodingPayload } from '../server/lib/job-queue/handlers/video-transcoding'
program
.option('-v, --video [videoUUID]', 'Video UUID')
const video = await VideoModel.loadByUUIDWithFile(program['video'])
if (!video) throw new Error('Video not found.')
- const dataInput = {
- videoUUID: video.uuid,
- isNewVideo: false,
- resolution: undefined
- }
-
- if (program.resolution !== undefined) {
- dataInput.resolution = program.resolution
- }
+ const dataInput: VideoTranscodingPayload = program.resolution !== undefined
+ ? { type: 'new-resolution' as 'new-resolution', videoUUID: video.uuid, isNewVideo: false, resolution: program.resolution }
+ : { type: 'optimize' as 'optimize', videoUUID: video.uuid, isNewVideo: false }
await JobQueue.Instance.init()
await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput })
--- /dev/null
+#!/bin/sh
+
+set -eu
+
+NOCLIENT=1 yarn install --pure-lockfile
+
+rm -rf ./dist/server/tools/
+
+(
+ cd ./server/tools
+ yarn install --pure-lockfile
+)
+
+npm run tsc -- --build ./server/tools/tsconfig.json
+
+mv "./server/tools/node_modules" "./dist/server/tools"
set -eu
npm run build:server
+npm run setup:cli
+
npm run travis -- lint
mocha --exit --require ts-node/register/type-check --bail server/tests/index.ts
server/tests/helpers/index.ts
elif [ "$1" = "cli" ]; then
npm run build:server
+ CC=gcc-4.9 CXX=g++-4.9 npm run setup:cli
mocha --timeout 5000 --exit --require ts-node/register --bail server/tests/cli/index.ts
elif [ "$1" = "api-1" ]; then
npm run build:server
- mocha --timeout 5000 --exit --require ts-node/register --bail server/tests/api/index-1.ts
+ sh ./server/tests/api/travis-1.sh 2
elif [ "$1" = "api-2" ]; then
npm run build:server
- mocha --timeout 5000 --exit --require ts-node/register --bail server/tests/api/index-2.ts
+ sh ./server/tests/api/travis-2.sh 2
elif [ "$1" = "api-3" ]; then
npm run build:server
- mocha --timeout 5000 --exit --require ts-node/register --bail server/tests/api/index-3.ts
+ sh ./server/tests/api/travis-3.sh 2
elif [ "$1" = "api-4" ]; then
npm run build:server
- mocha --timeout 5000 --exit --require ts-node/register --bail server/tests/api/index-4.ts
+ sh ./server/tests/api/travis-4.sh 2
elif [ "$1" = "lint" ]; then
npm run tslint -- --project ./tsconfig.json -c ./tslint.json server.ts "server/**/*.ts" "shared/**/*.ts"
accountNameWithHostGetValidator,
accountsSortValidator,
ensureAuthUserOwnsAccountValidator,
- videosSortValidator
+ videosSortValidator,
+ videoChannelsSortValidator
} from '../../middlewares/validators'
import { AccountModel } from '../../models/account/account'
import { AccountVideoRateModel } from '../../models/account/account-video-rate'
accountsRouter.get('/:accountName/video-channels',
asyncMiddleware(accountNameWithHostGetValidator),
+ paginationValidator,
+ videoChannelsSortValidator,
+ setDefaultSort,
+ setDefaultPagination,
asyncMiddleware(listAccountChannels)
)
}
async function listAccountChannels (req: express.Request, res: express.Response) {
- const resultList = await VideoChannelModel.listByAccount(res.locals.account.id)
+ const options = {
+ accountId: res.locals.account.id,
+ start: req.query.start,
+ count: req.query.count,
+ sort: req.query.sort
+ }
+
+ const resultList = await VideoChannelModel.listByAccount(options)
return res.json(getFormattedObjects(resultList.data, resultList.total))
}
if (serverCommit === undefined) serverCommit = await getServerCommit()
const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
- .filter(key => CONFIG.TRANSCODING.ENABLED === CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
+ .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
.map(r => parseInt(r, 10))
const json: ServerConfig = {
transcoding: {
enabled: CONFIG.TRANSCODING.ENABLED,
allowAdditionalExtensions: CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS,
+ allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES,
threads: CONFIG.TRANSCODING.THREADS,
resolutions: {
'240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ],
import { CONFIG } from '../../../initializers/config'
import { sequelizeTypescript } from '../../../initializers/database'
import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
+import { UserRegister } from '../../../../shared/models/users/user-register.model'
const auditLogger = auditLoggerFactory('users')
-const loginRateLimiter = new RateLimit({
+// FIXME: https://github.com/nfriedly/express-rate-limit/issues/138
+// @ts-ignore
+const loginRateLimiter = RateLimit({
windowMs: RATES_LIMIT.LOGIN.WINDOW_MS,
max: RATES_LIMIT.LOGIN.MAX
})
+// @ts-ignore
const askSendEmailLimiter = new RateLimit({
windowMs: RATES_LIMIT.ASK_SEND_EMAIL.WINDOW_MS,
max: RATES_LIMIT.ASK_SEND_EMAIL.MAX
user: {
id: user.id,
account: {
- id: account.id,
- uuid: account.Actor.uuid
+ id: account.id
}
}
}).end()
}
async function registerUser (req: express.Request, res: express.Response) {
- const body: UserCreate = req.body
+ const body: UserRegister = req.body
const userToCreate = new UserModel({
username: body.username,
emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
})
- const { user } = await createUserAccountAndChannelAndPlaylist(userToCreate)
+ const { user } = await createUserAccountAndChannelAndPlaylist(userToCreate, body.channel)
auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON()))
logger.info('User %s with its channel and account registered.', body.username)
import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../middlewares/validators'
import { sendUpdateActor } from '../../lib/activitypub/send'
import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared'
-import { createVideoChannel } from '../../lib/video-channel'
+import { createVideoChannel, federateAllVideosOfChannel } from '../../lib/video-channel'
import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
import { setAsyncActorKeys } from '../../lib/activitypub'
import { AccountModel } from '../../models/account/account'
})
setAsyncActorKeys(videoChannelCreated.Actor)
- .catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.uuid, { err }))
+ .catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.url, { err }))
auditLogger.create(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelCreated.toFormattedJSON()))
- logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid)
+ logger.info('Video channel %s created.', videoChannelCreated.Actor.url)
return res.json({
videoChannel: {
- id: videoChannelCreated.id,
- uuid: videoChannelCreated.Actor.uuid
+ id: videoChannelCreated.id
}
}).end()
}
const videoChannelFieldsSave = videoChannelInstance.toJSON()
const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannelInstance.toFormattedJSON())
const videoChannelInfoToUpdate = req.body as VideoChannelUpdate
+ let doBulkVideoUpdate = false
try {
await sequelizeTypescript.transaction(async t => {
transaction: t
}
- if (videoChannelInfoToUpdate.displayName !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.displayName)
- if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description)
- if (videoChannelInfoToUpdate.support !== undefined) videoChannelInstance.set('support', videoChannelInfoToUpdate.support)
+ if (videoChannelInfoToUpdate.displayName !== undefined) videoChannelInstance.name = videoChannelInfoToUpdate.displayName
+ if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.description = videoChannelInfoToUpdate.description
+
+ if (videoChannelInfoToUpdate.support !== undefined) {
+ const oldSupportField = videoChannelInstance.support
+ videoChannelInstance.support = videoChannelInfoToUpdate.support
+
+ if (videoChannelInfoToUpdate.bulkVideosSupportUpdate === true && oldSupportField !== videoChannelInfoToUpdate.support) {
+ doBulkVideoUpdate = true
+ await VideoModel.bulkUpdateSupportField(videoChannelInstance, t)
+ }
+ }
const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions)
await sendUpdateActor(videoChannelInstanceUpdated, t)
new VideoChannelAuditView(videoChannelInstanceUpdated.toFormattedJSON()),
oldVideoChannelAuditKeys
)
- logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.Actor.uuid)
+
+ logger.info('Video channel %s updated.', videoChannelInstance.Actor.url)
})
} catch (err) {
logger.debug('Cannot update the video channel.', { err })
throw err
}
- return res.type('json').status(204).end()
+ res.type('json').status(204).end()
+
+ // Don't process in a transaction, and after the response because it could be long
+ if (doBulkVideoUpdate) {
+ await federateAllVideosOfChannel(videoChannelInstance)
+ }
}
async function removeVideoChannel (req: express.Request, res: express.Response) {
await videoChannelInstance.destroy({ transaction: t })
auditLogger.delete(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelInstance.toFormattedJSON()))
- logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.Actor.uuid)
+ logger.info('Video channel %s deleted.', videoChannelInstance.Actor.url)
})
return res.type('json').status(204).end()
const videoPlaylistInstance = res.locals.videoPlaylist
const videoPlaylistFieldsSave = videoPlaylistInstance.toJSON()
const videoPlaylistInfoToUpdate = req.body as VideoPlaylistUpdate
+
const wasPrivatePlaylist = videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE
+ const wasNotPrivatePlaylist = videoPlaylistInstance.privacy !== VideoPlaylistPrivacy.PRIVATE
const thumbnailField = req.files['thumbnailfile']
const thumbnailModel = thumbnailField
if (videoPlaylistInfoToUpdate.privacy !== undefined) {
videoPlaylistInstance.privacy = parseInt(videoPlaylistInfoToUpdate.privacy.toString(), 10)
+
+ if (wasNotPrivatePlaylist === true && videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE) {
+ await sendDeleteVideoPlaylist(videoPlaylistInstance, t)
+ }
}
const playlistUpdated = await videoPlaylistInstance.save(sequelizeOptions)
import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger'
import { getFormattedObjects, getServerActor } from '../../../helpers/utils'
import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist'
-import { MIMETYPES, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../initializers/constants'
+import {
+ DEFAULT_AUDIO_RESOLUTION,
+ MIMETYPES,
+ VIDEO_CATEGORIES,
+ VIDEO_LANGUAGES,
+ VIDEO_LICENCES,
+ VIDEO_PRIVACIES
+} from '../../../initializers/constants'
import {
changeVideoChannelShare,
federateVideoIfNeeded,
import { sequelizeTypescript } from '../../../initializers/database'
import { createVideoMiniatureFromExisting, generateVideoMiniature } from '../../../lib/thumbnail'
import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type'
+import { VideoTranscodingPayload } from '../../../lib/job-queue/handlers/video-transcoding'
const auditLogger = auditLoggerFactory('videos')
const videosRouter = express.Router()
const video = new VideoModel(videoData)
video.url = getVideoActivityPubUrl(video) // We use the UUID, so set the URL after building the object
- // Build the file object
- const { videoFileResolution } = await getVideoFileResolution(videoPhysicalFile.path)
- const fps = await getVideoFileFPS(videoPhysicalFile.path)
-
- const videoFileData = {
+ const videoFile = new VideoFileModel({
extname: extname(videoPhysicalFile.filename),
- resolution: videoFileResolution,
- size: videoPhysicalFile.size,
- fps
+ size: videoPhysicalFile.size
+ })
+
+ if (videoFile.isAudio()) {
+ videoFile.resolution = DEFAULT_AUDIO_RESOLUTION
+ } else {
+ videoFile.fps = await getVideoFileFPS(videoPhysicalFile.path)
+ videoFile.resolution = (await getVideoFileResolution(videoPhysicalFile.path)).videoFileResolution
}
- const videoFile = new VideoFileModel(videoFileData)
// Move physical file
const videoDir = CONFIG.STORAGE.VIDEOS_DIR
if (video.state === VideoState.TO_TRANSCODE) {
// Put uuid because we don't have id auto incremented for now
- const dataInput = {
- videoUUID: videoCreated.uuid,
- isNewVideo: true
+ let dataInput: VideoTranscodingPayload
+
+ if (videoFile.isAudio()) {
+ dataInput = {
+ type: 'merge-audio' as 'merge-audio',
+ resolution: DEFAULT_AUDIO_RESOLUTION,
+ videoUUID: videoCreated.uuid,
+ isNewVideo: true
+ }
+ } else {
+ dataInput = {
+ type: 'optimize' as 'optimize',
+ videoUUID: videoCreated.uuid,
+ isNewVideo: true
+ }
}
await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput })
const videoFieldsSave = videoInstance.toJSON()
const oldVideoAuditView = new VideoAuditView(videoInstance.toFormattedDetailsJSON())
const videoInfoToUpdate: VideoUpdate = req.body
+
const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE
+ const wasNotPrivateVideo = videoInstance.privacy !== VideoPrivacy.PRIVATE
const wasUnlistedVideo = videoInstance.privacy === VideoPrivacy.UNLISTED
// Process thumbnail or create it from the video
const newPrivacy = parseInt(videoInfoToUpdate.privacy.toString(), 10)
videoInstance.privacy = newPrivacy
+ // The video was private, and is not anymore -> publish it
if (wasPrivateVideo === true && newPrivacy !== VideoPrivacy.PRIVATE) {
videoInstance.publishedAt = new Date()
}
+
+ // The video was not private, but now it is -> we need to unfederate it
+ if (wasNotPrivateVideo === true && newPrivacy === VideoPrivacy.PRIVATE) {
+ await VideoModel.sendDelete(videoInstance, { transaction: t })
+ }
}
const videoInstanceUpdated = await videoInstance.save(sequelizeOptions)
return res.sendFile(result.path, { maxAge: STATIC_MAX_AGE })
}
-async function generateNodeinfo (req: express.Request, res: express.Response, next: express.NextFunction) {
+async function generateNodeinfo (req: express.Request, res: express.Response) {
const { totalVideos } = await VideoModel.getStats()
const { totalLocalVideoComments } = await VideoCommentModel.getStats()
const { totalUsers } = await UserModel.getStats()
import * as Bluebird from 'bluebird'
import { Response } from 'express'
import 'express-validator'
-import * as validator from 'validator'
import { AccountModel } from '../../models/account/account'
import { isUserDescriptionValid, isUserUsernameValid } from './users'
import { exists } from './misc'
return isUserDescriptionValid(value)
}
-function doesAccountIdExist (id: number | string, res: Response, sendNotFound = true) {
- let promise: Bluebird<AccountModel>
-
- if (validator.isInt('' + id)) {
- promise = AccountModel.load(+id)
- } else { // UUID
- promise = AccountModel.loadByUUID('' + id)
- }
+function doesAccountIdExist (id: number, res: Response, sendNotFound = true) {
+ const promise = AccountModel.load(id)
return doesAccountExist(promise, res, sendNotFound)
}
if (!comment) return
if (typeof comment.url !== 'string') {
- comment.url = comment.url.href || comment.url.url
+ if (typeof comment.url === 'object') comment.url = comment.url.href || comment.url.url
+ else comment.url = comment.id
}
return
return processVideoChannelExist(videoChannel, res)
}
-async function doesVideoChannelIdExist (id: number | string, res: express.Response) {
- let videoChannel: VideoChannelModel
- if (validator.isInt('' + id)) {
- videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id)
- } else { // UUID
- videoChannel = await VideoChannelModel.loadByUUIDAndPopulateAccount('' + id)
- }
+async function doesVideoChannelIdExist (id: number, res: express.Response) {
+ const videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id)
return processVideoChannelExist(videoChannel, res)
}
},
filename: async (req, file, cb) => {
- const extension = mimeTypes[ file.mimetype ] || extname(file.originalname)
+ let extension: string
+ const fileExtension = extname(file.originalname)
+ const extensionFromMimetype = mimeTypes[ file.mimetype ]
+
+ // Take the file extension if we don't understand the mime type
+ // We have the OGG/OGV exception too because firefox sends a bad mime type when sending an OGG file
+ if (fileExtension === '.ogg' || fileExtension === '.ogv' || !extensionFromMimetype) {
+ extension = fileExtension
+ } else {
+ extension = extensionFromMimetype
+ }
+
let randomString = ''
try {
import * as ffmpeg from 'fluent-ffmpeg'
import { dirname, join } from 'path'
-import { getTargetBitrate, VideoResolution } from '../../shared/models/videos'
+import { getTargetBitrate, getMaxBitrate, VideoResolution } from '../../shared/models/videos'
import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants'
import { processImage } from './image-utils'
import { logger } from './logger'
VideoResolution.H_360P,
VideoResolution.H_720P,
VideoResolution.H_240P,
- VideoResolution.H_1080P
+ VideoResolution.H_1080P,
+ VideoResolution.H_4K
]
for (const resolution of resolutions) {
}
async function getVideoFileSize (path: string) {
- const videoStream = await getVideoFileStream(path)
+ const videoStream = await getVideoStreamFromFile(path)
return {
width: videoStream.width,
}
async function getVideoFileFPS (path: string) {
- const videoStream = await getVideoFileStream(path)
+ const videoStream = await getVideoStreamFromFile(path)
for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) {
const valuesText: string = videoStream[key]
}
}
-type TranscodeOptions = {
+type TranscodeOptionsType = 'hls' | 'quick-transcode' | 'video' | 'merge-audio'
+
+interface BaseTranscodeOptions {
+ type: TranscodeOptionsType
inputPath: string
outputPath: string
resolution: VideoResolution
isPortraitMode?: boolean
+}
- hlsPlaylist?: {
+interface HLSTranscodeOptions extends BaseTranscodeOptions {
+ type: 'hls'
+ hlsPlaylist: {
videoFilename: string
}
}
+interface QuickTranscodeOptions extends BaseTranscodeOptions {
+ type: 'quick-transcode'
+}
+
+interface VideoTranscodeOptions extends BaseTranscodeOptions {
+ type: 'video'
+}
+
+interface MergeAudioTranscodeOptions extends BaseTranscodeOptions {
+ type: 'merge-audio'
+ audioPath: string
+}
+
+type TranscodeOptions = HLSTranscodeOptions | VideoTranscodeOptions | MergeAudioTranscodeOptions | QuickTranscodeOptions
+
function transcode (options: TranscodeOptions) {
return new Promise<void>(async (res, rej) => {
try {
let command = ffmpeg(options.inputPath, { niceness: FFMPEG_NICE.TRANSCODING })
.output(options.outputPath)
- if (options.hlsPlaylist) {
+ if (options.type === 'quick-transcode') {
+ command = await buildQuickTranscodeCommand(command)
+ } else if (options.type === 'hls') {
command = await buildHLSCommand(command, options)
+ } else if (options.type === 'merge-audio') {
+ command = await buildAudioMergeCommand(command, options)
} else {
command = await buildx264Command(command, options)
}
return rej(err)
})
.on('end', () => {
- return onTranscodingSuccess(options)
+ return fixHLSPlaylistIfNeeded(options)
.then(() => res())
.catch(err => rej(err))
})
})
}
+async function canDoQuickTranscode (path: string): Promise<boolean> {
+ // NOTE: This could be optimized by running ffprobe only once (but it runs fast anyway)
+ const videoStream = await getVideoStreamFromFile(path)
+ const parsedAudio = await audio.get(path)
+ const fps = await getVideoFileFPS(path)
+ const bitRate = await getVideoFileBitrate(path)
+ const resolution = await getVideoFileResolution(path)
+
+ // check video params
+ if (videoStream[ 'codec_name' ] !== 'h264') return false
+ if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false
+ if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false
+
+ // check audio params (if audio stream exists)
+ if (parsedAudio.audioStream) {
+ if (parsedAudio.audioStream[ 'codec_name' ] !== 'aac') return false
+
+ const maxAudioBitrate = audio.bitrate[ 'aac' ](parsedAudio.audioStream[ 'bit_rate' ])
+ if (maxAudioBitrate !== -1 && parsedAudio.audioStream[ 'bit_rate' ] > maxAudioBitrate) return false
+ }
+
+ return true
+}
+
// ---------------------------------------------------------------------------
export {
getVideoFileResolution,
getDurationFromVideoFile,
generateImageFromVideoFile,
+ TranscodeOptions,
+ TranscodeOptionsType,
transcode,
getVideoFileFPS,
computeResolutionsToTranscode,
audio,
- getVideoFileBitrate
+ getVideoFileBitrate,
+ canDoQuickTranscode
}
// ---------------------------------------------------------------------------
-async function buildx264Command (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) {
+async function buildx264Command (command: ffmpeg.FfmpegCommand, options: VideoTranscodeOptions) {
let fps = await getVideoFileFPS(options.inputPath)
// On small/medium resolutions, limit FPS
if (
fps = VIDEO_TRANSCODING_FPS.AVERAGE
}
- command = await presetH264(command, options.resolution, fps)
+ command = await presetH264(command, options.inputPath, options.resolution, fps)
if (options.resolution !== undefined) {
// '?x720' or '720x?' for example
return command
}
-async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) {
+async function buildAudioMergeCommand (command: ffmpeg.FfmpegCommand, options: MergeAudioTranscodeOptions) {
+ command = command.loop(undefined)
+
+ command = await presetH264VeryFast(command, options.audioPath, options.resolution)
+
+ command = command.input(options.audioPath)
+ .videoFilter('scale=trunc(iw/2)*2:trunc(ih/2)*2') // Avoid "height not divisible by 2" error
+ .outputOption('-tune stillimage')
+ .outputOption('-shortest')
+
+ return command
+}
+
+async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) {
+ command = await presetCopy(command)
+
+ command = command.outputOption('-map_metadata -1') // strip all metadata
+ .outputOption('-movflags faststart')
+
+ return command
+}
+
+async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTranscodeOptions) {
const videoPath = getHLSVideoPath(options)
command = await presetCopy(command)
return command
}
-function getHLSVideoPath (options: TranscodeOptions) {
+function getHLSVideoPath (options: HLSTranscodeOptions) {
return `${dirname(options.outputPath)}/${options.hlsPlaylist.videoFilename}`
}
-async function onTranscodingSuccess (options: TranscodeOptions) {
- if (!options.hlsPlaylist) return
+async function fixHLSPlaylistIfNeeded (options: TranscodeOptions) {
+ if (options.type !== 'hls') return
- // Fix wrong mapping with some ffmpeg versions
const fileContent = await readFile(options.outputPath)
const videoFileName = options.hlsPlaylist.videoFilename
const videoFilePath = getHLSVideoPath(options)
+ // Fix wrong mapping with some ffmpeg versions
const newContent = fileContent.toString()
.replace(`#EXT-X-MAP:URI="${videoFilePath}",`, `#EXT-X-MAP:URI="${videoFileName}",`)
await writeFile(options.outputPath, newContent)
}
-function getVideoFileStream (path: string) {
+function getVideoStreamFromFile (path: string) {
return new Promise<any>((res, rej) => {
ffmpeg.ffprobe(path, (err, metadata) => {
if (err) return rej(err)
* and quality. Superfast and ultrafast will give you better
* performance, but then quality is noticeably worse.
*/
-async function presetH264VeryFast (command: ffmpeg.FfmpegCommand, resolution: VideoResolution, fps: number): Promise<ffmpeg.FfmpegCommand> {
- let localCommand = await presetH264(command, resolution, fps)
+async function presetH264VeryFast (command: ffmpeg.FfmpegCommand, input: string, resolution: VideoResolution, fps?: number) {
+ let localCommand = await presetH264(command, input, resolution, fps)
+
localCommand = localCommand.outputOption('-preset:v veryfast')
- .outputOption([ '--aq-mode=2', '--aq-strength=1.3' ])
+
/*
MAIN reference: https://slhck.info/video/2017/03/01/rate-control.html
Our target situation is closer to a livestream than a stream,
since we want to reduce as much a possible the encoding burden,
- altough not to the point of a livestream where there is a hard
+ although not to the point of a livestream where there is a hard
constraint on the frames per second to be encoded.
-
- why '--aq-mode=2 --aq-strength=1.3' instead of '-profile:v main'?
- Make up for most of the loss of grain and macroblocking
- with less computing power.
*/
return localCommand
}
-/**
- * A preset optimised for a stillimage audio video
- */
-async function presetStillImageWithAudio (
- command: ffmpeg.FfmpegCommand,
- resolution: VideoResolution,
- fps: number
-): Promise<ffmpeg.FfmpegCommand> {
- let localCommand = await presetH264VeryFast(command, resolution, fps)
- localCommand = localCommand.outputOption('-tune stillimage')
-
- return localCommand
-}
-
/**
* A toolbox to play with audio
*/
namespace audio {
- export const get = (option: ffmpeg.FfmpegCommand | string) => {
+ export const get = (option: string) => {
// without position, ffprobe considers the last input only
// we make it consider the first input only
// if you pass a file path to pos, then ffprobe acts on that file directly
return res({ absolutePath: data.format.filename })
}
- if (typeof option === 'string') {
- return ffmpeg.ffprobe(option, parseFfprobe)
- }
-
- return option.ffprobe(parseFfprobe)
+ return ffmpeg.ffprobe(option, parseFfprobe)
})
}
* As for the audio, quality '5' is the highest and ensures 96-112kbps/channel
* See https://trac.ffmpeg.org/wiki/Encode/AAC#fdk_vbr
*/
-async function presetH264 (command: ffmpeg.FfmpegCommand, resolution: VideoResolution, fps: number): Promise<ffmpeg.FfmpegCommand> {
+async function presetH264 (command: ffmpeg.FfmpegCommand, input: string, resolution: VideoResolution, fps?: number) {
let localCommand = command
.format('mp4')
.videoCodec('libx264')
.outputOption('-map_metadata -1') // strip all metadata
.outputOption('-movflags faststart')
- const parsedAudio = await audio.get(localCommand)
+ const parsedAudio = await audio.get(input)
if (!parsedAudio.audioStream) {
localCommand = localCommand.noAudio()
.audioCodec('libfdk_aac')
.audioQuality(5)
} else {
- // we try to reduce the ceiling bitrate by making rough correspondances of bitrates
+ // we try to reduce the ceiling bitrate by making rough matches of bitrates
// of course this is far from perfect, but it might save some space in the end
+ localCommand = localCommand.audioCodec('aac')
+
const audioCodecName = parsedAudio.audioStream[ 'codec_name' ]
- let bitrate: number
- if (audio.bitrate[ audioCodecName ]) {
- localCommand = localCommand.audioCodec('aac')
- bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ])
+ if (audio.bitrate[ audioCodecName ]) {
+ const bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ])
if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate)
}
}
- // Constrained Encoding (VBV)
- // https://slhck.info/video/2017/03/01/rate-control.html
- // https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate
- const targetBitrate = getTargetBitrate(resolution, fps, VIDEO_TRANSCODING_FPS)
- localCommand = localCommand.outputOptions([`-maxrate ${ targetBitrate }`, `-bufsize ${ targetBitrate * 2 }`])
-
- // Keyframe interval of 2 seconds for faster seeking and resolution switching.
- // https://streaminglearningcenter.com/blogs/whats-the-right-keyframe-interval.html
- // https://superuser.com/a/908325
- localCommand = localCommand.outputOption(`-g ${ fps * 2 }`)
+ if (fps) {
+ // Constrained Encoding (VBV)
+ // https://slhck.info/video/2017/03/01/rate-control.html
+ // https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate
+ const targetBitrate = getTargetBitrate(resolution, fps, VIDEO_TRANSCODING_FPS)
+ localCommand = localCommand.outputOptions([ `-maxrate ${targetBitrate}`, `-bufsize ${targetBitrate * 2}` ])
+
+ // Keyframe interval of 2 seconds for faster seeking and resolution switching.
+ // https://streaminglearningcenter.com/blogs/whats-the-right-keyframe-interval.html
+ // https://superuser.com/a/908325
+ localCommand = localCommand.outputOption(`-g ${fps * 2}`)
+ }
return localCommand
}
CA_FILE: config.get<string>('smtp.ca_file'),
FROM_ADDRESS: config.get<string>('smtp.from_address')
},
+ EMAIL: {
+ BODY: {
+ SIGNATURE: config.get<string>('email.body.signature')
+ },
+ OBJECT: {
+ PREFIX: config.get<string>('email.object.prefix') + ' '
+ }
+ },
STORAGE: {
TMP_DIR: buildPath(config.get<string>('storage.tmp')),
AVATARS_DIR: buildPath(config.get<string>('storage.avatars')),
TRANSCODING: {
get ENABLED () { return config.get<boolean>('transcoding.enabled') },
get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') },
+ get ALLOW_AUDIO_FILES () { return config.get<boolean>('transcoding.allow_audio_files') },
get THREADS () { return config.get<number>('transcoding.threads') },
RESOLUTIONS: {
get '240p' () { return config.get<boolean>('transcoding.resolutions.240p') },
import { join } from 'path'
-import { JobType, VideoRateType, VideoState } from '../../shared/models'
+import { JobType, VideoRateType, VideoResolution, VideoState } from '../../shared/models'
import { ActivityPubActorType } from '../../shared/models/activitypub'
import { FollowState } from '../../shared/models/actors'
import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos'
// Do not use barrels, remain constants as independent as possible
-import { isTestInstance, sanitizeHost, sanitizeUrl } from '../helpers/core-utils'
+import { isTestInstance, sanitizeHost, sanitizeUrl, root } from '../helpers/core-utils'
import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type'
import { invert } from 'lodash'
import { CronRepeatOptions, EveryRepeatOptions } from 'bull'
// ---------------------------------------------------------------------------
-const LAST_MIGRATION_VERSION = 380
+const LAST_MIGRATION_VERSION = 385
// ---------------------------------------------------------------------------
max: 2 * 1024 * 1024 // 2MB
}
},
- EXTNAME: buildVideosExtname(),
+ EXTNAME: [] as string[],
INFO_HASH: { min: 40, max: 40 }, // Length, info hash is 20 bytes length but we represent it in hexadecimal so 20 * 2
DURATION: { min: 0 }, // Number
TAGS: { min: 0, max: 5 }, // Number of total tags
KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum)
}
+const DEFAULT_AUDIO_RESOLUTION = VideoResolution.H_480P
+
const VIDEO_RATE_TYPES: { [ id: string ]: VideoRateType } = {
LIKE: 'like',
DISLIKE: 'dislike'
}
const MIMETYPES = {
+ AUDIO: {
+ MIMETYPE_EXT: {
+ 'audio/mpeg': '.mp3',
+ 'audio/mp3': '.mp3',
+ 'application/ogg': '.ogg',
+ 'audio/ogg': '.ogg',
+ 'audio/flac': '.flac'
+ },
+ EXT_MIMETYPE: null as { [ id: string ]: string }
+ },
VIDEO: {
- MIMETYPE_EXT: buildVideoMimetypeExt(),
+ MIMETYPE_EXT: null as { [ id: string ]: string },
EXT_MIMETYPE: null as { [ id: string ]: string }
},
IMAGE: {
}
}
}
-MIMETYPES.VIDEO.EXT_MIMETYPE = invert(MIMETYPES.VIDEO.MIMETYPE_EXT)
+MIMETYPES.AUDIO.EXT_MIMETYPE = invert(MIMETYPES.AUDIO.MIMETYPE_EXT)
// ---------------------------------------------------------------------------
COLLECTION_ITEMS_PER_PAGE: 10,
FETCH_PAGE_LIMIT: 100,
URL_MIME_TYPES: {
- VIDEO: Object.keys(MIMETYPES.VIDEO.MIMETYPE_EXT),
+ VIDEO: [] as string[],
TORRENT: [ 'application/x-bittorrent' ],
MAGNET: [ 'application/x-bittorrent;x-scheme-handler/magnet' ]
},
height: 122
}
const PREVIEWS_SIZE = {
- width: 560,
- height: 315
+ width: 850,
+ height: 480
}
const AVATARS_SIZE = {
width: 120,
const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS)
+const ASSETS_PATH = {
+ DEFAULT_AUDIO_BACKGROUND: join(root(), 'server', 'assets', 'default-audio-background.jpg')
+}
+
// ---------------------------------------------------------------------------
const CUSTOM_HTML_TAG_COMMENTS = {
}
updateWebserverUrls()
+updateWebserverConfig()
registerConfigChangedHandler(() => {
updateWebserverUrls()
RATES_LIMIT,
MIMETYPES,
CRAWL_REQUEST_CONCURRENCY,
+ DEFAULT_AUDIO_RESOLUTION,
JOB_COMPLETED_LIFETIME,
HTTP_SIGNATURE,
VIDEO_IMPORT_STATES,
VIDEO_VIEW_LIFETIME,
CONTACT_FORM_LIFETIME,
VIDEO_PLAYLIST_PRIVACIES,
+ ASSETS_PATH,
loadLanguages,
buildLanguages
}
'video/mp4': '.mp4'
}
- if (CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS) {
- Object.assign(data, {
- 'video/quicktime': '.mov',
- 'video/x-msvideo': '.avi',
- 'video/x-flv': '.flv',
- 'video/x-matroska': '.mkv',
- 'application/octet-stream': '.mkv',
- 'video/avi': '.avi'
- })
+ if (CONFIG.TRANSCODING.ENABLED) {
+ if (CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS) {
+ Object.assign(data, {
+ 'video/quicktime': '.mov',
+ 'video/x-msvideo': '.avi',
+ 'video/x-flv': '.flv',
+ 'video/x-matroska': '.mkv',
+ 'application/octet-stream': '.mkv',
+ 'video/avi': '.avi'
+ })
+ }
+
+ if (CONFIG.TRANSCODING.ALLOW_AUDIO_FILES) {
+ Object.assign(data, MIMETYPES.AUDIO.MIMETYPE_EXT)
+ }
}
return data
}
function updateWebserverConfig () {
- CONSTRAINTS_FIELDS.VIDEOS.EXTNAME = buildVideosExtname()
-
MIMETYPES.VIDEO.MIMETYPE_EXT = buildVideoMimetypeExt()
MIMETYPES.VIDEO.EXT_MIMETYPE = invert(MIMETYPES.VIDEO.MIMETYPE_EXT)
+ ACTIVITY_PUB.URL_MIME_TYPES.VIDEO = Object.keys(MIMETYPES.VIDEO.MIMETYPE_EXT)
+
+ CONSTRAINTS_FIELDS.VIDEOS.EXTNAME = buildVideosExtname()
}
function buildVideosExtname () {
- return CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS
- ? [ '.mp4', '.ogv', '.webm', '.mkv', '.mov', '.avi', '.flv' ]
- : [ '.mp4', '.ogv', '.webm' ]
+ return Object.keys(MIMETYPES.VIDEO.EXT_MIMETYPE)
}
function loadLanguages () {
// Our password is weak so do not validate it
validatePassword = false
+ } else if (process.env.PT_INITIAL_ROOT_PASSWORD) {
+ password = process.env.PT_INITIAL_ROOT_PASSWORD
} else {
password = passwordGenerator(16, true)
}
}
const user = new UserModel(userData)
- await createUserAccountAndChannelAndPlaylist(user, validatePassword)
+ await createUserAccountAndChannelAndPlaylist(user, undefined, validatePassword)
logger.info('Username: ' + username)
logger.info('User password: ' + password)
}
--- /dev/null
+import * as Sequelize from 'sequelize'
+
+async function up (utils: {
+ transaction: Sequelize.Transaction,
+ queryInterface: Sequelize.QueryInterface,
+ sequelize: Sequelize.Sequelize,
+ db: any
+}): Promise<void> {
+ await utils.queryInterface.removeColumn('actor', 'uuid')
+}
+
+function down (options) {
+ throw new Error('Not implemented.')
+}
+
+export {
+ up,
+ down
+}
import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub'
import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects'
import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub'
-import { isActorObjectValid, normalizeActor } from '../../helpers/custom-validators/activitypub/actor'
+import { sanitizeAndCheckActorObject } from '../../helpers/custom-validators/activitypub/actor'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils'
import { logger } from '../../helpers/logger'
return actor.save()
})
.catch(err => {
- logger.error('Cannot set public/private keys of actor %d.', actor.uuid, { err })
+ logger.error('Cannot set public/private keys of actor %d.', actor.url, { err })
return actor
})
}
const followersCount = await fetchActorTotalItems(attributes.followers)
const followingCount = await fetchActorTotalItems(attributes.following)
- actorInstance.set('type', attributes.type)
- actorInstance.set('uuid', attributes.uuid)
- actorInstance.set('preferredUsername', attributes.preferredUsername)
- actorInstance.set('url', attributes.id)
- actorInstance.set('publicKey', attributes.publicKey.publicKeyPem)
- actorInstance.set('followersCount', followersCount)
- actorInstance.set('followingCount', followingCount)
- actorInstance.set('inboxUrl', attributes.inbox)
- actorInstance.set('outboxUrl', attributes.outbox)
- actorInstance.set('sharedInboxUrl', attributes.endpoints.sharedInbox)
- actorInstance.set('followersUrl', attributes.followers)
- actorInstance.set('followingUrl', attributes.following)
+ actorInstance.type = attributes.type
+ actorInstance.preferredUsername = attributes.preferredUsername
+ actorInstance.url = attributes.id
+ actorInstance.publicKey = attributes.publicKey.publicKeyPem
+ actorInstance.followersCount = followersCount
+ actorInstance.followingCount = followingCount
+ actorInstance.inboxUrl = attributes.inbox
+ actorInstance.outboxUrl = attributes.outbox
+ actorInstance.sharedInboxUrl = attributes.endpoints.sharedInbox
+ actorInstance.followersUrl = attributes.followers
+ actorInstance.followingUrl = attributes.following
}
async function updateActorAvatarInstance (actorInstance: ActorModel, avatarName: string, t: Transaction) {
logger.info('Fetching remote actor %s.', actorUrl)
const requestResult = await doRequest<ActivityPubActor>(options)
- normalizeActor(requestResult.body)
-
const actorJSON = requestResult.body
- if (isActorObjectValid(actorJSON) === false) {
+
+ if (sanitizeAndCheckActorObject(actorJSON) === false) {
logger.debug('Remote actor JSON is not valid.', { actorJSON })
return { result: undefined, statusCode: requestResult.response.statusCode }
}
const actor = new ActorModel({
type: actorJSON.type,
- uuid: actorJSON.uuid,
preferredUsername: actorJSON.preferredUsername,
url: actorJSON.id,
publicKey: actorJSON.publicKey.publicKeyPem,
let i = 0
let nextLink = firstBody.first
while (nextLink && i < limit) {
- // Don't crawl ourselves
- const remoteHost = parse(nextLink).host
- if (remoteHost === WEBSERVER.HOST) continue
+ let body: any
- options.uri = nextLink
+ if (typeof nextLink === 'string') {
+ // Don't crawl ourselves
+ const remoteHost = parse(nextLink).host
+ if (remoteHost === WEBSERVER.HOST) continue
+
+ options.uri = nextLink
+
+ const res = await doRequest<ActivityPubOrderedCollection<T>>(options)
+ body = res.body
+ } else {
+ // nextLink is already the object we want
+ body = nextLink
+ }
- const { body } = await doRequest<ActivityPubOrderedCollection<T>>(options)
nextLink = body.next
i++
import { VideoShareModel } from '../../../models/video/video-share'
import { forwardVideoRelatedActivity } from '../send/utils'
import { getOrCreateVideoAndAccountAndChannel } from '../videos'
-import { VideoPrivacy } from '../../../../shared/models/videos'
import { Notifier } from '../../notifier'
+import { VideoModel } from '../../../models/video/video'
+import { logger } from '../../../helpers/logger'
async function processAnnounceActivity (activity: ActivityAnnounce, actorAnnouncer: ActorModel) {
return retryTransactionWrapper(processVideoShare, actorAnnouncer, activity)
async function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnounce) {
const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id
- const { video, created: videoCreated } = await getOrCreateVideoAndAccountAndChannel({ videoObject: objectUri })
+ let video: VideoModel
+ let videoCreated: boolean
+
+ try {
+ const result = await getOrCreateVideoAndAccountAndChannel({ videoObject: objectUri })
+ video = result.video
+ videoCreated = result.created
+ } catch (err) {
+ logger.debug('Cannot process share of %s. Maybe this is not a video object, so just skipping.', objectUri, { err })
+ return
+ }
await sequelizeTypescript.transaction(async t => {
// Add share entry
import { forwardVideoRelatedActivity } from '../send/utils'
import { createOrUpdateCacheFile } from '../cache-file'
import { Notifier } from '../../notifier'
-import { processViewActivity } from './process-view'
-import { processDislikeActivity } from './process-dislike'
-import { processFlagActivity } from './process-flag'
import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object'
import { createOrUpdateVideoPlaylist } from '../playlist'
+import { VideoModel } from '../../../models/video/video'
async function processCreateActivity (activity: ActivityCreate, byActor: ActorModel) {
const activityObject = activity.object
const activityType = activityObject.type
- if (activityType === 'View') {
- return processViewActivity(activity, byActor)
- }
-
- if (activityType === 'Dislike') {
- return retryTransactionWrapper(processDislikeActivity, activity, byActor)
- }
-
- if (activityType === 'Flag') {
- return retryTransactionWrapper(processFlagActivity, activity, byActor)
- }
-
if (activityType === 'Video') {
return processCreateVideo(activity)
}
if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url)
- const { video } = await resolveThread(commentObject.inReplyTo)
+ let video: VideoModel
+ try {
+ const resolveThreadResult = await resolveThread(commentObject.inReplyTo)
+ video = resolveThreadResult.video
+ } catch (err) {
+ logger.debug(
+ 'Cannot process video comment because we could not resolve thread %s. Maybe it was not a video thread, so skip it.',
+ commentObject.inReplyTo,
+ { err }
+ )
+ return
+ }
const { comment, created } = await addVideoComment(video, commentObject.id)
}
async function processDeleteAccount (accountToRemove: AccountModel) {
- logger.debug('Removing remote account "%s".', accountToRemove.Actor.uuid)
+ logger.debug('Removing remote account "%s".', accountToRemove.Actor.url)
await sequelizeTypescript.transaction(async t => {
await accountToRemove.destroy({ transaction: t })
})
- logger.info('Remote account with uuid %s removed.', accountToRemove.Actor.uuid)
+ logger.info('Remote account %s removed.', accountToRemove.Actor.url)
}
async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelModel) {
- logger.debug('Removing remote video channel "%s".', videoChannelToRemove.Actor.uuid)
+ logger.debug('Removing remote video channel "%s".', videoChannelToRemove.Actor.url)
await sequelizeTypescript.transaction(async t => {
await videoChannelToRemove.destroy({ transaction: t })
})
- logger.info('Remote video channel with uuid %s removed.', videoChannelToRemove.Actor.uuid)
+ logger.info('Remote video channel %s removed.', videoChannelToRemove.Actor.url)
}
function processDeleteVideoComment (byActor: ActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) {
async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) {
const actorAttributesToUpdate = activity.object as ActivityPubActor
- logger.debug('Updating remote account "%s".', actorAttributesToUpdate.uuid)
+ logger.debug('Updating remote account "%s".', actorAttributesToUpdate.url)
let accountOrChannelInstance: AccountModel | VideoChannelModel
let actorFieldsSave: object
let accountOrChannelFieldsSave: object
await accountOrChannelInstance.save({ transaction: t })
})
- logger.info('Remote account with uuid %s updated', actorAttributesToUpdate.uuid)
+ logger.info('Remote account %s updated', actorAttributesToUpdate.url)
} catch (err) {
if (actor !== undefined && actorFieldsSave !== undefined) {
resetSequelizeInstance(actor, actorFieldsSave)
return { comment, created }
}
-async function resolveThread (url: string, comments: VideoCommentModel[] = []) {
+type ResolveThreadResult = Promise<{ video: VideoModel, parents: VideoCommentModel[] }>
+async function resolveThread (url: string, comments: VideoCommentModel[] = []): ResolveThreadResult {
// Already have this comment?
const commentFromDatabase = await VideoCommentModel.loadByUrlAndPopulateReplyAndVideo(url)
if (commentFromDatabase) {
return resolveThread(body.inReplyTo, comments.concat([ comment ]))
}
-
}
export {
`You can view it on ${videoUrl} ` +
`\n\n` +
`Cheers,\n` +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to,
- subject: channelName + ' just published a new video',
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + channelName + ' just published a new video',
text
}
`Your ${followType} ${followingName} has a new subscriber: ${followerName}` +
`\n\n` +
`Cheers,\n` +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to,
- subject: 'New follower on your channel ' + followingName,
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + 'New follower on your channel ' + followingName,
text
}
`Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` +
`\n\n` +
`Cheers,\n` +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to,
- subject: 'New instance follower',
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + 'New instance follower',
text
}
`You can view it on ${videoUrl} ` +
`\n\n` +
`Cheers,\n` +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to,
- subject: `Your video ${video.name} is published`,
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + `Your video ${video.name} is published`,
text
}
`You can view the imported video on ${videoUrl} ` +
`\n\n` +
`Cheers,\n` +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to,
- subject: `Your video import ${videoImport.getTargetIdentifier()} is finished`,
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + `Your video import ${videoImport.getTargetIdentifier()} is finished`,
text
}
`See your videos import dashboard for more information: ${importUrl}` +
`\n\n` +
`Cheers,\n` +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to,
- subject: `Your video import ${videoImport.getTargetIdentifier()} encountered an error`,
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + `Your video import ${videoImport.getTargetIdentifier()} encountered an error`,
text
}
`You can view it on ${commentUrl} ` +
`\n\n` +
`Cheers,\n` +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to,
- subject: 'New comment on your video ' + video.name,
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + 'New comment on your video ' + video.name,
text
}
`You can view the comment on ${commentUrl} ` +
`\n\n` +
`Cheers,\n` +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to,
- subject: 'Mention on video ' + video.name,
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Mention on video ' + video.name,
text
}
const text = `Hi,\n\n` +
`${WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` +
`Cheers,\n` +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to,
- subject: '[PeerTube] Received a video abuse',
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Received a video abuse',
text
}
`A full list of auto-blacklisted videos can be reviewed here: ${VIDEO_AUTO_BLACKLIST_URL}` +
`\n\n` +
`Cheers,\n` +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to,
- subject: '[PeerTube] An auto-blacklisted video is awaiting review',
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + 'An auto-blacklisted video is awaiting review',
text
}
const text = `Hi,\n\n` +
`User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` +
`Cheers,\n` +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to,
- subject: '[PeerTube] New user registration on ' + WEBSERVER.HOST,
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + 'New user registration on ' + WEBSERVER.HOST,
text
}
blockedString +
'\n\n' +
'Cheers,\n' +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to,
- subject: `[PeerTube] Video ${videoName} blacklisted`,
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + `Video ${videoName} blacklisted`,
text
}
`Your video ${video.name} (${videoUrl}) on ${WEBSERVER.HOST} has been unblacklisted.` +
'\n\n' +
'Cheers,\n' +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to,
- subject: `[PeerTube] Video ${video.name} unblacklisted`,
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + `Video ${video.name} unblacklisted`,
text
}
`Please follow this link to reset it: ${resetPasswordUrl}\n\n` +
`If you are not the person who initiated this request, please ignore this email.\n\n` +
`Cheers,\n` +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to: [ to ],
- subject: 'Reset your PeerTube password',
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Reset your password',
text
}
`Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` +
`If you are not the person who initiated this request, please ignore this email.\n\n` +
`Cheers,\n` +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
to: [ to ],
- subject: 'Verify your PeerTube email',
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Verify your email',
text
}
blockedString +
'\n\n' +
'Cheers,\n' +
- `PeerTube.`
+ `${CONFIG.EMAIL.BODY.SIGNATURE}`
const to = user.email
const emailPayload: EmailPayload = {
to: [ to ],
- subject: '[PeerTube] Account ' + blockedWord,
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Account ' + blockedWord,
text
}
fromDisplayName: fromEmail,
replyTo: fromEmail,
to: [ CONFIG.ADMIN.EMAIL ],
- subject: '[PeerTube] Contact form submitted',
+ subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Contact form submitted',
text
}
const video = await VideoModel.loadByUUIDWithFile(videoUUID)
if (!video) return undefined
- if (video.isOwned()) return { isOwned: true, path: join(CONFIG.STORAGE.PREVIEWS_DIR, video.getPreview().filename) }
+ if (video.isOwned()) return { isOwned: true, path: video.getPreview().getPath() }
return this.loadRemoteFile(videoUUID)
}
import * as Bull from 'bull'
import { logger } from '../../../helpers/logger'
import { VideoModel } from '../../../models/video/video'
-import { publishVideoIfNeeded } from './video-transcoding'
+import { publishNewResolutionIfNeeded } from './video-transcoding'
import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils'
import { copy, stat } from 'fs-extra'
import { VideoFileModel } from '../../../models/video/video-file'
await updateVideoFile(video, payload.filePath)
- await publishVideoIfNeeded(video)
+ await publishNewResolutionIfNeeded(video)
return video
}
if (videoImportUpdated.Video.state === VideoState.TO_TRANSCODE) {
// Put uuid because we don't have id auto incremented for now
const dataInput = {
+ type: 'optimize' as 'optimize',
videoUUID: videoImportUpdated.Video.uuid,
isNewVideo: true
}
import { sequelizeTypescript } from '../../../initializers'
import * as Bluebird from 'bluebird'
import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils'
-import { generateHlsPlaylist, optimizeVideofile, transcodeOriginalVideofile } from '../../video-transcoding'
+import { generateHlsPlaylist, optimizeVideofile, transcodeOriginalVideofile, mergeAudioVideofile } from '../../video-transcoding'
import { Notifier } from '../../notifier'
import { CONFIG } from '../../../initializers/config'
-export type VideoTranscodingPayload = {
+interface BaseTranscodingPayload {
videoUUID: string
- resolution?: VideoResolution
isNewVideo?: boolean
+}
+
+interface HLSTranscodingPayload extends BaseTranscodingPayload {
+ type: 'hls'
+ isPortraitMode?: boolean
+ resolution: VideoResolution
+}
+
+interface NewResolutionTranscodingPayload extends BaseTranscodingPayload {
+ type: 'new-resolution'
isPortraitMode?: boolean
- generateHlsPlaylist?: boolean
+ resolution: VideoResolution
+}
+
+interface MergeAudioTranscodingPayload extends BaseTranscodingPayload {
+ type: 'merge-audio'
+ resolution: VideoResolution
+}
+
+interface OptimizeTranscodingPayload extends BaseTranscodingPayload {
+ type: 'optimize'
}
+export type VideoTranscodingPayload = HLSTranscodingPayload | NewResolutionTranscodingPayload
+ | OptimizeTranscodingPayload | MergeAudioTranscodingPayload
+
async function processVideoTranscoding (job: Bull.Job) {
const payload = job.data as VideoTranscodingPayload
logger.info('Processing video file in job %d.', job.id)
return undefined
}
- if (payload.generateHlsPlaylist) {
+ if (payload.type === 'hls') {
await generateHlsPlaylist(video, payload.resolution, payload.isPortraitMode || false)
await retryTransactionWrapper(onHlsPlaylistGenerationSuccess, video)
- } else if (payload.resolution) { // Transcoding in other resolution
+ } else if (payload.type === 'new-resolution') {
await transcodeOriginalVideofile(video, payload.resolution, payload.isPortraitMode || false)
- await retryTransactionWrapper(publishVideoIfNeeded, video, payload)
+ await retryTransactionWrapper(publishNewResolutionIfNeeded, video, payload)
+ } else if (payload.type === 'merge-audio') {
+ await mergeAudioVideofile(video, payload.resolution)
+
+ await retryTransactionWrapper(publishNewResolutionIfNeeded, video, payload)
} else {
await optimizeVideofile(video)
})
}
-async function publishVideoIfNeeded (video: VideoModel, payload?: VideoTranscodingPayload) {
+async function publishNewResolutionIfNeeded (video: VideoModel, payload?: NewResolutionTranscodingPayload | MergeAudioTranscodingPayload) {
const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => {
// Maybe the video changed in database, refresh it
let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.uuid, t)
await createHlsJobIfEnabled(payload)
}
-async function onVideoFileOptimizerSuccess (videoArg: VideoModel, payload: VideoTranscodingPayload) {
+async function onVideoFileOptimizerSuccess (videoArg: VideoModel, payload: OptimizeTranscodingPayload) {
if (videoArg === undefined) return undefined
// Outside the transaction (IO on disk)
for (const resolution of resolutionsEnabled) {
const dataInput = {
+ type: 'new-resolution' as 'new-resolution',
videoUUID: videoDatabase.uuid,
resolution
}
if (payload.isNewVideo) Notifier.Instance.notifyOnNewVideo(videoDatabase)
if (videoPublished) Notifier.Instance.notifyOnVideoPublishedAfterTranscoding(videoDatabase)
- await createHlsJobIfEnabled(Object.assign({}, payload, { resolution: videoDatabase.getOriginalFile().resolution }))
+ const hlsPayload = Object.assign({}, payload, { resolution: videoDatabase.getOriginalFile().resolution })
+ await createHlsJobIfEnabled(hlsPayload)
}
// ---------------------------------------------------------------------------
export {
processVideoTranscoding,
- publishVideoIfNeeded
+ publishNewResolutionIfNeeded
}
// ---------------------------------------------------------------------------
-function createHlsJobIfEnabled (payload?: VideoTranscodingPayload) {
+function createHlsJobIfEnabled (payload?: { videoUUID: string, resolution: number, isPortraitMode?: boolean }) {
// Generate HLS playlist?
if (payload && CONFIG.TRANSCODING.HLS.ENABLED) {
const hlsTranscodingPayload = {
+ type: 'hls' as 'hls',
videoUUID: payload.videoUUID,
resolution: payload.resolution,
- isPortraitMode: payload.isPortraitMode,
-
- generateHlsPlaylist: true
+ isPortraitMode: payload.isPortraitMode
}
return JobQueue.Instance.createJob({ type: 'video-transcoding', payload: hlsTranscodingPayload })
import { VideoFileModel } from '../models/video/video-file'
import { generateImageFromVideoFile } from '../helpers/ffmpeg-utils'
import { CONFIG } from '../initializers/config'
-import { PREVIEWS_SIZE, THUMBNAILS_SIZE } from '../initializers/constants'
+import { PREVIEWS_SIZE, THUMBNAILS_SIZE, ASSETS_PATH } from '../initializers/constants'
import { VideoModel } from '../models/video/video'
import { ThumbnailModel } from '../models/video/thumbnail'
import { ThumbnailType } from '../../shared/models/videos/thumbnail.type'
function generateVideoMiniature (video: VideoModel, videoFile: VideoFileModel, type: ThumbnailType) {
const input = video.getVideoFilePath(videoFile)
- const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type)
- const thumbnailCreator = () => generateImageFromVideoFile(input, basePath, filename, { height, width })
+ const { filename, basePath, height, width, existingThumbnail, outputPath } = buildMetadataFromVideo(video, type)
+ const thumbnailCreator = videoFile.isAudio()
+ ? () => processImage(ASSETS_PATH.DEFAULT_AUDIO_BACKGROUND, outputPath, { width, height }, true)
+ : () => generateImageFromVideoFile(input, basePath, filename, { height, width })
return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail })
}
import { createWatchLaterPlaylist } from './video-playlist'
import { sequelizeTypescript } from '../initializers/database'
-async function createUserAccountAndChannelAndPlaylist (userToCreate: UserModel, validateUser = true) {
+type ChannelNames = { name: string, displayName: string }
+async function createUserAccountAndChannelAndPlaylist (userToCreate: UserModel, channelNames?: ChannelNames, validateUser = true) {
const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => {
const userOptions = {
transaction: t,
const accountCreated = await createLocalAccountWithoutKeys(userCreated.username, userCreated.id, null, t)
userCreated.Account = accountCreated
- let channelName = userCreated.username + '_channel'
-
- // Conflict, generate uuid instead
- const actor = await ActorModel.loadLocalByName(channelName)
- if (actor) channelName = uuidv4()
-
- const videoChannelDisplayName = `Main ${userCreated.username} channel`
- const videoChannelInfo = {
- name: channelName,
- displayName: videoChannelDisplayName
- }
- const videoChannel = await createVideoChannel(videoChannelInfo, accountCreated, t)
+ const channelAttributes = await buildChannelAttributes(userCreated, channelNames)
+ const videoChannel = await createVideoChannel(channelAttributes, accountCreated, t)
const videoPlaylist = await createWatchLaterPlaylist(accountCreated, t)
return UserNotificationSettingModel.create(values, { transaction: t })
}
+
+async function buildChannelAttributes (user: UserModel, channelNames?: ChannelNames) {
+ if (channelNames) return channelNames
+
+ let channelName = user.username + '_channel'
+
+ // Conflict, generate uuid instead
+ const actor = await ActorModel.loadLocalByName(channelName)
+ if (actor) channelName = uuidv4()
+
+ const videoChannelDisplayName = `Main ${user.username} channel`
+
+ return {
+ name: channelName,
+ displayName: videoChannelDisplayName
+ }
+}
import { VideoChannelCreate } from '../../shared/models'
import { AccountModel } from '../models/account/account'
import { VideoChannelModel } from '../models/video/video-channel'
-import { buildActorInstance, getVideoChannelActivityPubUrl } from './activitypub'
+import { buildActorInstance, federateVideoIfNeeded, getVideoChannelActivityPubUrl } from './activitypub'
+import { VideoModel } from '../models/video/video'
async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountModel, t: Sequelize.Transaction) {
const uuid = uuidv4()
return videoChannelCreated
}
+async function federateAllVideosOfChannel (videoChannel: VideoChannelModel) {
+ const videoIds = await VideoModel.getAllIdsFromChannel(videoChannel)
+
+ for (const videoId of videoIds) {
+ const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoId)
+
+ await federateVideoIfNeeded(video, false)
+ }
+}
+
// ---------------------------------------------------------------------------
export {
- createVideoChannel
+ createVideoChannel,
+ federateAllVideosOfChannel
}
import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSERVER } from '../initializers/constants'
import { join } from 'path'
-import { getVideoFileFPS, transcode } from '../helpers/ffmpeg-utils'
+import { canDoQuickTranscode, getVideoFileFPS, transcode, TranscodeOptions, TranscodeOptionsType } from '../helpers/ffmpeg-utils'
import { ensureDir, move, remove, stat } from 'fs-extra'
import { logger } from '../helpers/logger'
import { VideoResolution } from '../../shared/models/videos'
import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type'
import { CONFIG } from '../initializers/config'
+/**
+ * Optimize the original video file and replace it. The resolution is not changed.
+ */
async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFileModel) {
const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
+ const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
const newExtname = '.mp4'
const inputVideoFile = inputVideoFileArg ? inputVideoFileArg : video.getOriginalFile()
const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile))
- const videoTranscodedPath = join(videosDirectory, video.id + '-transcoded' + newExtname)
+ const videoTranscodedPath = join(transcodeDirectory, video.id + '-transcoded' + newExtname)
- const transcodeOptions = {
+ const transcodeType: TranscodeOptionsType = await canDoQuickTranscode(videoInputPath)
+ ? 'quick-transcode'
+ : 'video'
+
+ const transcodeOptions: TranscodeOptions = {
+ type: transcodeType as any, // FIXME: typing issue
inputPath: videoInputPath,
outputPath: videoTranscodedPath,
resolution: inputVideoFile.resolution
await remove(videoInputPath)
// Important to do this before getVideoFilename() to take in account the new file extension
- inputVideoFile.set('extname', newExtname)
+ inputVideoFile.extname = newExtname
const videoOutputPath = video.getVideoFilePath(inputVideoFile)
- await move(videoTranscodedPath, videoOutputPath)
- const stats = await stat(videoOutputPath)
- const fps = await getVideoFileFPS(videoOutputPath)
- inputVideoFile.set('size', stats.size)
- inputVideoFile.set('fps', fps)
-
- await video.createTorrentAndSetInfoHash(inputVideoFile)
- await inputVideoFile.save()
+ await onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath)
} catch (err) {
// Auto destruction...
video.destroy().catch(err => logger.error('Cannot destruct video after transcoding failure.', { err }))
}
}
+/**
+ * Transcode the original video file to a lower resolution.
+ */
async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoResolution, isPortrait: boolean) {
const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
+ const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
const extname = '.mp4'
// We are sure it's x264 in mp4 because optimizeOriginalVideofile was already executed
videoId: video.id
})
const videoOutputPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename(newVideoFile))
+ const videoTranscodedPath = join(transcodeDirectory, video.getVideoFilename(newVideoFile))
const transcodeOptions = {
+ type: 'video' as 'video',
inputPath: videoInputPath,
- outputPath: videoOutputPath,
+ outputPath: videoTranscodedPath,
resolution,
isPortraitMode: isPortrait
}
await transcode(transcodeOptions)
- const stats = await stat(videoOutputPath)
- const fps = await getVideoFileFPS(videoOutputPath)
+ return onVideoFileTranscoding(video, newVideoFile, videoTranscodedPath, videoOutputPath)
+}
+
+async function mergeAudioVideofile (video: VideoModel, resolution: VideoResolution) {
+ const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
+ const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
+ const newExtname = '.mp4'
+
+ const inputVideoFile = video.getOriginalFile()
- newVideoFile.set('size', stats.size)
- newVideoFile.set('fps', fps)
+ const audioInputPath = join(videosDirectory, video.getVideoFilename(video.getOriginalFile()))
+ const videoTranscodedPath = join(transcodeDirectory, video.id + '-transcoded' + newExtname)
- await video.createTorrentAndSetInfoHash(newVideoFile)
+ const transcodeOptions = {
+ type: 'merge-audio' as 'merge-audio',
+ inputPath: video.getPreview().getPath(),
+ outputPath: videoTranscodedPath,
+ audioPath: audioInputPath,
+ resolution
+ }
+
+ await transcode(transcodeOptions)
- await newVideoFile.save()
+ await remove(audioInputPath)
- video.VideoFiles.push(newVideoFile)
+ // Important to do this before getVideoFilename() to take in account the new file extension
+ inputVideoFile.extname = newExtname
+
+ const videoOutputPath = video.getVideoFilePath(inputVideoFile)
+
+ return onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath)
}
async function generateHlsPlaylist (video: VideoModel, resolution: VideoResolution, isPortraitMode: boolean) {
const outputPath = join(baseHlsDirectory, VideoStreamingPlaylistModel.getHlsPlaylistFilename(resolution))
const transcodeOptions = {
+ type: 'hls' as 'hls',
inputPath: videoInputPath,
outputPath,
resolution,
})
}
+// ---------------------------------------------------------------------------
+
export {
generateHlsPlaylist,
optimizeVideofile,
- transcodeOriginalVideofile
+ transcodeOriginalVideofile,
+ mergeAudioVideofile
+}
+
+// ---------------------------------------------------------------------------
+
+async function onVideoFileTranscoding (video: VideoModel, videoFile: VideoFileModel, transcodingPath: string, outputPath: string) {
+ const stats = await stat(transcodingPath)
+ const fps = await getVideoFileFPS(transcodingPath)
+
+ await move(transcodingPath, outputPath)
+
+ videoFile.set('size', stats.size)
+ videoFile.set('fps', fps)
+
+ await video.createTorrentAndSetInfoHash(videoFile)
+
+ const updatedVideoFile = await videoFile.save()
+
+ // Add it if this is a new created file
+ if (video.VideoFiles.some(f => f.id === videoFile.id) === false) {
+ video.VideoFiles.push(updatedVideoFile)
+ }
+
+ return video
}
import * as express from 'express'
import { param, query } from 'express-validator/check'
-import { doesAccountIdExist, isAccountNameValid, doesAccountNameWithHostExist } from '../../helpers/custom-validators/accounts'
-import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
+import { doesAccountIdExist, doesAccountNameWithHostExist } from '../../helpers/custom-validators/accounts'
+import { isIdOrUUIDValid, isIdValid } from '../../helpers/custom-validators/misc'
import { logger } from '../../helpers/logger'
import { areValidationErrors } from './utils'
import { isValidRSSFeed } from '../../helpers/custom-validators/feeds'
import { doesVideoChannelIdExist, doesVideoChannelNameWithHostExist } from '../../helpers/custom-validators/video-channels'
import { doesVideoExist } from '../../helpers/custom-validators/videos'
-import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor'
const videoFeedsValidator = [
param('format').optional().custom(isValidRSSFeed).withMessage('Should have a valid format (rss, atom, json)'),
query('format').optional().custom(isValidRSSFeed).withMessage('Should have a valid format (rss, atom, json)'),
- query('accountId').optional().custom(isIdOrUUIDValid),
- query('accountName').optional().custom(isAccountNameValid),
- query('videoChannelId').optional().custom(isIdOrUUIDValid),
- query('videoChannelName').optional().custom(isActorPreferredUsernameValid),
+ query('accountId').optional().custom(isIdValid),
+ query('accountName').optional(),
+ query('videoChannelId').optional().custom(isIdValid),
+ query('videoChannelName').optional(),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking feeds parameters', { parameters: req.query })
import { UserModel } from '../../models/account/user'
import { areValidationErrors } from './utils'
import { ActorModel } from '../../models/activitypub/actor'
+import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor'
+import { isVideoChannelNameValid } from '../../helpers/custom-validators/video-channels'
+import { UserCreate } from '../../../shared/models/users'
+import { UserRegister } from '../../../shared/models/users/user-register.model'
const usersAddValidator = [
body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'),
body('username').custom(isUserUsernameValid).withMessage('Should have a valid username'),
body('password').custom(isUserPasswordValid).withMessage('Should have a valid password'),
body('email').isEmail().withMessage('Should have a valid email'),
+ body('channel.name').optional().custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'),
+ body('channel.displayName').optional().custom(isVideoChannelNameValid).withMessage('Should have a valid display name'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking usersRegister parameters', { parameters: omit(req.body, 'password') })
if (areValidationErrors(req, res)) return
if (!await checkUserNameOrEmailDoesNotAlreadyExist(req.body.username, req.body.email, res)) return
+ const body: UserRegister = req.body
+ if (body.channel) {
+ if (!body.channel.name || !body.channel.displayName) {
+ return res.status(400)
+ .send({ error: 'Channel is optional but if you specify it, channel.name and channel.displayName are required.' })
+ .end()
+ }
+
+ if (body.channel.name === body.username) {
+ return res.status(400)
+ .send({ error: 'Channel name cannot be the same than user username.' })
+ .end()
+ }
+
+ const existing = await ActorModel.loadLocalByName(body.channel.name)
+ if (existing) {
+ return res.status(409)
+ .send({ error: `Channel with name ${body.channel.name} already exists.` })
+ .end()
+ }
+ }
+
return next()
}
]
import { areValidationErrors } from '../utils'
import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor'
import { ActorModel } from '../../../models/activitypub/actor'
+import { isBooleanValid } from '../../../helpers/custom-validators/misc'
const videoChannelsAddValidator = [
body('name').custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'),
const videoChannelsUpdateValidator = [
param('nameWithHost').exists().withMessage('Should have an video channel name with host'),
- body('displayName').optional().custom(isVideoChannelNameValid).withMessage('Should have a valid display name'),
- body('description').optional().custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'),
- body('support').optional().custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'),
+ body('displayName')
+ .optional()
+ .custom(isVideoChannelNameValid).withMessage('Should have a valid display name'),
+ body('description')
+ .optional()
+ .custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'),
+ body('support')
+ .optional()
+ .custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'),
+ body('bulkVideosSupportUpdate')
+ .optional()
+ .custom(isBooleanValid).withMessage('Should have a valid bulkVideosSupportUpdate boolean field'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body })
import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model'
const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([
+ body('displayName')
+ .custom(isVideoPlaylistNameValid).withMessage('Should have a valid display name'),
+
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videoPlaylistsAddValidator parameters', { parameters: req.body })
param('playlistId')
.custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
+ body('displayName')
+ .optional()
+ .custom(isVideoPlaylistNameValid).withMessage('Should have a valid display name'),
+
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videoPlaylistsUpdateValidator parameters', { parameters: req.body })
const body: VideoPlaylistUpdate = req.body
- if (videoPlaylist.privacy !== VideoPlaylistPrivacy.PRIVATE && body.privacy === VideoPlaylistPrivacy.PRIVATE) {
- cleanUpReqFiles(req)
- return res.status(400)
- .json({ error: 'Cannot set "private" a video playlist that was not private.' })
- }
-
const newPrivacy = body.privacy || videoPlaylist.privacy
if (newPrivacy === VideoPlaylistPrivacy.PUBLIC &&
(
+ CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ')
),
- body('displayName')
- .custom(isVideoPlaylistNameValid).withMessage('Should have a valid display name'),
body('description')
.optional()
.customSanitizer(toValueOrNull)
if (areErrorsInScheduleUpdate(req, res)) return cleanUpReqFiles(req)
if (!await doesVideoExist(req.params.id, res)) return cleanUpReqFiles(req)
- const video = res.locals.video
-
// Check if the user who did the request is able to update the video
const user = res.locals.oauth.token.User
if (!checkUserCanManageVideo(user, res.locals.video, UserRight.UPDATE_ANY_VIDEO, res)) return cleanUpReqFiles(req)
- if (video.privacy !== VideoPrivacy.PRIVATE && req.body.privacy === VideoPrivacy.PRIVATE) {
- cleanUpReqFiles(req)
- return res.status(409)
- .json({ error: 'Cannot set "private" a video that was not private.' })
- }
-
if (req.body.channelId && !await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req)
return next()
attributes: [ 'id', 'name' ],
include: [
{
- attributes: [ 'id', 'uuid', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
+ attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
model: ActorModel.unscoped(),
required: true,
where: whereActor,
return AccountModel.findByPk(id, { transaction })
}
- static loadByUUID (uuid: string) {
- const query = {
- include: [
- {
- model: ActorModel,
- required: true,
- where: {
- uuid
- }
- }
- ]
- }
-
- return AccountModel.findOne(query)
- }
-
static loadByNameWithHost (nameWithHost: string) {
const [ accountName, host ] = nameWithHost.split('@')
return {
id: this.id,
- uuid: actor.uuid,
name: actor.name,
displayName: this.getDisplayName(),
url: actor.url,
Column,
CreatedAt,
DataType,
- Default,
DefaultScope,
ForeignKey,
HasMany,
HasOne,
Is,
- IsUUID,
Model,
Scopes,
Table,
{
fields: [ 'avatarId' ]
},
- {
- fields: [ 'uuid' ],
- unique: true
- },
{
fields: [ 'followersUrl' ]
}
@Column(DataType.ENUM(...values(ACTIVITY_PUB_ACTOR_TYPES)))
type: ActivityPubActorType
- @AllowNull(false)
- @Default(DataType.UUIDV4)
- @IsUUID(4)
- @Column(DataType.UUID)
- uuid: string
-
@AllowNull(false)
@Is('ActorPreferredUsername', value => throwIfNotValid(value, isActorPreferredUsernameValid, 'actor preferred username'))
@Column
return {
id: this.id,
url: this.url,
- uuid: this.uuid,
name: this.preferredUsername,
host: this.getHost(),
hostRedundancyAllowed: this.getRedundancyAllowed(),
endpoints: {
sharedInbox: this.sharedInboxUrl
},
- uuid: this.uuid,
publicKey: {
id: this.getPublicKeyUrl(),
owner: this.url,
return WEBSERVER.URL + staticPath + this.filename
}
- removeThumbnail () {
+ getPath () {
const directory = ThumbnailModel.types[this.type].directory
- const thumbnailPath = join(directory, this.filename)
+ return join(directory, this.filename)
+ }
- return remove(thumbnailPath)
+ removeThumbnail () {
+ return remove(this.getPath())
}
}
attributes: [ 'name', 'description', 'id', 'actorId' ],
include: [
{
- attributes: [ 'uuid', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
+ attributes: [ 'preferredUsername', 'url', 'serverId', 'avatarId' ],
model: ActorModel.unscoped(),
required: true,
include: [
})
}
- static listByAccount (accountId: number) {
+ static listByAccount (options: {
+ accountId: number,
+ start: number,
+ count: number,
+ sort: string
+ }) {
const query = {
- order: getSort('createdAt'),
+ offset: options.start,
+ limit: options.count,
+ order: getSort(options.sort),
include: [
{
model: AccountModel,
where: {
- id: accountId
+ id: options.accountId
},
required: true
}
.findByPk(id)
}
- static loadByUUIDAndPopulateAccount (uuid: string) {
- const query = {
- include: [
- {
- model: ActorModel,
- required: true,
- where: {
- uuid
- }
- }
- ]
- }
-
- return VideoChannelModel
- .scope([ ScopeNames.WITH_ACCOUNT ])
- .findOne(query)
- }
-
static loadByUrlAndPopulateAccount (url: string) {
const query = {
include: [
return {
id: this.id,
- uuid: actor.uuid,
name: actor.name,
displayName: this.getDisplayName(),
url: actor.url,
import { VideoRedundancyModel } from '../redundancy/video-redundancy'
import { VideoStreamingPlaylistModel } from './video-streaming-playlist'
import { FindOptions, QueryTypes, Transaction } from 'sequelize'
+import { MIMETYPES } from '../../initializers/constants'
@Table({
tableName: 'videoFile',
}))
}
+ isAudio () {
+ return !!MIMETYPES.AUDIO.EXT_MIMETYPE[this.extname]
+ }
+
hasSameUniqueKeysThan (other: VideoFileModel) {
return this.fps === other.fps &&
this.resolution === other.resolution &&
.then(results => results.length === 1)
}
+ static bulkUpdateSupportField (videoChannel: VideoChannelModel, t: Transaction) {
+ const options = {
+ where: {
+ channelId: videoChannel.id
+ },
+ transaction: t
+ }
+
+ return VideoModel.update({ support: videoChannel.support }, options)
+ }
+
+ static getAllIdsFromChannel (videoChannel: VideoChannelModel) {
+ const query = {
+ attributes: [ 'id' ],
+ where: {
+ channelId: videoChannel.id
+ }
+ }
+
+ return VideoModel.findAll(query)
+ .then(videos => videos.map(v => v.id))
+ }
+
// threshold corresponds to how many video the field should have to be returned
static async getRandomFieldSamples (field: 'category' | 'channelId', threshold: number, count: number) {
const serverActor = await getServerActor()
import * as chai from 'chai'
import 'mocha'
import {
+ cleanupTests,
doubleFollow,
flushAndRunMultipleServers,
flushTests,
const object = res.body
expect(object.type).to.equal('Person')
- expect(object.id).to.equal('http://localhost:9001/accounts/root')
+ expect(object.id).to.equal('http://localhost:' + servers[0].port + '/accounts/root')
expect(object.name).to.equal('root')
expect(object.preferredUsername).to.equal('root')
})
const object = res.body
expect(object.type).to.equal('Video')
- expect(object.id).to.equal('http://localhost:9001/videos/watch/' + videoUUID)
+ expect(object.id).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + videoUUID)
expect(object.name).to.equal('video')
})
it('Should redirect to the origin video object', async function () {
const res = await makeActivityPubGetRequest(servers[1].url, '/videos/watch/' + videoUUID, 302)
- expect(res.header.location).to.equal('http://localhost:9001/videos/watch/' + videoUUID)
+ expect(res.header.location).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + videoUUID)
})
- after(function () {
- killallServers(servers)
+ after(async function () {
+ await cleanupTests(servers)
})
})
import 'mocha'
import {
+ cleanupTests,
closeAllSequelize,
createUser,
doubleFollow,
const badVideoUUID = res.body.video.uuid
await uploadVideo(servers[0].url, userAccessToken, { name: 'video user' })
- await setActorField(1, 'http://localhost:9001/accounts/user1', 'url', 'http://localhost:9002/accounts/user1')
- await setVideoField(1, badVideoUUID, 'url', 'http://localhost:9003/videos/watch/' + badVideoUUID)
+ {
+ const to = 'http://localhost:' + servers[0].port + '/accounts/user1'
+ const value = 'http://localhost:' + servers[1].port + '/accounts/user1'
+ await setActorField(servers[0].internalServerNumber, to, 'url', value)
+ }
+
+ {
+ const value = 'http://localhost:' + servers[2].port + '/videos/watch/' + badVideoUUID
+ await setVideoField(servers[0].internalServerNumber, badVideoUUID, 'url', value)
+ }
})
it('Should add only the video with a valid actor URL', async function () {
})
after(async function () {
- killallServers(servers)
+ this.timeout(10000)
+
+ await cleanupTests(servers)
await closeAllSequelize(servers)
})
import 'mocha'
import {
+ cleanupTests, closeAllSequelize,
createVideoPlaylist,
doubleFollow,
flushAndRunMultipleServers,
generateUserAccessToken,
getVideo,
getVideoPlaylist,
- killallServers, rateVideo,
+ killallServers,
reRunServer,
ServerInfo,
setAccessTokensToServers,
}
{
- const a1 = await generateUserAccessToken(servers[1], 'user1')
- await uploadVideo(servers[1].url, a1, { name: 'video4' })
+ const a1 = await generateUserAccessToken(servers[ 1 ], 'user1')
+ await uploadVideo(servers[ 1 ].url, a1, { name: 'video4' })
- const a2 = await generateUserAccessToken(servers[1], 'user2')
- await uploadVideo(servers[1].url, a2, { name: 'video5' })
+ const a2 = await generateUserAccessToken(servers[ 1 ], 'user2')
+ await uploadVideo(servers[ 1 ].url, a2, { name: 'video5' })
}
{
- const playlistAttrs = { displayName: 'playlist1', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].videoChannel.id }
- const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs })
+ const playlistAttrs = { displayName: 'playlist1', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[ 1 ].videoChannel.id }
+ const res = await createVideoPlaylist({ url: servers[ 1 ].url, token: servers[ 1 ].accessToken, playlistAttrs })
playlistUUID1 = res.body.videoPlaylist.uuid
}
{
- const playlistAttrs = { displayName: 'playlist2', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].videoChannel.id }
- const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs })
+ const playlistAttrs = { displayName: 'playlist2', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[ 1 ].videoChannel.id }
+ const res = await createVideoPlaylist({ url: servers[ 1 ].url, token: servers[ 1 ].accessToken, playlistAttrs })
playlistUUID2 = res.body.videoPlaylist.uuid
}
- await doubleFollow(servers[0], servers[1])
+ await doubleFollow(servers[ 0 ], servers[ 1 ])
})
describe('Videos refresher', function () {
await wait(10000)
// Change UUID so the remote server returns a 404
- await setVideoField(2, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f')
+ await setVideoField(servers[ 1 ].internalServerNumber, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f')
await getVideo(servers[ 0 ].url, videoUUID1)
await getVideo(servers[ 0 ].url, videoUUID2)
killallServers([ servers[ 1 ] ])
- await setVideoField(2, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e')
+ await setVideoField(servers[ 1 ].internalServerNumber, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e')
// Video will need a refresh
await wait(10000)
await wait(10000)
// Change actor name so the remote server returns a 404
- await setActorField(2, 'http://localhost:9002/accounts/user2', 'preferredUsername', 'toto')
+ const to = 'http://localhost:' + servers[ 1 ].port + '/accounts/user2'
+ await setActorField(servers[ 1 ].internalServerNumber, to, 'preferredUsername', 'toto')
- await getAccount(servers[ 0 ].url, 'user1@localhost:9002')
- await getAccount(servers[ 0 ].url, 'user2@localhost:9002')
+ await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port)
+ await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port)
await waitJobs(servers)
- await getAccount(servers[ 0 ].url, 'user1@localhost:9002', 200)
- await getAccount(servers[ 0 ].url, 'user2@localhost:9002', 404)
+ await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port, 200)
+ await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port, 404)
})
})
await wait(10000)
// Change UUID so the remote server returns a 404
- await setPlaylistField(2, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e')
+ await setPlaylistField(servers[ 1 ].internalServerNumber, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e')
await getVideoPlaylist(servers[ 0 ].url, playlistUUID1)
await getVideoPlaylist(servers[ 0 ].url, playlistUUID2)
})
})
- after(function () {
- killallServers(servers)
+ after(async function () {
+ this.timeout(10000)
+
+ await cleanupTests(servers)
+
+ await closeAllSequelize(servers)
})
})
import 'mocha'
import {
+ cleanupTests,
closeAllSequelize,
flushAndRunMultipleServers,
- flushTests,
killallServers,
ServerInfo,
setActorField
const expect = chai.expect
-function setKeysOfServer2 (serverNumber: number, publicKey: string, privateKey: string) {
+function setKeysOfServer (onServer: ServerInfo, ofServer: ServerInfo, publicKey: string, privateKey: string) {
return Promise.all([
- setActorField(serverNumber, 'http://localhost:9002/accounts/peertube', 'publicKey', publicKey),
- setActorField(serverNumber, 'http://localhost:9002/accounts/peertube', 'privateKey', privateKey)
+ setActorField(onServer.internalServerNumber, 'http://localhost:' + ofServer.port + '/accounts/peertube', 'publicKey', publicKey),
+ setActorField(onServer.internalServerNumber, 'http://localhost:' + ofServer.port + '/accounts/peertube', 'privateKey', privateKey)
])
}
-function setKeysOfServer3 (serverNumber: number, publicKey: string, privateKey: string) {
- return Promise.all([
- setActorField(serverNumber, 'http://localhost:9003/accounts/peertube', 'publicKey', publicKey),
- setActorField(serverNumber, 'http://localhost:9003/accounts/peertube', 'privateKey', privateKey)
- ])
+function getAnnounceWithoutContext (server2: ServerInfo) {
+ const json = require('./json/peertube/announce-without-context.json')
+ const result: typeof json = {}
+
+ for (const key of Object.keys(json)) {
+ if (Array.isArray(json[key])) {
+ result[key] = json[key].map(v => v.replace(':9002', `:${server2.port}`))
+ } else {
+ result[ key ] = json[ key ].replace(':9002', `:${server2.port}`)
+ }
+ }
+
+ return result
}
describe('Test ActivityPub security', function () {
const keys = require('./json/peertube/keys.json')
const invalidKeys = require('./json/peertube/invalid-keys.json')
- const baseHttpSignature = {
+ const baseHttpSignature = () => ({
algorithm: HTTP_SIGNATURE.ALGORITHM,
authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME,
- keyId: 'acct:peertube@localhost:9002',
+ keyId: 'acct:peertube@localhost:' + servers[1].port,
key: keys.privateKey,
headers: HTTP_SIGNATURE.HEADERS_TO_SIGN
- }
+ })
// ---------------------------------------------------------------
url = servers[0].url + '/inbox'
- await setKeysOfServer2(1, keys.publicKey, keys.privateKey)
+ await setKeysOfServer(servers[0], servers[1], keys.publicKey, keys.privateKey)
- const to = { url: 'http://localhost:9001/accounts/peertube' }
- const by = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey }
+ const to = { url: 'http://localhost:' + servers[0].port + '/accounts/peertube' }
+ const by = { url: 'http://localhost:' + servers[1].port + '/accounts/peertube', privateKey: keys.privateKey }
await makeFollowRequest(to, by)
})
describe('When checking HTTP signature', function () {
it('Should fail with an invalid digest', async function () {
- const body = activityPubContextify(require('./json/peertube/announce-without-context.json'))
+ const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
const headers = {
Digest: buildDigest({ hello: 'coucou' })
}
- const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers)
+ const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers)
expect(response.statusCode).to.equal(403)
})
it('Should fail with an invalid date', async function () {
- const body = activityPubContextify(require('./json/peertube/announce-without-context.json'))
+ const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
const headers = buildGlobalHeaders(body)
headers['date'] = 'Wed, 21 Oct 2015 07:28:00 GMT'
- const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers)
+ const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers)
expect(response.statusCode).to.equal(403)
})
it('Should fail with bad keys', async function () {
- await setKeysOfServer2(1, invalidKeys.publicKey, invalidKeys.privateKey)
- await setKeysOfServer2(2, invalidKeys.publicKey, invalidKeys.privateKey)
+ await setKeysOfServer(servers[0], servers[1], invalidKeys.publicKey, invalidKeys.privateKey)
+ await setKeysOfServer(servers[1], servers[1], invalidKeys.publicKey, invalidKeys.privateKey)
- const body = activityPubContextify(require('./json/peertube/announce-without-context.json'))
+ const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
const headers = buildGlobalHeaders(body)
- const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers)
+ const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers)
expect(response.statusCode).to.equal(403)
})
it('Should succeed with a valid HTTP signature', async function () {
- await setKeysOfServer2(1, keys.publicKey, keys.privateKey)
- await setKeysOfServer2(2, keys.publicKey, keys.privateKey)
+ await setKeysOfServer(servers[0], servers[1], keys.publicKey, keys.privateKey)
+ await setKeysOfServer(servers[1], servers[1], keys.publicKey, keys.privateKey)
- const body = activityPubContextify(require('./json/peertube/announce-without-context.json'))
+ const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
const headers = buildGlobalHeaders(body)
- const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers)
+ const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers)
expect(response.statusCode).to.equal(204)
})
describe('When checking Linked Data Signature', function () {
before(async () => {
- await setKeysOfServer3(3, keys.publicKey, keys.privateKey)
+ await setKeysOfServer(servers[2], servers[2], keys.publicKey, keys.privateKey)
- const to = { url: 'http://localhost:9001/accounts/peertube' }
- const by = { url: 'http://localhost:9003/accounts/peertube', privateKey: keys.privateKey }
+ const to = { url: 'http://localhost:' + servers[0].port + '/accounts/peertube' }
+ const by = { url: 'http://localhost:' + servers[2].port + '/accounts/peertube', privateKey: keys.privateKey }
await makeFollowRequest(to, by)
})
it('Should fail with bad keys', async function () {
this.timeout(10000)
- await setKeysOfServer3(1, invalidKeys.publicKey, invalidKeys.privateKey)
- await setKeysOfServer3(3, invalidKeys.publicKey, invalidKeys.privateKey)
+ await setKeysOfServer(servers[0], servers[2], invalidKeys.publicKey, invalidKeys.privateKey)
+ await setKeysOfServer(servers[2], servers[2], invalidKeys.publicKey, invalidKeys.privateKey)
- const body = require('./json/peertube/announce-without-context.json')
- body.actor = 'http://localhost:9003/accounts/peertube'
+ const body = getAnnounceWithoutContext(servers[1])
+ body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube'
- const signer: any = { privateKey: invalidKeys.privateKey, url: 'http://localhost:9003/accounts/peertube' }
+ const signer: any = { privateKey: invalidKeys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' }
const signedBody = await buildSignedActivity(signer, body)
const headers = buildGlobalHeaders(signedBody)
- const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers)
+ const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers)
expect(response.statusCode).to.equal(403)
})
it('Should fail with an altered body', async function () {
this.timeout(10000)
- await setKeysOfServer3(1, keys.publicKey, keys.privateKey)
- await setKeysOfServer3(3, keys.publicKey, keys.privateKey)
+ await setKeysOfServer(servers[0], servers[2], keys.publicKey, keys.privateKey)
+ await setKeysOfServer(servers[0], servers[2], keys.publicKey, keys.privateKey)
- const body = require('./json/peertube/announce-without-context.json')
- body.actor = 'http://localhost:9003/accounts/peertube'
+ const body = getAnnounceWithoutContext(servers[1])
+ body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube'
- const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:9003/accounts/peertube' }
+ const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' }
const signedBody = await buildSignedActivity(signer, body)
- signedBody.actor = 'http://localhost:9003/account/peertube'
+ signedBody.actor = 'http://localhost:' + servers[2].port + '/account/peertube'
const headers = buildGlobalHeaders(signedBody)
- const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers)
+ const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers)
expect(response.statusCode).to.equal(403)
})
it('Should succeed with a valid signature', async function () {
this.timeout(10000)
- const body = require('./json/peertube/announce-without-context.json')
- body.actor = 'http://localhost:9003/accounts/peertube'
+ const body = getAnnounceWithoutContext(servers[1])
+ body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube'
- const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:9003/accounts/peertube' }
+ const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' }
const signedBody = await buildSignedActivity(signer, body)
const headers = buildGlobalHeaders(signedBody)
- const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers)
+ const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers)
expect(response.statusCode).to.equal(204)
})
})
after(async function () {
- killallServers(servers)
+ this.timeout(10000)
+
+ await cleanupTests(servers)
await closeAllSequelize(servers)
})
transcoding: {
enabled: true,
allowAdditionalExtensions: true,
+ allowAudioFiles: true,
threads: 1,
resolutions: {
'240p': false,
import { UserRole, VideoImport, VideoImportState } from '../../../../shared'
import {
+ addVideoChannel,
blockUser,
cleanupTests,
createUser,
})
})
- describe('When register a new user', function () {
+ describe('When registering a new user', function () {
const registrationPath = path + '/register'
const baseCorrectParams = {
username: 'user3',
})
})
+ it('Should fail with a bad channel name', async function () {
+ const fields = immutableAssign(baseCorrectParams, { channel: { name: '[]azf', displayName: 'toto' } })
+
+ await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
+ })
+
+ it('Should fail with a bad channel display name', async function () {
+ const fields = immutableAssign(baseCorrectParams, { channel: { name: 'toto', displayName: '' } })
+
+ await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
+ })
+
+ it('Should fail with a channel name that is the same than user username', async function () {
+ const source = { username: 'super_user', channel: { name: 'super_user', displayName: 'display name' } }
+ const fields = immutableAssign(baseCorrectParams, source)
+
+ await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
+ })
+
+ it('Should fail with an existing channel', async function () {
+ const videoChannelAttributesArg = { name: 'existing_channel', displayName: 'hello', description: 'super description' }
+ await addVideoChannel(server.url, server.accessToken, videoChannelAttributesArg)
+
+ const fields = immutableAssign(baseCorrectParams, { channel: { name: 'existing_channel', displayName: 'toto' } })
+
+ await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields, statusCodeExpected: 409 })
+ })
+
it('Should succeed with the correct params', async function () {
+ const fields = immutableAssign(baseCorrectParams, { channel: { name: 'super_channel', displayName: 'toto' } })
+
await makePostBodyRequest({
url: server.url,
path: registrationPath,
token: server.accessToken,
- fields: baseCorrectParams,
+ fields: fields,
statusCodeExpected: 204
})
})
checkBadStartPagination
} from '../../../../shared/extra-utils/requests/check-api-params'
import { join } from 'path'
+import { VideoChannelUpdate } from '../../../../shared/models/videos'
const expect = chai.expect
})
describe('When listing account video channels', function () {
+ const accountChannelPath = '/api/v1/accounts/fake/video-channels'
+
+ it('Should fail with a bad start pagination', async function () {
+ await checkBadStartPagination(server.url, accountChannelPath, server.accessToken)
+ })
+
+ it('Should fail with a bad count pagination', async function () {
+ await checkBadCountPagination(server.url, accountChannelPath, server.accessToken)
+ })
+
+ it('Should fail with an incorrect sort', async function () {
+ await checkBadSortPagination(server.url, accountChannelPath, server.accessToken)
+ })
+
it('Should fail with a unknown account', async function () {
- await getAccountVideoChannelsList(server.url, 'unknown', 404)
+ await getAccountVideoChannelsList({ url: server.url, accountName: 'unknown', specialStatus: 404 })
+ })
+
+ it('Should succeed with the correct parameters', async function () {
+ await makeGetRequest({
+ url: server.url,
+ path: accountChannelPath,
+ statusCodeExpected: 200
+ })
})
})
})
describe('When updating a video channel', function () {
- const baseCorrectParams = {
+ const baseCorrectParams: VideoChannelUpdate = {
displayName: 'hello',
- description: 'super description'
+ description: 'super description',
+ support: 'toto',
+ bulkVideosSupportUpdate: false
}
let path: string
await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
})
+ it('Should fail with a bad bulkVideosSupportUpdate field', async function () {
+ const fields = immutableAssign(baseCorrectParams, { bulkVideosSupportUpdate: 'super' })
+ await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
+ })
+
it('Should succeed with the correct parameters', async function () {
await makePutBodyRequest({
url: server.url,
const params = getBase({ displayName: undefined })
await createVideoPlaylist(params)
- await updateVideoPlaylist(getUpdate(params, playlistUUID))
})
it('Should fail with an incorrect display name', async function () {
))
})
- it('Should fail to update to private a public/unlisted playlist', async function () {
- const params = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC }, { expectedStatus: 200 })
-
- const res = await createVideoPlaylist(params)
- const playlist = res.body.videoPlaylist
-
- const paramsUpdate = getBase({ privacy: VideoPlaylistPrivacy.PRIVATE }, { expectedStatus: 400 })
-
- await updateVideoPlaylist(getUpdate(paramsUpdate, playlist.id))
- })
-
it('Should fail to update the watch later playlist', async function () {
await updateVideoPlaylist(getUpdate(
getBase({}, { expectedStatus: 400 }),
+++ /dev/null
-import './check-params'
-import './notifications'
-import './search'
+++ /dev/null
-import './server'
-import './users'
+++ /dev/null
-import './videos'
+++ /dev/null
-import './redundancy'
-import './activitypub'
// Order of the tests we want to execute
-import './index-1'
-import './index-2'
-import './index-3'
-import './index-4'
+import './activitypub'
+import './check-params'
+import './notifications'
+import './redundancy'
+import './search'
+import './server'
+import './users'
+import './videos'
-export * from './user-notifications'
+import './user-notifications'
before(async function () {
this.timeout(120000)
- await MockSmtpServer.Instance.collectEmails(emails)
+ const port = await MockSmtpServer.Instance.collectEmails(emails)
const overrideConfig = {
smtp: {
- hostname: 'localhost'
+ hostname: 'localhost',
+ port
}
}
servers = await flushAndRunMultipleServers(3, overrideConfig)
it('Should send a new video notification if the user follows the local video publisher', async function () {
this.timeout(15000)
- await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:9001')
+ await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:' + servers[0].port)
await waitJobs(servers)
const { name, uuid } = await uploadVideoByLocalAccount(servers)
it('Should send a new video notification from a remote account', async function () {
this.timeout(50000) // Server 2 has transcoding enabled
- await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:9002')
+ await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:' + servers[1].port)
await waitJobs(servers)
const { name, uuid } = await uploadVideoByRemoteAccount(servers)
const uuid = resVideo.body.video.uuid
await waitJobs(servers)
- const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, 'hello @user_1@localhost:9001 1')
+
+ const text1 = `hello @user_1@localhost:${servers[ 0 ].port} 1`
+ const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, text1)
const server2ThreadId = resThread.body.comment.id
await waitJobs(servers)
const server1ThreadId = resThread2.body.data[0].id
await checkCommentMention(baseParams, uuid, server1ThreadId, server1ThreadId, 'super root 2 name', 'presence')
- const text = '@user_1@localhost:9001 hello 2 @root@localhost:9001'
- await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, server2ThreadId, text)
+ const text2 = `@user_1@localhost:${servers[ 0 ].port} hello 2 @root@localhost:${servers[ 0 ].port}`
+ await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, server2ThreadId, text2)
await waitJobs(servers)
await waitJobs(servers)
- await checkNewInstanceFollower(baseParams, 'localhost:9003', 'presence')
+ await checkNewInstanceFollower(baseParams, 'localhost:' + servers[2].port, 'presence')
const userOverride = { socketNotifications: userNotifications, token: userAccessToken, check: { web: true, mail: false } }
- await checkNewInstanceFollower(immutableAssign(baseParams, userOverride), 'localhost:9003', 'absence')
+ await checkNewInstanceFollower(immutableAssign(baseParams, userOverride), 'localhost:' + servers[2].port, 'absence')
})
})
it('Should notify when a local channel is following one of our channel', async function () {
this.timeout(10000)
- await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:9001')
+ await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port)
await waitJobs(servers)
await checkNewActorFollow(baseParams, 'channel', 'root', 'super root name', myChannelName, 'presence')
- await removeUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:9001')
+ await removeUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port)
})
it('Should notify when a remote channel is following one of our channel', async function () {
this.timeout(10000)
- await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:9001')
+ await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port)
await waitJobs(servers)
await checkNewActorFollow(baseParams, 'channel', 'root', 'super root 2 name', myChannelName, 'presence')
- await removeUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:9001')
+ await removeUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port)
})
it('Should notify when a local account is following one of our channel', async function () {
this.timeout(10000)
- await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1@localhost:9001')
+ await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1@localhost:' + servers[0].port)
await waitJobs(servers)
it('Should notify when a remote account is following one of our channel', async function () {
this.timeout(10000)
- await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1@localhost:9001')
+ await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1@localhost:' + servers[0].port)
await waitJobs(servers)
autoBlacklistTestsCustomConfig.transcoding.enabled = true
await updateCustomConfig(servers[0].url, servers[0].accessToken, autoBlacklistTestsCustomConfig)
- await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:9001')
- await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:9001')
+ await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port)
+ await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port)
})
after(async () => {
await updateCustomConfig(servers[0].url, servers[0].accessToken, currentCustomConfig)
- await removeUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:9001')
- await removeUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:9001')
+ await removeUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port)
+ await removeUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port)
})
})
if (!videoUUID) videoUUID = video1Server2UUID
const webseeds = [
- 'http://localhost:9002/static/webseed/' + videoUUID
+ `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}`
]
for (const server of servers) {
if (!videoUUID) videoUUID = video1Server2UUID
const webseeds = [
- 'http://localhost:9001/static/redundancy/' + videoUUID,
- 'http://localhost:9002/static/webseed/' + videoUUID
+ `http://localhost:${servers[ 0 ].port}/static/redundancy/${videoUUID}`,
+ `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}`
]
for (const server of servers) {
}
}
- for (const directory of [ 'test1/redundancy', 'test2/videos' ]) {
+ const directories = [
+ 'test' + servers[0].internalServerNumber + '/redundancy',
+ 'test' + servers[1].internalServerNumber + '/videos'
+ ]
+
+ for (const directory of directories) {
const files = await readdir(join(root(), directory))
expect(files).to.have.length.at.least(4)
await checkSegmentHash(baseUrlPlaylist, baseUrlSegment, videoUUID, resolution, hlsPlaylist)
}
- for (const directory of [ 'test1/redundancy/hls', 'test2/streaming-playlists/hls' ]) {
+ const directories = [
+ 'test' + servers[0].internalServerNumber + '/redundancy/hls',
+ 'test' + servers[1].internalServerNumber + '/streaming-playlists/hls'
+ ]
+
+ for (const directory of directories) {
const files = await readdir(join(root(), directory, videoUUID))
expect(files).to.have.length.at.least(4)
const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt')
const follows: ActorFollow[] = res.body.data
- const server2 = follows.find(f => f.following.host === 'localhost:9002')
- const server3 = follows.find(f => f.following.host === 'localhost:9003')
+ const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`)
+ const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`)
expect(server3).to.not.be.undefined
expect(server3.following.hostRedundancyAllowed).to.be.false
const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt')
const follows: ActorFollow[] = res.body.data
- const server2 = follows.find(f => f.following.host === 'localhost:9002')
- const server3 = follows.find(f => f.following.host === 'localhost:9003')
+ const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`)
+ const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`)
expect(server3).to.not.be.undefined
expect(server3.following.hostRedundancyAllowed).to.be.false
await wait(10000)
try {
- await checkContains(servers, 'http%3A%2F%2Flocalhost%3A9001')
+ await checkContains(servers, 'http%3A%2F%2Flocalhost%3A' + servers[0].port)
} catch {
// Maybe a server deleted a redundancy in the scheduler
await wait(2000)
- await checkContains(servers, 'http%3A%2F%2Flocalhost%3A9001')
+ await checkContains(servers, 'http%3A%2F%2Flocalhost%3A' + servers[0].port)
}
})
await wait(15000)
- await checkNotContains([ servers[1], servers[2] ], 'http%3A%2F%2Flocalhost%3A9001')
+ await checkNotContains([ servers[1], servers[2] ], 'http%3A%2F%2Flocalhost%3A' + servers[0].port)
})
after(async function () {
import * as chai from 'chai'
import 'mocha'
import {
- addVideoChannel, cleanupTests,
+ addVideoChannel,
+ cleanupTests,
createUser,
deleteVideoChannel,
flushAndRunMultipleServers,
- flushTests,
- getVideoChannelsList, getVideoChannelVideos,
- killallServers,
+ getVideoChannelsList,
+ getVideoChannelVideos,
ServerInfo,
setAccessTokensToServers,
- updateMyUser, updateVideo,
+ updateMyUser,
+ updateVideo,
updateVideoChannel,
uploadVideo,
userLogin,
const expect = chai.expect
-describe('Test a ActivityPub video channels search', function () {
+describe('Test ActivityPub video channels search', function () {
let servers: ServerInfo[]
let userServer2Token: string
let videoServer2UUID: string
it('Should not find a remote video channel', async function () {
{
- const search = 'http://localhost:9002/video-channels/channel1_server3'
+ const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server3'
const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken)
expect(res.body.total).to.equal(0)
{
// Without token
- const search = 'http://localhost:9002/video-channels/channel1_server2'
+ const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2'
const res = await searchVideoChannel(servers[0].url, search)
expect(res.body.total).to.equal(0)
it('Should search a local video channel', async function () {
const searches = [
- 'http://localhost:9001/video-channels/channel1_server1',
- 'channel1_server1@localhost:9001'
+ 'http://localhost:' + servers[ 0 ].port + '/video-channels/channel1_server1',
+ 'channel1_server1@localhost:' + servers[ 0 ].port
]
for (const search of searches) {
it('Should search a remote video channel with URL or handle', async function () {
const searches = [
- 'http://localhost:9002/video-channels/channel1_server2',
- 'channel1_server2@localhost:9002'
+ 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2',
+ 'channel1_server2@localhost:' + servers[ 1 ].port
]
for (const search of searches) {
await waitJobs(servers)
- const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:9002', 0, 5)
+ const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
})
it('Should list video channel videos of server 2 with token', async function () {
- const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:9002', 0, 5)
+ const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data[0].name).to.equal('video 1 server 2')
// Expire video channel
await wait(10000)
- const search = 'http://localhost:9002/video-channels/channel1_server2'
+ const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2'
const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
// Expire video channel
await wait(10000)
- const search = 'http://localhost:9002/video-channels/channel1_server2'
+ const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2'
await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
await waitJobs(servers)
- const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:9002', 0, 5, '-createdAt')
+ const videoChannelName = 'channel1_server2@localhost:' + servers[ 1 ].port
+ const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, videoChannelName, 0, 5, '-createdAt')
expect(res.body.total).to.equal(2)
expect(res.body.data[0].name).to.equal('video 2 server 2')
// Expire video
await wait(10000)
- const res = await searchVideoChannel(servers[0].url, 'http://localhost:9002/video-channels/channel1_server2', servers[0].accessToken)
+ const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2'
+ const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
})
import 'mocha'
import {
addVideoChannel,
+ cleanupTests,
flushAndRunMultipleServers,
- flushTests,
getVideosList,
- killallServers,
removeVideo,
+ searchVideo,
searchVideoWithToken,
ServerInfo,
setAccessTokensToServers,
updateVideo,
uploadVideo,
- wait,
- searchVideo, cleanupTests
+ wait
} from '../../../../shared/extra-utils'
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
import { Video, VideoPrivacy } from '../../../../shared/models/videos'
const expect = chai.expect
-describe('Test a ActivityPub videos search', function () {
+describe('Test ActivityPub videos search', function () {
let servers: ServerInfo[]
let videoServer1UUID: string
let videoServer2UUID: string
it('Should not find a remote video', async function () {
{
- const res = await searchVideoWithToken(servers[ 0 ].url, 'http://localhost:9002/videos/watch/43', servers[ 0 ].accessToken)
+ const search = 'http://localhost:' + servers[1].port + '/videos/watch/43'
+ const res = await searchVideoWithToken(servers[ 0 ].url, search, servers[ 0 ].accessToken)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.be.an('array')
{
// Without token
- const res = await searchVideo(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID)
+ const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID
+ const res = await searchVideo(servers[0].url, search)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.be.an('array')
})
it('Should search a local video', async function () {
- const res = await searchVideo(servers[0].url, 'http://localhost:9001/videos/watch/' + videoServer1UUID)
+ const search = 'http://localhost:' + servers[0].port + '/videos/watch/' + videoServer1UUID
+ const res = await searchVideo(servers[0].url, search)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.be.an('array')
})
it('Should search a remote video', async function () {
- const res = await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken)
+ const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID
+ const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.be.an('array')
await wait(10000)
// Will run refresh async
- await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken)
+ const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID
+ await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
// Wait refresh
await wait(5000)
- const res = await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken)
+ const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
await wait(10000)
// Will run refresh async
- await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken)
+ const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID
+ await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
// Wait refresh
await wait(5000)
- const res = await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken)
+ const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
})
import 'mocha'
import {
advancedVideosSearch,
- flushTests,
- killallServers,
+ cleanupTests,
flushAndRunServer,
+ immutableAssign,
searchVideo,
ServerInfo,
setAccessTokensToServers,
uploadVideo,
- wait,
- immutableAssign,
- cleanupTests
+ wait
} from '../../../../shared/extra-utils'
const expect = chai.expect
-describe('Test a videos search', function () {
+describe('Test videos search', function () {
let server: ServerInfo = null
let startDate: string
getAbout,
getConfig,
getCustomConfig,
- killallServers,
+ killallServers, parallelTests,
registerUser,
- reRunServer,
+ reRunServer, ServerInfo,
setAccessTokensToServers,
- updateCustomConfig
+ updateCustomConfig, uploadVideo
} from '../../../../shared/extra-utils'
import { ServerConfig } from '../../../../shared/models'
const expect = chai.expect
-function checkInitialConfig (data: CustomConfig) {
+function checkInitialConfig (server: ServerInfo, data: CustomConfig) {
expect(data.instance.name).to.equal('PeerTube')
expect(data.instance.shortDescription).to.equal(
'PeerTube, a federated (ActivityPub) video streaming platform using P2P (BitTorrent) directly in the web browser ' +
expect(data.signup.limit).to.equal(4)
expect(data.signup.requiresEmailVerification).to.be.false
- expect(data.admin.email).to.equal('admin1@example.com')
+ expect(data.admin.email).to.equal('admin' + server.internalServerNumber + '@example.com')
expect(data.contactForm.enabled).to.be.true
expect(data.user.videoQuota).to.equal(5242880)
expect(data.user.videoQuotaDaily).to.equal(-1)
expect(data.transcoding.enabled).to.be.false
expect(data.transcoding.allowAdditionalExtensions).to.be.false
+ expect(data.transcoding.allowAudioFiles).to.be.false
expect(data.transcoding.threads).to.equal(2)
expect(data.transcoding.resolutions['240p']).to.be.true
expect(data.transcoding.resolutions['360p']).to.be.true
expect(data.signup.limit).to.equal(5)
expect(data.signup.requiresEmailVerification).to.be.false
- expect(data.admin.email).to.equal('superadmin1@example.com')
+ // We override admin email in parallel tests, so skip this exception
+ if (parallelTests() === false) {
+ expect(data.admin.email).to.equal('superadmin1@example.com')
+ }
+
expect(data.contactForm.enabled).to.be.false
expect(data.user.videoQuota).to.equal(5242881)
expect(data.transcoding.enabled).to.be.true
expect(data.transcoding.threads).to.equal(1)
expect(data.transcoding.allowAdditionalExtensions).to.be.true
+ expect(data.transcoding.allowAudioFiles).to.be.true
expect(data.transcoding.resolutions['240p']).to.be.false
expect(data.transcoding.resolutions['360p']).to.be.true
expect(data.transcoding.resolutions['480p']).to.be.true
before(async function () {
this.timeout(30000)
+
server = await flushAndRunServer(1)
await setAccessTokensToServers([ server ])
})
expect(data.video.file.extensions).to.contain('.webm')
expect(data.video.file.extensions).to.contain('.ogv')
+ await uploadVideo(server.url, server.accessToken, { fixture: 'video_short.mkv' }, 400)
+ await uploadVideo(server.url, server.accessToken, { fixture: 'sample.ogg' }, 400)
+
expect(data.contactForm.enabled).to.be.true
})
const res = await getCustomConfig(server.url, server.accessToken)
const data = res.body as CustomConfig
- checkInitialConfig(data)
+ checkInitialConfig(server, data)
})
it('Should update the customized configuration', async function () {
transcoding: {
enabled: true,
allowAdditionalExtensions: true,
+ allowAudioFiles: true,
threads: 1,
resolutions: {
'240p': false,
expect(data.video.file.extensions).to.contain('.ogv')
expect(data.video.file.extensions).to.contain('.flv')
expect(data.video.file.extensions).to.contain('.mkv')
+ expect(data.video.file.extensions).to.contain('.mp3')
+ expect(data.video.file.extensions).to.contain('.ogg')
+ expect(data.video.file.extensions).to.contain('.flac')
+
+ await uploadVideo(server.url, server.accessToken, { fixture: 'video_short.mkv' }, 200)
+ await uploadVideo(server.url, server.accessToken, { fixture: 'sample.ogg' }, 200)
})
it('Should have the configuration updated after a restart', async function () {
const res = await getCustomConfig(server.url, server.accessToken)
const data = res.body
- checkInitialConfig(data)
+ checkInitialConfig(server, data)
})
after(async function () {
before(async function () {
this.timeout(30000)
- await MockSmtpServer.Instance.collectEmails(emails)
+ const port = await MockSmtpServer.Instance.collectEmails(emails)
const overrideConfig = {
smtp: {
- hostname: 'localhost'
+ hostname: 'localhost',
+ port
}
}
server = await flushAndRunServer(1, overrideConfig)
expect(email['from'][0]['address']).equal('test-admin@localhost')
expect(email['from'][0]['name']).equal('toto@example.com')
- expect(email['to'][0]['address']).equal('admin1@example.com')
+ expect(email['to'][0]['address']).equal('admin' + server.internalServerNumber + '@example.com')
expect(email['subject']).contains('Contact form')
expect(email['text']).contains('my super message')
})
askResetPassword,
askSendVerifyEmail,
blockUser,
- createUser, removeVideoFromBlacklist,
+ cleanupTests,
+ createUser,
+ flushAndRunServer,
+ removeVideoFromBlacklist,
reportVideoAbuse,
resetPassword,
- flushAndRunServer,
+ ServerInfo,
+ setAccessTokensToServers,
unblockUser,
uploadVideo,
userLogin,
- verifyEmail,
- flushTests,
- killallServers,
- ServerInfo,
- setAccessTokensToServers, cleanupTests
+ verifyEmail
} from '../../../../shared/extra-utils'
import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
username: 'user_1',
password: 'super_password'
}
+ let emailPort: number
before(async function () {
this.timeout(30000)
- await MockSmtpServer.Instance.collectEmails(emails)
+ emailPort = await MockSmtpServer.Instance.collectEmails(emails)
const overrideConfig = {
smtp: {
- hostname: 'localhost'
+ hostname: 'localhost',
+ port: emailPort
}
}
server = await flushAndRunServer(1, overrideConfig)
const email = emails[0]
- expect(email['from'][0]['name']).equal('localhost:9001')
+ expect(email['from'][0]['name']).equal('localhost:' + server.port)
expect(email['from'][0]['address']).equal('test-admin@localhost')
expect(email['to'][0]['address']).equal('user_1@example.com')
expect(email['subject']).contains('password')
const email = emails[1]
- expect(email['from'][0]['name']).equal('localhost:9001')
+ expect(email['from'][0]['name']).equal('localhost:' + server.port)
expect(email['from'][0]['address']).equal('test-admin@localhost')
- expect(email['to'][0]['address']).equal('admin1@example.com')
+ expect(email['to'][0]['address']).equal('admin' + server.internalServerNumber + '@example.com')
expect(email['subject']).contains('abuse')
expect(email['text']).contains(videoUUID)
})
const email = emails[2]
- expect(email['from'][0]['name']).equal('localhost:9001')
+ expect(email['from'][0]['name']).equal('localhost:' + server.port)
expect(email['from'][0]['address']).equal('test-admin@localhost')
expect(email['to'][0]['address']).equal('user_1@example.com')
expect(email['subject']).contains(' blocked')
const email = emails[3]
- expect(email['from'][0]['name']).equal('localhost:9001')
+ expect(email['from'][0]['name']).equal('localhost:' + server.port)
expect(email['from'][0]['address']).equal('test-admin@localhost')
expect(email['to'][0]['address']).equal('user_1@example.com')
expect(email['subject']).contains(' unblocked')
const email = emails[4]
- expect(email['from'][0]['name']).equal('localhost:9001')
+ expect(email['from'][0]['name']).equal('localhost:' + server.port)
expect(email['from'][0]['address']).equal('test-admin@localhost')
expect(email['to'][0]['address']).equal('user_1@example.com')
expect(email['subject']).contains(' blacklisted')
const email = emails[5]
- expect(email['from'][0]['name']).equal('localhost:9001')
+ expect(email['from'][0]['name']).equal('localhost:' + server.port)
expect(email['from'][0]['address']).equal('test-admin@localhost')
expect(email['to'][0]['address']).equal('user_1@example.com')
expect(email['subject']).contains(' unblacklisted')
const email = emails[6]
- expect(email['from'][0]['name']).equal('localhost:9001')
+ expect(email['from'][0]['name']).equal('localhost:' + server.port)
expect(email['from'][0]['address']).equal('test-admin@localhost')
expect(email['to'][0]['address']).equal('user_1@example.com')
expect(email['subject']).contains('Verify')
import * as chai from 'chai'
import 'mocha'
import {
+ cleanupTests,
doubleFollow,
+ flushAndRunMultipleServers,
getAccountVideos,
getVideo,
getVideoChannelVideos,
getVideoWithToken,
- flushAndRunMultipleServers,
- killallServers,
ServerInfo,
setAccessTokensToServers,
- uploadVideo, cleanupTests
+ uploadVideo
} from '../../../../shared/extra-utils'
import { unfollow } from '../../../../shared/extra-utils/server/follows'
import { userLogin } from '../../../../shared/extra-utils/users/login'
})
it('Should list local account videos', async function () {
- const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:9001', 0, 5)
+ const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:' + servers[0].port, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
})
it('Should list remote account videos', async function () {
- const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:9002', 0, 5)
+ const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:' + servers[1].port, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
})
it('Should list local channel videos', async function () {
- const res = await getVideoChannelVideos(servers[0].url, undefined, 'root_channel@localhost:9001', 0, 5)
+ const videoChannelName = 'root_channel@localhost:' + servers[0].port
+ const res = await getVideoChannelVideos(servers[0].url, undefined, videoChannelName, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
})
it('Should list remote channel videos', async function () {
- const res = await getVideoChannelVideos(servers[0].url, undefined, 'root_channel@localhost:9002', 0, 5)
+ const videoChannelName = 'root_channel@localhost:' + servers[1].port
+ const res = await getVideoChannelVideos(servers[0].url, undefined, videoChannelName, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
})
it('Should list local account videos', async function () {
- const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:9001', 0, 5)
+ const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:' + servers[0].port, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
})
it('Should list remote account videos', async function () {
- const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:9002', 0, 5)
+ const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:' + servers[1].port, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
})
it('Should list local channel videos', async function () {
- const res = await getVideoChannelVideos(servers[0].url, userAccessToken, 'root_channel@localhost:9001', 0, 5)
+ const videoChannelName = 'root_channel@localhost:' + servers[0].port
+ const res = await getVideoChannelVideos(servers[0].url, userAccessToken, videoChannelName, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
})
it('Should list remote channel videos', async function () {
- const res = await getVideoChannelVideos(servers[0].url, userAccessToken, 'root_channel@localhost:9002', 0, 5)
+ const videoChannelName = 'root_channel@localhost:' + servers[1].port
+ const res = await getVideoChannelVideos(servers[0].url, userAccessToken, videoChannelName, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
})
it('Should list local account videos', async function () {
- const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:9001', 0, 5)
+ const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:' + servers[0].port, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
})
it('Should not list remote account videos', async function () {
- const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:9002', 0, 5)
+ const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:' + servers[1].port, 0, 5)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
})
it('Should list local channel videos', async function () {
- const res = await getVideoChannelVideos(servers[0].url, undefined, 'root_channel@localhost:9001', 0, 5)
+ const videoChannelName = 'root_channel@localhost:' + servers[0].port
+ const res = await getVideoChannelVideos(servers[0].url, undefined, videoChannelName, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
})
it('Should not list remote channel videos', async function () {
- const res = await getVideoChannelVideos(servers[0].url, undefined, 'root_channel@localhost:9002', 0, 5)
+ const videoChannelName = 'root_channel@localhost:' + servers[1].port
+ const res = await getVideoChannelVideos(servers[0].url, undefined, videoChannelName, 0, 5)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
})
it('Should list local account videos', async function () {
- const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:9001', 0, 5)
+ const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:' + servers[0].port, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
})
it('Should list remote account videos', async function () {
- const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:9002', 0, 5)
+ const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:' + servers[1].port, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
})
it('Should list local channel videos', async function () {
- const res = await getVideoChannelVideos(servers[0].url, userAccessToken, 'root_channel@localhost:9001', 0, 5)
+ const videoChannelName = 'root_channel@localhost:' + servers[0].port
+ const res = await getVideoChannelVideos(servers[0].url, userAccessToken, videoChannelName, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
})
it('Should list remote channel videos', async function () {
- const res = await getVideoChannelVideos(servers[0].url, userAccessToken, 'root_channel@localhost:9002', 0, 5)
+ const videoChannelName = 'root_channel@localhost:' + servers[1].port
+ const res = await getVideoChannelVideos(servers[0].url, userAccessToken, videoChannelName, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
import * as chai from 'chai'
import 'mocha'
import {
- acceptFollower, cleanupTests,
+ acceptFollower,
+ cleanupTests,
flushAndRunMultipleServers,
- killallServers,
ServerInfo,
setAccessTokensToServers,
updateCustomSubConfig
follow,
getFollowersListPaginationAndSort,
getFollowingListPaginationAndSort,
- removeFollower,
- rejectFollower
+ rejectFollower,
+ removeFollower
} from '../../../../shared/extra-utils/server/follows'
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
import { ActorFollow } from '../../../../shared/models/actors'
const follow = res.body.data[0] as ActorFollow
expect(follow.state).to.equal(state)
- expect(follow.follower.url).to.equal('http://localhost:9001/accounts/peertube')
- expect(follow.following.url).to.equal('http://localhost:9002/accounts/peertube')
+ expect(follow.follower.url).to.equal('http://localhost:' + servers[0].port + '/accounts/peertube')
+ expect(follow.following.url).to.equal('http://localhost:' + servers[1].port + '/accounts/peertube')
}
{
const follow = res.body.data[0] as ActorFollow
expect(follow.state).to.equal(state)
- expect(follow.follower.url).to.equal('http://localhost:9001/accounts/peertube')
- expect(follow.following.url).to.equal('http://localhost:9002/accounts/peertube')
+ expect(follow.follower.url).to.equal('http://localhost:' + servers[0].port + '/accounts/peertube')
+ expect(follow.following.url).to.equal('http://localhost:' + servers[1].port + '/accounts/peertube')
}
}
})
it('Should accept a follower', async function () {
- await acceptFollower(servers[1].url, servers[1].accessToken, 'peertube@localhost:9001')
+ await acceptFollower(servers[1].url, servers[1].accessToken, 'peertube@localhost:' + servers[0].port)
await waitJobs(servers)
await checkServer1And2HasFollowers(servers)
expect(res.body.total).to.equal(1)
}
- await rejectFollower(servers[2].url, servers[2].accessToken, 'peertube@localhost:9001')
+ await rejectFollower(servers[2].url, servers[2].accessToken, 'peertube@localhost:' + servers[0].port)
await waitJobs(servers)
await checkServer1And2HasFollowers(servers)
import {
flushAndRunMultipleServers,
getVideosList,
- killallServers,
ServerInfo,
setAccessTokensToServers,
uploadVideo
res = await getFollowingListPaginationAndSort(servers[0].url, 1, 1, 'createdAt')
follows = follows.concat(res.body.data)
- const server2Follow = follows.find(f => f.following.host === 'localhost:9002')
- const server3Follow = follows.find(f => f.following.host === 'localhost:9003')
+ const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port)
+ const server3Follow = follows.find(f => f.following.host === 'localhost:' + servers[2].port)
expect(server2Follow).to.not.be.undefined
expect(server3Follow).to.not.be.undefined
it('Should search followings on server 1', async function () {
{
- const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', ':9002')
+ const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', ':' + servers[1].port)
const follows = res.body.data
expect(res.body.total).to.equal(1)
expect(follows.length).to.equal(1)
- expect(follows[ 0 ].following.host).to.equal('localhost:9002')
+ expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[1].port)
}
{
expect(res.body.total).to.equal(1)
expect(follows).to.be.an('array')
expect(follows.length).to.equal(1)
- expect(follows[0].follower.host).to.equal('localhost:9001')
+ expect(follows[0].follower.host).to.equal('localhost:' + servers[0].port)
}
})
it('Should search followers on server 2', async function () {
{
- const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', '9001')
+ const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', servers[0].port + '')
const follows = res.body.data
expect(res.body.total).to.equal(1)
expect(follows.length).to.equal(1)
- expect(follows[ 0 ].following.host).to.equal('localhost:9003')
+ expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[2].port)
}
{
})
it('Should have the correct follows counts', async function () {
- await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 2)
- await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0)
- await expectAccountFollows(servers[0].url, 'peertube@localhost:9003', 1, 0)
+ await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[0].port, 0, 2)
+ await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[1].port, 1, 0)
+ await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[2].port, 1, 0)
// Server 2 and 3 does not know server 1 follow another server (there was not a refresh)
- await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1)
- await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0)
+ await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[0].port, 0, 1)
+ await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[1].port, 1, 0)
- await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 1)
- await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 1, 0)
+ await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[0].port, 0, 1)
+ await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[2].port, 1, 0)
})
it('Should unfollow server 3 on server 1', async function () {
expect(follows).to.be.an('array')
expect(follows.length).to.equal(1)
- expect(follows[0].following.host).to.equal('localhost:9002')
+ expect(follows[0].following.host).to.equal('localhost:' + servers[1].port)
})
it('Should not have server 1 as follower on server 3 anymore', async function () {
})
it('Should have the correct follows counts 2', async function () {
- await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 1)
- await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0)
+ await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[0].port, 0, 1)
+ await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[1].port, 1, 0)
- await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1)
- await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0)
+ await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[0].port, 0, 1)
+ await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[1].port, 1, 0)
- await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 0)
- await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 0, 0)
+ await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[0].port, 0, 0)
+ await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[2].port, 0, 0)
})
it('Should upload a video on server 2 and 3 and propagate only the video of server 2', async function () {
})
it('Should have the correct follows counts 3', async function () {
- await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 2)
- await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0)
- await expectAccountFollows(servers[0].url, 'peertube@localhost:9003', 1, 0)
+ await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[0].port, 0, 2)
+ await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[1].port, 1, 0)
+ await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[2].port, 1, 0)
- await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1)
- await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0)
+ await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[0].port, 0, 1)
+ await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[1].port, 1, 0)
- await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 2)
- await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 1, 0)
+ await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[0].port, 0, 2)
+ await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[2].port, 1, 0)
})
it('Should have propagated videos', async function () {
support: 'my super support text',
account: {
name: 'root',
- host: 'localhost:9003'
+ host: 'localhost:' + servers[2].port
},
isLocal,
commentsEnabled: true,
expect(comment.videoId).to.equal(video4.id)
expect(comment.id).to.equal(comment.threadId)
expect(comment.account.name).to.equal('root')
- expect(comment.account.host).to.equal('localhost:9003')
+ expect(comment.account.host).to.equal('localhost:' + servers[2].port)
expect(comment.totalReplies).to.equal(3)
expect(dateIsValid(comment.createdAt as string)).to.be.true
expect(dateIsValid(comment.updatedAt as string)).to.be.true
privacy: VideoPrivacy.UNLISTED
})
- const checkAttributes = {
- name: 'my super name for server 1',
- category: 5,
- licence: 4,
- language: 'ja',
- nsfw: true,
- description: 'my super description for server 1',
- support: 'my super support text for server 1',
- account: {
- name: 'root',
- host: 'localhost:9001'
- },
- isLocal: false,
- duration: 10,
- tags: [ 'tag1p1', 'tag2p1' ],
- privacy: VideoPrivacy.PUBLIC,
- commentsEnabled: true,
- downloadEnabled: true,
- channel: {
- name: 'root_channel',
- displayName: 'Main root channel',
- description: '',
- isLocal: false
- },
- fixture: 'video_short1.webm',
- files: [
- {
- resolution: 720,
- size: 572456
- }
- ]
- }
-
- const unlistedCheckAttributes = immutableAssign(checkAttributes, {
- privacy: VideoPrivacy.UNLISTED
- })
+ let checkAttributes: any
+ let unlistedCheckAttributes: any
before(async function () {
this.timeout(30000)
servers = await flushAndRunMultipleServers(3)
+ checkAttributes = {
+ name: 'my super name for server 1',
+ category: 5,
+ licence: 4,
+ language: 'ja',
+ nsfw: true,
+ description: 'my super description for server 1',
+ support: 'my super support text for server 1',
+ account: {
+ name: 'root',
+ host: 'localhost:' + servers[0].port
+ },
+ isLocal: false,
+ duration: 10,
+ tags: [ 'tag1p1', 'tag2p1' ],
+ privacy: VideoPrivacy.PUBLIC,
+ commentsEnabled: true,
+ downloadEnabled: true,
+ channel: {
+ name: 'root_channel',
+ displayName: 'Main root channel',
+ description: '',
+ isLocal: false
+ },
+ fixture: 'video_short1.webm',
+ files: [
+ {
+ resolution: 720,
+ size: 572456
+ }
+ ]
+ }
+ unlistedCheckAttributes = immutableAssign(checkAttributes, {
+ privacy: VideoPrivacy.UNLISTED
+ })
+
// Get the access tokens
await setAccessTokensToServers(servers)
})
const res = await getFollowersListPaginationAndSort(servers[0].url, 0, 2, 'createdAt')
expect(res.body.data).to.be.an('array')
expect(res.body.data).to.have.lengthOf(1)
- expect(res.body.data[0].follower.host).to.equal('localhost:9003')
+ expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port)
})
it('Should not have pending/processing jobs anymore', async function () {
})
it('Should create some jobs', async function () {
- this.timeout(30000)
+ this.timeout(60000)
await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video1' })
await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video2' })
})
it('Should get logs with an end date', async function () {
- this.timeout(10000)
+ this.timeout(20000)
await uploadVideo(server.url, server.accessToken, { name: 'video 3' })
await waitJobs([ server ])
--- /dev/null
+#!/usr/bin/env sh
+
+set -eu
+
+checkParamFiles=$(find server/tests/api/check-params -type f | grep -v index.ts | xargs echo)
+notificationsFiles=$(find server/tests/api/notifications -type f | grep -v index.ts | xargs echo)
+searchFiles=$(find server/tests/api/search -type f | grep -v index.ts | xargs echo)
+
+MOCHA_PARALLEL=true mocha --timeout 5000 --exit --require ts-node/register --bail \
+ $notificationsFiles $searchFiles $checkParamFiles
--- /dev/null
+#!/usr/bin/env sh
+
+set -eu
+
+serverFiles=$(find server/tests/api/server -type f | grep -v index.ts | xargs echo)
+usersFiles=$(find server/tests/api/users -type f | grep -v index.ts | xargs echo)
+
+MOCHA_PARALLEL=true mocha --timeout 5000 --exit --require ts-node/register --bail \
+ $serverFiles $usersFiles
--- /dev/null
+#!/usr/bin/env sh
+
+set -eu
+
+videosFiles=$(find server/tests/api/videos -type f | grep -v index.ts | xargs echo)
+
+MOCHA_PARALLEL=true mocha --timeout 5000 --exit --require ts-node/register --bail \
+ $videosFiles
--- /dev/null
+#!/usr/bin/env sh
+
+set -eu
+
+redundancyFiles=$(find server/tests/api/redundancy -type f | grep -v index.ts | xargs echo)
+activitypubFiles=$(find server/tests/api/activitypub -type f | grep -v index.ts | xargs echo)
+
+MOCHA_PARALLEL=true mocha-parallel-tests --max-parallel $1 --timeout 5000 --exit --require ts-node/register --bail \
+ $redundancyFiles $activitypubFiles
})
it('Should block a remote account', async function () {
- await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:9002')
+ await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port)
})
it('Should hide its videos', async function () {
expect(block.byAccount.name).to.equal('root')
expect(block.blockedAccount.displayName).to.equal('user2')
expect(block.blockedAccount.name).to.equal('user2')
- expect(block.blockedAccount.host).to.equal('localhost:9002')
+ expect(block.blockedAccount.host).to.equal('localhost:' + servers[1].port)
}
{
expect(block.byAccount.name).to.equal('root')
expect(block.blockedAccount.displayName).to.equal('user1')
expect(block.blockedAccount.name).to.equal('user1')
- expect(block.blockedAccount.host).to.equal('localhost:9001')
+ expect(block.blockedAccount.host).to.equal('localhost:' + servers[0].port)
}
})
it('Should unblock the remote account', async function () {
- await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:9002')
+ await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port)
})
it('Should display its videos', async function () {
})
it('Should block a remote server', async function () {
- await addServerToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:9002')
+ await addServerToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
})
it('Should hide its videos', async function () {
const block = blocks[ 0 ]
expect(block.byAccount.displayName).to.equal('root')
expect(block.byAccount.name).to.equal('root')
- expect(block.blockedServer.host).to.equal('localhost:9002')
+ expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port)
})
it('Should unblock the remote server', async function () {
- await removeServerFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:9002')
+ await removeServerFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
})
it('Should display its videos', function () {
})
it('Should block a remote account', async function () {
- await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:9002')
+ await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port)
})
it('Should hide its videos', async function () {
expect(block.byAccount.name).to.equal('peertube')
expect(block.blockedAccount.displayName).to.equal('user2')
expect(block.blockedAccount.name).to.equal('user2')
- expect(block.blockedAccount.host).to.equal('localhost:9002')
+ expect(block.blockedAccount.host).to.equal('localhost:' + servers[1].port)
}
{
expect(block.byAccount.name).to.equal('peertube')
expect(block.blockedAccount.displayName).to.equal('user1')
expect(block.blockedAccount.name).to.equal('user1')
- expect(block.blockedAccount.host).to.equal('localhost:9001')
+ expect(block.blockedAccount.host).to.equal('localhost:' + servers[0].port)
}
})
it('Should unblock the remote account', async function () {
- await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:9002')
+ await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port)
})
it('Should display its videos', async function () {
})
it('Should block a remote server', async function () {
- await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:9002')
+ await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
})
it('Should hide its videos', async function () {
const block = blocks[ 0 ]
expect(block.byAccount.displayName).to.equal('peertube')
expect(block.byAccount.name).to.equal('peertube')
- expect(block.blockedServer.host).to.equal('localhost:9002')
+ expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port)
})
it('Should unblock the remote server', async function () {
- await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:9002')
+ await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
})
it('Should list all videos', async function () {
it('User of server 1 should follow user of server 3 and root of server 1', async function () {
this.timeout(60000)
- await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:9003')
- await addUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:9001')
+ await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:' + servers[2].port)
+ await addUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:' + servers[0].port)
await waitJobs(servers)
it('Should get subscription', async function () {
{
- const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'user3_channel@localhost:9003')
+ const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'user3_channel@localhost:' + servers[2].port)
const videoChannel: VideoChannel = res.body
expect(videoChannel.name).to.equal('user3_channel')
- expect(videoChannel.host).to.equal('localhost:9003')
+ expect(videoChannel.host).to.equal('localhost:' + servers[2].port)
expect(videoChannel.displayName).to.equal('Main user3 channel')
expect(videoChannel.followingCount).to.equal(0)
expect(videoChannel.followersCount).to.equal(1)
}
{
- const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'root_channel@localhost:9001')
+ const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'root_channel@localhost:' + servers[0].port)
const videoChannel: VideoChannel = res.body
expect(videoChannel.name).to.equal('root_channel')
- expect(videoChannel.host).to.equal('localhost:9001')
+ expect(videoChannel.host).to.equal('localhost:' + servers[0].port)
expect(videoChannel.displayName).to.equal('Main root channel')
expect(videoChannel.followingCount).to.equal(0)
expect(videoChannel.followersCount).to.equal(1)
it('Should return the existing subscriptions', async function () {
const uris = [
- 'user3_channel@localhost:9003',
- 'root2_channel@localhost:9001',
- 'root_channel@localhost:9001',
- 'user3_channel@localhost:9001'
+ 'user3_channel@localhost:' + servers[2].port,
+ 'root2_channel@localhost:' + servers[0].port,
+ 'root_channel@localhost:' + servers[0].port,
+ 'user3_channel@localhost:' + servers[0].port
]
const res = await areSubscriptionsExist(servers[ 0 ].url, users[ 0 ].accessToken, uris)
const body = res.body
- expect(body['user3_channel@localhost:9003']).to.be.true
- expect(body['root2_channel@localhost:9001']).to.be.false
- expect(body['root_channel@localhost:9001']).to.be.true
- expect(body['user3_channel@localhost:9001']).to.be.false
+ expect(body['user3_channel@localhost:' + servers[2].port]).to.be.true
+ expect(body['root2_channel@localhost:' + servers[0].port]).to.be.false
+ expect(body['root_channel@localhost:' + servers[0].port]).to.be.true
+ expect(body['user3_channel@localhost:' + servers[0].port]).to.be.false
})
it('Should list subscription videos', async function () {
it('Should remove user of server 3 subscription', async function () {
this.timeout(30000)
- await removeUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:9003')
+ await removeUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:' + servers[2].port)
await waitJobs(servers)
})
it('Should remove the root subscription and not display the videos anymore', async function () {
this.timeout(30000)
- await removeUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:9001')
+ await removeUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:' + servers[0].port)
await waitJobs(servers)
it('Should follow user of server 3 again', async function () {
this.timeout(60000)
- await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:9003')
+ await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:' + servers[2].port)
await waitJobs(servers)
import { Account } from '../../../../shared/models/actors'
import {
checkTmpIsEmpty,
- checkVideoFilesWereRemoved, cleanupTests,
+ checkVideoFilesWereRemoved,
+ cleanupTests,
createUser,
doubleFollow,
flushAndRunMultipleServers,
updateMyUser,
userLogin
} from '../../../../shared/extra-utils'
-import {
- getMyUserInformation,
- killallServers,
- ServerInfo,
- testImage,
- updateMyAvatar,
- uploadVideo
-} from '../../../../shared/extra-utils/index'
+import { getMyUserInformation, ServerInfo, testImage, updateMyAvatar, uploadVideo } from '../../../../shared/extra-utils/index'
import { checkActorFilesWereRemoved, getAccount, getAccountsList } from '../../../../shared/extra-utils/users/accounts'
import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
import { User } from '../../../../shared/models/users'
describe('Test users with multiple servers', function () {
let servers: ServerInfo[] = []
let user: User
- let userAccountName: string
- let userAccountUUID: string
- let userVideoChannelUUID: string
let userId: number
let videoUUID: string
let userAccessToken: string
+ let userAvatarFilename: string
before(async function () {
this.timeout(120000)
userAccessToken = await userLogin(servers[ 0 ], user)
}
- {
- const res = await getMyUserInformation(servers[0].url, userAccessToken)
- const account: Account = res.body.account
- userAccountName = account.name + '@' + account.host
- userAccountUUID = account.uuid
- }
-
- {
- const res = await getMyUserInformation(servers[ 0 ].url, servers[ 0 ].accessToken)
- const user: User = res.body
- userVideoChannelUUID = user.videoChannels[0].uuid
- }
-
{
const resVideo = await uploadVideo(servers[ 0 ].url, userAccessToken, {})
videoUUID = resVideo.body.video.uuid
const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
user = res.body
+
+ const account: Account = user.account
expect(user.account.displayName).to.equal('my super display name')
await waitJobs(servers)
const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
user = res.body
- await testImage(servers[0].url, 'avatar2-resized', user.account.avatar.path, '.png')
+ userAvatarFilename = user.account.avatar.path
+
+ await testImage(servers[0].url, 'avatar2-resized', userAvatarFilename, '.png')
await waitJobs(servers)
})
for (const server of servers) {
const resAccounts = await getAccountsList(server.url, '-createdAt')
- const rootServer1List = resAccounts.body.data.find(a => a.name === 'root' && a.host === 'localhost:9001') as Account
+ const rootServer1List = resAccounts.body.data.find(a => a.name === 'root' && a.host === 'localhost:' + servers[0].port) as Account
expect(rootServer1List).not.to.be.undefined
const resAccount = await getAccount(server.url, rootServer1List.name + '@' + rootServer1List.host)
const rootServer1Get = resAccount.body as Account
expect(rootServer1Get.name).to.equal('root')
- expect(rootServer1Get.host).to.equal('localhost:9001')
+ expect(rootServer1Get.host).to.equal('localhost:' + servers[0].port)
expect(rootServer1Get.displayName).to.equal('my super display name')
expect(rootServer1Get.description).to.equal('my super description updated')
it('Should list account videos', async function () {
for (const server of servers) {
- const res = await getAccountVideos(server.url, server.accessToken, userAccountName, 0, 5)
+ const res = await getAccountVideos(server.url, server.accessToken, 'user1@localhost:' + servers[0].port, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.be.an('array')
for (const server of servers) {
const resAccounts = await getAccountsList(server.url, '-createdAt')
- const accountDeleted = resAccounts.body.data.find(a => a.name === 'user1' && a.host === 'localhost:9001') as Account
+ const accountDeleted = resAccounts.body.data.find(a => a.name === 'user1' && a.host === 'localhost:' + servers[0].port) as Account
expect(accountDeleted).not.to.be.undefined
const resVideoChannels = await getVideoChannelsList(server.url, 0, 10)
const videoChannelDeleted = resVideoChannels.body.data.find(a => {
- return a.displayName === 'Main user1 channel' && a.host === 'localhost:9001'
+ return a.displayName === 'Main user1 channel' && a.host === 'localhost:' + servers[0].port
}) as VideoChannel
expect(videoChannelDeleted).not.to.be.undefined
}
for (const server of servers) {
const resAccounts = await getAccountsList(server.url, '-createdAt')
- const accountDeleted = resAccounts.body.data.find(a => a.name === 'user1' && a.host === 'localhost:9001') as Account
+ const accountDeleted = resAccounts.body.data.find(a => a.name === 'user1' && a.host === 'localhost:' + servers[0].port) as Account
expect(accountDeleted).to.be.undefined
const resVideoChannels = await getVideoChannelsList(server.url, 0, 10)
const videoChannelDeleted = resVideoChannels.body.data.find(a => {
- return a.name === 'Main user1 channel' && a.host === 'localhost:9001'
+ return a.name === 'Main user1 channel' && a.host === 'localhost:' + servers[0].port
}) as VideoChannel
expect(videoChannelDeleted).to.be.undefined
}
it('Should not have actor files', async () => {
for (const server of servers) {
- await checkActorFilesWereRemoved(userAccountUUID, server.serverNumber)
- await checkActorFilesWereRemoved(userVideoChannelUUID, server.serverNumber)
+ await checkActorFilesWereRemoved(userAvatarFilename, server.internalServerNumber)
}
})
it('Should not have video files', async () => {
for (const server of servers) {
- await checkVideoFilesWereRemoved(videoUUID, server.serverNumber)
+ await checkVideoFilesWereRemoved(videoUUID, server.internalServerNumber)
}
})
before(async function () {
this.timeout(30000)
- await MockSmtpServer.Instance.collectEmails(emails)
+ const port = await MockSmtpServer.Instance.collectEmails(emails)
const overrideConfig = {
smtp: {
- hostname: 'localhost'
+ hostname: 'localhost',
+ port
}
}
server = await flushAndRunServer(1, overrideConfig)
updateMyUser,
updateUser,
uploadVideo,
- userLogin
+ userLogin,
+ registerUserWithChannel, getVideoChannel
} from '../../../../shared/extra-utils'
import { follow } from '../../../../shared/extra-utils/server/follows'
import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
const rootUser = users[ 1 ]
expect(rootUser.username).to.equal('root')
- expect(rootUser.email).to.equal('admin1@example.com')
+ expect(rootUser.email).to.equal('admin' + server.internalServerNumber + '@example.com')
expect(user.nsfwPolicy).to.equal('display')
userId = user.id
const user = users[ 0 ]
expect(user.username).to.equal('root')
- expect(user.email).to.equal('admin1@example.com')
+ expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com')
expect(user.roleLabel).to.equal('Administrator')
expect(user.nsfwPolicy).to.equal('display')
})
expect(users.length).to.equal(2)
expect(users[ 0 ].username).to.equal('root')
- expect(users[ 0 ].email).to.equal('admin1@example.com')
+ expect(users[ 0 ].email).to.equal('admin' + server.internalServerNumber + '@example.com')
expect(users[ 0 ].nsfwPolicy).to.equal('display')
expect(users[ 1 ].username).to.equal('user_1')
describe('Registering a new user', function () {
it('Should register a new user', async function () {
- await registerUser(server.url, 'user_15', 'my super password')
+ const user = { username: 'user_15', password: 'my super password' }
+ const channel = { name: 'my_user_15_channel', displayName: 'my channel rocks' }
+
+ await registerUserWithChannel({ url: server.url, user, channel })
})
it('Should be able to login with this registered user', async function () {
expect(user.videoQuota).to.equal(5 * 1024 * 1024)
})
+ it('Should have created the channel', async function () {
+ const res = await getVideoChannel(server.url, 'my_user_15_channel')
+
+ expect(res.body.displayName).to.equal('my channel rocks')
+ })
+
it('Should remove me', async function () {
{
const res = await getUsersList(server.url, server.accessToken)
import {
addVideoChannel,
checkTmpIsEmpty,
- checkVideoFilesWereRemoved, cleanupTests,
+ checkVideoFilesWereRemoved,
+ cleanupTests,
completeVideoCheck,
createUser,
dateIsValid,
doubleFollow,
flushAndRunMultipleServers,
- flushTests,
getLocalVideos,
getVideo,
getVideoChannelsList,
getVideosList,
- killallServers,
rateVideo,
removeVideo,
ServerInfo,
// All servers should have this video
let publishedAt: string = null
for (const server of servers) {
- const isLocal = server.url === 'http://localhost:9001'
+ const isLocal = server.port === servers[0].port
const checkAttributes = {
name: 'my super name for server 1',
category: 5,
originallyPublishedAt: '2019-02-10T13:38:14.449Z',
account: {
name: 'root',
- host: 'localhost:9001'
+ host: 'localhost:' + servers[0].port
},
isLocal,
publishedAt,
// All servers should have this video
for (const server of servers) {
- const isLocal = server.url === 'http://localhost:9002'
+ const isLocal = server.url === 'http://localhost:' + servers[1].port
const checkAttributes = {
name: 'my super name for server 2',
category: 4,
support: 'my super support text for server 2',
account: {
name: 'user1',
- host: 'localhost:9002'
+ host: 'localhost:' + servers[1].port
},
isLocal,
commentsEnabled: true,
files: [
{
resolution: 240,
- size: 187000
+ size: 189000
},
{
resolution: 360,
},
{
resolution: 480,
- size: 383000
+ size: 384000
},
{
resolution: 720,
// All servers should have this video
for (const server of servers) {
- const isLocal = server.url === 'http://localhost:9003'
+ const isLocal = server.url === 'http://localhost:' + servers[2].port
const res = await getVideosList(server.url)
const videos = res.body.data
support: 'my super support text for server 3',
account: {
name: 'root',
- host: 'localhost:9003'
+ host: 'localhost:' + servers[2].port
},
isLocal,
duration: 5,
support: 'my super support text for server 3-2',
account: {
name: 'root',
- host: 'localhost:9003'
+ host: 'localhost:' + servers[2].port
},
commentsEnabled: true,
downloadEnabled: true,
const videoUpdated = videos.find(video => video.name === 'my super video updated')
expect(!!videoUpdated).to.be.true
- const isLocal = server.url === 'http://localhost:9003'
+ const isLocal = server.url === 'http://localhost:' + servers[2].port
const checkAttributes = {
name: 'my super video updated',
category: 10,
originallyPublishedAt: '2019-02-11T13:38:14.449Z',
account: {
name: 'root',
- host: 'localhost:9003'
+ host: 'localhost:' + servers[2].port
},
isLocal,
duration: 5,
expect(comment).to.not.be.undefined
expect(comment.inReplyToCommentId).to.be.null
expect(comment.account.name).to.equal('root')
- expect(comment.account.host).to.equal('localhost:9001')
+ expect(comment.account.host).to.equal('localhost:' + servers[0].port)
expect(comment.totalReplies).to.equal(3)
expect(dateIsValid(comment.createdAt as string)).to.be.true
expect(dateIsValid(comment.updatedAt as string)).to.be.true
expect(comment).to.not.be.undefined
expect(comment.inReplyToCommentId).to.be.null
expect(comment.account.name).to.equal('root')
- expect(comment.account.host).to.equal('localhost:9003')
+ expect(comment.account.host).to.equal('localhost:' + servers[2].port)
expect(comment.totalReplies).to.equal(0)
expect(dateIsValid(comment.createdAt as string)).to.be.true
expect(dateIsValid(comment.updatedAt as string)).to.be.true
const tree: VideoCommentThreadTree = res2.body
expect(tree.comment.text).equal('my super first comment')
expect(tree.comment.account.name).equal('root')
- expect(tree.comment.account.host).equal('localhost:9001')
+ expect(tree.comment.account.host).equal('localhost:' + servers[0].port)
expect(tree.children).to.have.lengthOf(2)
const firstChild = tree.children[0]
expect(firstChild.comment.text).to.equal('my super answer to thread 1')
expect(firstChild.comment.account.name).equal('root')
- expect(firstChild.comment.account.host).equal('localhost:9002')
+ expect(firstChild.comment.account.host).equal('localhost:' + servers[1].port)
expect(firstChild.children).to.have.lengthOf(1)
childOfFirstChild = firstChild.children[0]
expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1')
expect(childOfFirstChild.comment.account.name).equal('root')
- expect(childOfFirstChild.comment.account.host).equal('localhost:9003')
+ expect(childOfFirstChild.comment.account.host).equal('localhost:' + servers[2].port)
expect(childOfFirstChild.children).to.have.lengthOf(0)
const secondChild = tree.children[1]
expect(secondChild.comment.text).to.equal('my second answer to thread 1')
expect(secondChild.comment.account.name).equal('root')
- expect(secondChild.comment.account.host).equal('localhost:9003')
+ expect(secondChild.comment.account.host).equal('localhost:' + servers[2].port)
expect(secondChild.children).to.have.lengthOf(0)
}
})
expect(comment).to.not.be.undefined
expect(comment.inReplyToCommentId).to.be.null
expect(comment.account.name).to.equal('root')
- expect(comment.account.host).to.equal('localhost:9003')
+ expect(comment.account.host).to.equal('localhost:' + servers[2].port)
expect(comment.totalReplies).to.equal(0)
expect(dateIsValid(comment.createdAt as string)).to.be.true
expect(dateIsValid(comment.updatedAt as string)).to.be.true
const res = await getVideosList(server.url)
const video = res.body.data.find(v => v.name === 'minimum parameters')
- const isLocal = server.url === 'http://localhost:9002'
+ const isLocal = server.url === 'http://localhost:' + servers[1].port
const checkAttributes = {
name: 'minimum parameters',
category: null,
support: null,
account: {
name: 'root',
- host: 'localhost:9002'
+ host: 'localhost:' + servers[1].port
},
isLocal,
duration: 5,
})
it('Should have a valid oEmbed response', async function () {
- const oembedUrl = 'http://localhost:9001/videos/watch/' + server.video.uuid
+ const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/' + server.video.uuid
const res = await getOEmbed(server.url, oembedUrl)
const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' +
- `src="http://localhost:9001/videos/embed/${server.video.uuid}" ` +
+ `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` +
'frameborder="0" allowfullscreen></iframe>'
- const expectedThumbnailUrl = 'http://localhost:9001/static/previews/' + server.video.uuid + '.jpg'
+ const expectedThumbnailUrl = 'http://localhost:' + server.port + '/static/previews/' + server.video.uuid + '.jpg'
expect(res.body.html).to.equal(expectedHtml)
expect(res.body.title).to.equal(server.video.name)
expect(res.body.width).to.equal(560)
expect(res.body.height).to.equal(315)
expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl)
- expect(res.body.thumbnail_width).to.equal(560)
- expect(res.body.thumbnail_height).to.equal(315)
+ expect(res.body.thumbnail_width).to.equal(850)
+ expect(res.body.thumbnail_height).to.equal(480)
})
it('Should have a valid oEmbed response with small max height query', async function () {
- const oembedUrl = 'http://localhost:9001/videos/watch/' + server.video.uuid
+ const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/' + server.video.uuid
const format = 'json'
const maxHeight = 50
const maxWidth = 50
const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth)
const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' +
- `src="http://localhost:9001/videos/embed/${server.video.uuid}" ` +
+ `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` +
'frameborder="0" allowfullscreen></iframe>'
expect(res.body.html).to.equal(expectedHtml)
let videoUUID = ''
let videosListBase: any[] = null
- const getCheckAttributes = {
+ const getCheckAttributes = () => ({
name: 'my super name',
category: 2,
licence: 6,
support: 'my super support text',
account: {
name: 'root',
- host: 'localhost:9001'
+ host: 'localhost:' + server.port
},
isLocal: true,
duration: 5,
size: 218910
}
]
- }
+ })
- const updateCheckAttributes = {
+ const updateCheckAttributes = () => ({
name: 'my super video updated',
category: 4,
licence: 2,
support: 'my super support text updated',
account: {
name: 'root',
- host: 'localhost:9001'
+ host: 'localhost:' + server.port
},
isLocal: true,
tags: [ 'tagup1', 'tagup2' ],
size: 292677
}
]
- }
+ })
before(async function () {
this.timeout(30000)
expect(res.body.data.length).to.equal(1)
const video = res.body.data[0]
- await completeVideoCheck(server.url, video, getCheckAttributes)
+ await completeVideoCheck(server.url, video, getCheckAttributes())
})
it('Should get the video by UUID', async function () {
const res = await getVideo(server.url, videoUUID)
const video = res.body
- await completeVideoCheck(server.url, video, getCheckAttributes)
+ await completeVideoCheck(server.url, video, getCheckAttributes())
})
it('Should have the views updated', async function () {
const res = await getVideo(server.url, videoId)
const video = res.body
- await completeVideoCheck(server.url, video, updateCheckAttributes)
+ await completeVideoCheck(server.url, video, updateCheckAttributes())
})
it('Should update only the tags of a video', async function () {
const res = await getVideo(server.url, videoId)
const video = res.body
- await completeVideoCheck(server.url, video, Object.assign(updateCheckAttributes, attributes))
+ await completeVideoCheck(server.url, video, Object.assign(updateCheckAttributes(), attributes))
})
it('Should update only the description of a video', async function () {
const res = await getVideo(server.url, videoId)
const video = res.body
- await completeVideoCheck(server.url, video, Object.assign(updateCheckAttributes, attributes))
+ const expectedAttributes = Object.assign(updateCheckAttributes(), { tags: [ 'supertag', 'tag1', 'tag2' ] }, attributes)
+ await completeVideoCheck(server.url, video, expectedAttributes)
})
it('Should like a video', async function () {
flushAndRunMultipleServers,
getVideoAbusesList,
getVideosList,
- killallServers,
reportVideoAbuse,
ServerInfo,
setAccessTokensToServers,
const abuse: VideoAbuse = res1.body.data[0]
expect(abuse.reason).to.equal('my super bad reason')
expect(abuse.reporterAccount.name).to.equal('root')
- expect(abuse.reporterAccount.host).to.equal('localhost:9001')
+ expect(abuse.reporterAccount.host).to.equal('localhost:' + servers[0].port)
expect(abuse.video.id).to.equal(servers[0].video.id)
const res2 = await getVideoAbusesList(servers[1].url, servers[1].accessToken)
const abuse1: VideoAbuse = res1.body.data[0]
expect(abuse1.reason).to.equal('my super bad reason')
expect(abuse1.reporterAccount.name).to.equal('root')
- expect(abuse1.reporterAccount.host).to.equal('localhost:9001')
+ expect(abuse1.reporterAccount.host).to.equal('localhost:' + servers[0].port)
expect(abuse1.video.id).to.equal(servers[0].video.id)
expect(abuse1.state.id).to.equal(VideoAbuseState.PENDING)
expect(abuse1.state.label).to.equal('Pending')
const abuse2: VideoAbuse = res1.body.data[1]
expect(abuse2.reason).to.equal('my super bad reason 2')
expect(abuse2.reporterAccount.name).to.equal('root')
- expect(abuse2.reporterAccount.host).to.equal('localhost:9001')
+ expect(abuse2.reporterAccount.host).to.equal('localhost:' + servers[0].port)
expect(abuse2.video.id).to.equal(servers[1].video.id)
expect(abuse2.state.id).to.equal(VideoAbuseState.PENDING)
expect(abuse2.state.label).to.equal('Pending')
abuseServer2 = res2.body.data[0]
expect(abuseServer2.reason).to.equal('my super bad reason 2')
expect(abuseServer2.reporterAccount.name).to.equal('root')
- expect(abuseServer2.reporterAccount.host).to.equal('localhost:9001')
+ expect(abuseServer2.reporterAccount.host).to.equal('localhost:' + servers[0].port)
expect(abuseServer2.state.id).to.equal(VideoAbuseState.PENDING)
expect(abuseServer2.state.label).to.equal('Pending')
expect(abuseServer2.moderationComment).to.be.null
import 'mocha'
import {
acceptChangeOwnership,
- changeVideoOwnership, cleanupTests,
+ changeVideoOwnership,
+ cleanupTests,
createUser,
doubleFollow,
flushAndRunMultipleServers,
getVideo,
getVideoChangeOwnershipList,
getVideosList,
- killallServers,
refuseChangeOwnership,
ServerInfo,
setAccessTokensToServers,
}
})
- after(function () {
- killallServers(servers)
+ after(async function () {
+ await cleanupTests(servers)
})
})
import * as chai from 'chai'
import 'mocha'
-import { User, Video } from '../../../../shared/index'
+import { User, Video, VideoChannel, VideoDetails } from '../../../../shared/index'
import {
cleanupTests,
createUser,
doubleFollow,
- flushAndRunMultipleServers,
+ flushAndRunMultipleServers, getVideo,
getVideoChannelVideos,
testImage,
updateVideo,
import {
addVideoChannel,
deleteVideoChannel,
- flushTests,
getAccountVideoChannelsList,
getMyUserInformation,
getVideoChannel,
getVideoChannelsList,
- killallServers,
ServerInfo,
setAccessTokensToServers,
updateVideoChannel
describe('Test video channels', function () {
let servers: ServerInfo[]
let userInfo: User
- let accountUUID: string
let firstVideoChannelId: number
let secondVideoChannelId: number
let videoUUID: string
before(async function () {
- this.timeout(30000)
+ this.timeout(60000)
servers = await flushAndRunMultipleServers(2)
{
const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
const user: User = res.body
- accountUUID = user.account.uuid
firstVideoChannelId = user.videoChannels[0].id
}
// The channel is 1 is propagated to servers 2
{
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'my video name', channelId: secondVideoChannelId })
+ const videoAttributesArg = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' }
+ const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributesArg)
videoUUID = res.body.video.uuid
}
})
it('Should have two video channels when getting account channels on server 1', async function () {
- const res = await getAccountVideoChannelsList(servers[0].url, userInfo.account.name + '@' + userInfo.account.host)
+ const res = await getAccountVideoChannelsList({
+ url: servers[ 0 ].url,
+ accountName: userInfo.account.name + '@' + userInfo.account.host
+ })
+
expect(res.body.total).to.equal(2)
expect(res.body.data).to.be.an('array')
expect(res.body.data).to.have.lengthOf(2)
expect(videoChannels[1].support).to.equal('super video channel support text')
})
+ it('Should paginate and sort account channels', async function () {
+ {
+ const res = await getAccountVideoChannelsList({
+ url: servers[ 0 ].url,
+ accountName: userInfo.account.name + '@' + userInfo.account.host,
+ start: 0,
+ count: 1,
+ sort: 'createdAt'
+ })
+
+ expect(res.body.total).to.equal(2)
+ expect(res.body.data).to.have.lengthOf(1)
+
+ const videoChannel: VideoChannel = res.body.data[ 0 ]
+ expect(videoChannel.name).to.equal('root_channel')
+ }
+
+ {
+ const res = await getAccountVideoChannelsList({
+ url: servers[ 0 ].url,
+ accountName: userInfo.account.name + '@' + userInfo.account.host,
+ start: 0,
+ count: 1,
+ sort: '-createdAt'
+ })
+
+ expect(res.body.total).to.equal(2)
+ expect(res.body.data).to.have.lengthOf(1)
+
+ const videoChannel: VideoChannel = res.body.data[ 0 ]
+ expect(videoChannel.name).to.equal('second_video_channel')
+ }
+
+ {
+ const res = await getAccountVideoChannelsList({
+ url: servers[ 0 ].url,
+ accountName: userInfo.account.name + '@' + userInfo.account.host,
+ start: 1,
+ count: 1,
+ sort: '-createdAt'
+ })
+
+ expect(res.body.total).to.equal(2)
+ expect(res.body.data).to.have.lengthOf(1)
+
+ const videoChannel: VideoChannel = res.body.data[ 0 ]
+ expect(videoChannel.name).to.equal('root_channel')
+ }
+ })
+
it('Should have one video channel when getting account channels on server 2', async function () {
- const res = await getAccountVideoChannelsList(servers[1].url, userInfo.account.name + '@' + userInfo.account.host)
+ const res = await getAccountVideoChannelsList({
+ url: servers[ 1 ].url,
+ accountName: userInfo.account.name + '@' + userInfo.account.host
+ })
+
expect(res.body.total).to.equal(1)
expect(res.body.data).to.be.an('array')
expect(res.body.data).to.have.lengthOf(1)
})
it('Should update video channel', async function () {
- this.timeout(5000)
+ this.timeout(15000)
const videoChannelAttributes = {
displayName: 'video channel updated',
description: 'video channel description updated',
- support: 'video channel support text updated'
+ support: 'support updated'
}
await updateVideoChannel(servers[0].url, servers[0].accessToken, 'second_video_channel', videoChannelAttributes)
expect(res.body.data[0].name).to.equal('second_video_channel')
expect(res.body.data[0].displayName).to.equal('video channel updated')
expect(res.body.data[0].description).to.equal('video channel description updated')
- expect(res.body.data[0].support).to.equal('video channel support text updated')
+ expect(res.body.data[0].support).to.equal('support updated')
+ }
+ })
+
+ it('Should not have updated the video support field', async function () {
+ for (const server of servers) {
+ const res = await getVideo(server.url, videoUUID)
+ const video: VideoDetails = res.body
+
+ expect(video.support).to.equal('video support field')
+ }
+ })
+
+ it('Should update the channel support field and update videos too', async function () {
+ this.timeout(35000)
+
+ const videoChannelAttributes = {
+ support: 'video channel support text updated',
+ bulkVideosSupportUpdate: true
+ }
+
+ await updateVideoChannel(servers[0].url, servers[0].accessToken, 'second_video_channel', videoChannelAttributes)
+
+ await waitJobs(servers)
+
+ for (const server of servers) {
+ const res = await getVideo(server.url, videoUUID)
+ const video: VideoDetails = res.body
+
+ expect(video.support).to.equal(videoChannelAttributes.support)
}
})
this.timeout(10000)
for (const server of servers) {
- const channelURI = 'second_video_channel@localhost:9001'
+ const channelURI = 'second_video_channel@localhost:' + servers[0].port
const res1 = await getVideoChannelVideos(server.url, server.accessToken, channelURI, 0, 5)
expect(res1.body.total).to.equal(1)
expect(res1.body.data).to.be.an('array')
this.timeout(10000)
for (const server of servers) {
- const secondChannelURI = 'second_video_channel@localhost:9001'
+ const secondChannelURI = 'second_video_channel@localhost:' + servers[0].port
const res1 = await getVideoChannelVideos(server.url, server.accessToken, secondChannelURI, 0, 5)
expect(res1.body.total).to.equal(0)
- const channelURI = 'root_channel@localhost:9001'
+ const channelURI = 'root_channel@localhost:' + servers[0].port
const res2 = await getVideoChannelVideos(server.url, server.accessToken, channelURI, 0, 5)
expect(res2.body.total).to.equal(1)
expect(comment.videoId).to.equal(videoId)
expect(comment.id).to.equal(comment.threadId)
expect(comment.account.name).to.equal('root')
- expect(comment.account.host).to.equal('localhost:9001')
- expect(comment.account.url).to.equal('http://localhost:9001/accounts/root')
+ expect(comment.account.host).to.equal('localhost:' + server.port)
+ expect(comment.account.url).to.equal('http://localhost:' + server.port + '/accounts/root')
expect(comment.totalReplies).to.equal(0)
expect(dateIsValid(comment.createdAt as string)).to.be.true
expect(dateIsValid(comment.updatedAt as string)).to.be.true
expect(comment.videoId).to.equal(videoId)
expect(comment.id).to.equal(comment.threadId)
expect(comment.account.name).to.equal('root')
- expect(comment.account.host).to.equal('localhost:9001')
+ expect(comment.account.host).to.equal('localhost:' + server.port)
await testImage(server.url, 'avatar-resized', comment.account.avatar.path, '.png')
import {
checkDirectoryIsEmpty,
checkSegmentHash,
- checkTmpIsEmpty, cleanupTests,
+ checkTmpIsEmpty,
+ cleanupTests,
doubleFollow,
flushAndRunMultipleServers,
- flushTests,
getPlaylist,
getVideo,
- killallServers,
removeVideo,
ServerInfo,
setAccessTokensToServers,
import { VideoDetails } from '../../../../shared/models/videos'
import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type'
import { join } from 'path'
+import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants'
const expect = chai.expect
-async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string) {
- const resolutions = [ 240, 360, 480, 720 ]
-
+async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string, resolutions = [ 240, 360, 480, 720 ]) {
for (const server of servers) {
const res = await getVideo(server.url, videoUUID)
const videoDetails: VideoDetails = res.body
const masterPlaylist = res2.text
- expect(masterPlaylist).to.contain('#EXT-X-STREAM-INF:BANDWIDTH=55472,RESOLUTION=640x360,FRAME-RATE=25')
-
for (const resolution of resolutions) {
+ expect(masterPlaylist).to.match(new RegExp('#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',FRAME-RATE=\\d+'))
expect(masterPlaylist).to.contain(`${resolution}.m3u8`)
}
}
{
for (const resolution of resolutions) {
- const res2 = await getPlaylist(`http://localhost:9001/static/streaming-playlists/hls/${videoUUID}/${resolution}.m3u8`)
+ const res2 = await getPlaylist(`http://localhost:${servers[0].port}/static/streaming-playlists/hls/${videoUUID}/${resolution}.m3u8`)
const subPlaylist = res2.text
expect(subPlaylist).to.contain(`${videoUUID}-${resolution}-fragmented.mp4`)
}
{
- const baseUrl = 'http://localhost:9001/static/streaming-playlists/hls'
+ const baseUrl = 'http://localhost:' + servers[0].port + '/static/streaming-playlists/hls'
for (const resolution of resolutions) {
await checkSegmentHash(baseUrl, baseUrl, videoUUID, resolution, hlsPlaylist)
describe('Test HLS videos', function () {
let servers: ServerInfo[] = []
let videoUUID = ''
+ let videoAudioUUID = ''
before(async function () {
this.timeout(120000)
- servers = await flushAndRunMultipleServers(2, { transcoding: { enabled: true, hls: { enabled: true } } })
+ const configOverride = {
+ transcoding: {
+ enabled: true,
+ allow_audio_files: true,
+ hls: {
+ enabled: true
+ }
+ }
+ }
+ servers = await flushAndRunMultipleServers(2, configOverride)
// Get the access tokens
await setAccessTokensToServers(servers)
it('Should upload a video and transcode it to HLS', async function () {
this.timeout(120000)
- {
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1', fixture: 'video_short.webm' })
- videoUUID = res.body.video.uuid
- }
+ const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1', fixture: 'video_short.webm' })
+ videoUUID = res.body.video.uuid
await waitJobs(servers)
await checkHlsPlaylist(servers, videoUUID)
})
+ it('Should upload an audio file and transcode it to HLS', async function () {
+ this.timeout(120000)
+
+ const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video audio', fixture: 'sample.ogg' })
+ videoAudioUUID = res.body.video.uuid
+
+ await waitJobs(servers)
+
+ await checkHlsPlaylist(servers, videoAudioUUID, [ DEFAULT_AUDIO_RESOLUTION ])
+ })
+
it('Should update the video', async function () {
+ this.timeout(10000)
+
await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { name: 'video 1 updated' })
await waitJobs(servers)
await checkHlsPlaylist(servers, videoUUID)
})
- it('Should delete the video', async function () {
+ it('Should delete videos', async function () {
+ this.timeout(10000)
+
await removeVideo(servers[0].url, servers[0].accessToken, videoUUID)
+ await removeVideo(servers[0].url, servers[0].accessToken, videoAudioUUID)
await waitJobs(servers)
for (const server of servers) {
await getVideo(server.url, videoUUID, 404)
+ await getVideo(server.url, videoAudioUUID, 404)
}
})
for (const server of servers) {
const results = [
- await getAccountPlaylistsList(server.url, 'root@localhost:9002', 0, 5, '-createdAt'),
+ await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[1].port, 0, 5, '-createdAt'),
await getVideoPlaylistsList(server.url, 0, 2, '-createdAt')
]
}
})
+
+ it('Should be able to create a public playlist, and set it to private', async function () {
+ this.timeout(30000)
+
+ const res = await createVideoPlaylist({
+ url: servers[0].url,
+ token: servers[0].accessToken,
+ playlistAttrs: {
+ displayName: 'my super public playlist',
+ privacy: VideoPlaylistPrivacy.PUBLIC,
+ videoChannelId: servers[0].videoChannel.id
+ }
+ })
+ const videoPlaylistIds = res.body.videoPlaylist
+
+ await waitJobs(servers)
+
+ for (const server of servers) {
+ await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 200)
+ }
+
+ const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE }
+ await updateVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs })
+
+ await waitJobs(servers)
+
+ for (const server of [ servers[1], servers[2] ]) {
+ await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404)
+ }
+ await getVideoPlaylist(servers[0].url, videoPlaylistIds.uuid, 401)
+
+ await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistIds.uuid, 200)
+ })
+
it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () {
this.timeout(30000)
this.timeout(30000)
for (const server of servers) {
- await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.serverNumber)
+ await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.internalServerNumber)
}
})
import {
cleanupTests,
flushAndRunMultipleServers,
- getVideosList,
- killallServers,
+ getVideosList, getVideosListWithToken,
ServerInfo,
setAccessTokensToServers,
uploadVideo
}
})
+ it('Should set this new video as private', async function () {
+ this.timeout(10000)
+
+ await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, { privacy: VideoPrivacy.PRIVATE })
+
+ await waitJobs(servers)
+
+ for (const server of servers) {
+ const res = await getVideosList(server.url)
+
+ expect(res.body.total).to.equal(0)
+ expect(res.body.data).to.have.lengthOf(0)
+ }
+
+ {
+ const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 5)
+
+ expect(res.body.total).to.equal(1)
+ expect(res.body.data).to.have.lengthOf(1)
+ expect(res.body.data[0].name).to.equal('super video public')
+ }
+ })
+
after(async function () {
await cleanupTests(servers)
})
import 'mocha'
import { omit } from 'lodash'
import { getMaxBitrate, VideoDetails, VideoResolution, VideoState } from '../../../../shared/models/videos'
-import { audio, getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils'
+import { audio, canDoQuickTranscode, getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils'
import {
- buildAbsoluteFixturePath, cleanupTests,
+ buildAbsoluteFixturePath,
+ cleanupTests,
doubleFollow,
flushAndRunMultipleServers,
generateHighBitrateVideo,
getMyVideos,
getVideo,
getVideosList,
- killallServers,
+ makeGetRequest,
root,
ServerInfo,
setAccessTokensToServers,
uploadVideo,
+ waitJobs,
webtorrentAdd
} from '../../../../shared/extra-utils'
-import { extname, join } from 'path'
-import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
+import { join } from 'path'
import { VIDEO_TRANSCODING_FPS } from '../../../../server/initializers/constants'
const expect = chai.expect
expect(videoDetails.files).to.have.lengthOf(4)
- const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4')
+ const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4')
const probe = await audio.get(path)
if (probe.audioStream) {
const videoDetails: VideoDetails = res2.body
expect(videoDetails.files).to.have.lengthOf(4)
- const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4')
+ const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4')
const probe = await audio.get(path)
expect(probe).to.not.have.property('audioStream')
}
expect(videoDetails.files).to.have.lengthOf(4)
const fixturePath = buildAbsoluteFixturePath(videoAttributes.fixture)
const fixtureVideoProbe = await audio.get(fixturePath)
- const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4')
+ const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4')
const videoProbe = await audio.get(path)
if (videoProbe.audioStream && fixtureVideoProbe.audioStream) {
const toOmit = [ 'max_bit_rate', 'duration', 'duration_ts', 'nb_frames', 'start_time', 'start_pts' ]
expect(videoDetails.files[ 3 ].fps).to.be.below(31)
for (const resolution of [ '240', '360', '480' ]) {
- const path = join(root(), 'test2', 'videos', video.uuid + '-' + resolution + '.mp4')
+ const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4')
const fps = await getVideoFileFPS(path)
expect(fps).to.be.below(31)
}
- const path = join(root(), 'test2', 'videos', video.uuid + '-720.mp4')
+ const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-720.mp4')
const fps = await getVideoFileFPS(path)
expect(fps).to.be.above(58).and.below(62)
const video = res.body.data.find(v => v.name === videoAttributes.name)
for (const resolution of ['240', '360', '480', '720', '1080']) {
- const path = join(root(), 'test2', 'videos', video.uuid + '-' + resolution + '.mp4')
+ const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4')
const bitrate = await getVideoFileBitrate(path)
const fps = await getVideoFileFPS(path)
const resolution2 = await getVideoFileResolution(path)
it('Should accept and transcode additional extensions', async function () {
this.timeout(300000)
+ let tempFixturePath: string
+
+ {
+ tempFixturePath = await generateHighBitrateVideo()
+
+ const bitrate = await getVideoFileBitrate(tempFixturePath)
+ expect(bitrate).to.be.above(getMaxBitrate(VideoResolution.H_1080P, 60, VIDEO_TRANSCODING_FPS))
+ }
+
for (const fixture of [ 'video_short.mkv', 'video_short.avi' ]) {
const videoAttributes = {
name: fixture,
}
})
+ it('Should correctly detect if quick transcode is possible', async function () {
+ this.timeout(10000)
+
+ expect(await canDoQuickTranscode(buildAbsoluteFixturePath('video_short.mp4'))).to.be.true
+ expect(await canDoQuickTranscode(buildAbsoluteFixturePath('video_short.webm'))).to.be.false
+ })
+
+ it('Should merge an audio file with the preview file', async function () {
+ this.timeout(60000)
+
+ const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' }
+ await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg)
+
+ await waitJobs(servers)
+
+ for (const server of servers) {
+ const res = await getVideosList(server.url)
+
+ const video = res.body.data.find(v => v.name === 'audio_with_preview')
+ const res2 = await getVideo(server.url, video.id)
+ const videoDetails: VideoDetails = res2.body
+
+ expect(videoDetails.files).to.have.lengthOf(1)
+
+ await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 })
+ await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 })
+
+ const magnetUri = videoDetails.files[ 0 ].magnetUri
+ expect(magnetUri).to.contain('.mp4')
+ }
+ })
+
+ it('Should upload an audio file and choose a default background image', async function () {
+ this.timeout(60000)
+
+ const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' }
+ await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg)
+
+ await waitJobs(servers)
+
+ for (const server of servers) {
+ const res = await getVideosList(server.url)
+
+ const video = res.body.data.find(v => v.name === 'audio_without_preview')
+ const res2 = await getVideo(server.url, video.id)
+ const videoDetails = res2.body
+
+ expect(videoDetails.files).to.have.lengthOf(1)
+
+ await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 })
+ await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 })
+
+ const magnetUri = videoDetails.files[ 0 ].magnetUri
+ expect(magnetUri).to.contain('.mp4')
+ }
+ })
+
after(async function () {
await cleanupTests(servers)
})
flushAndRunServer,
ServerInfo,
setAccessTokensToServers,
- uploadVideo, uploadVideoAndGetId, viewVideo, wait, countVideoViewsOf, doubleFollow, waitJobs, cleanupTests
+ uploadVideo, uploadVideoAndGetId, viewVideo, wait, countVideoViewsOf, doubleFollow, waitJobs, cleanupTests, closeAllSequelize
} from '../../../../shared/extra-utils'
import { getVideosOverview } from '../../../../shared/extra-utils/overviews/overviews'
import { VideosOverview } from '../../../../shared/models/overviews'
{
for (const server of servers) {
- const total = await countVideoViewsOf(server.serverNumber, videoIdServer1)
+ const total = await countVideoViewsOf(server.internalServerNumber, videoIdServer1)
expect(total).to.equal(2)
}
}
{
for (const server of servers) {
- const total = await countVideoViewsOf(server.serverNumber, videoIdServer2)
+ const total = await countVideoViewsOf(server.internalServerNumber, videoIdServer2)
expect(total).to.equal(2)
}
}
it('Should clean old video views', async function () {
this.timeout(50000)
- this.timeout(50000)
-
killallServers([ servers[0] ])
await reRunServer(servers[0], { views: { videos: { remote: { max_age: '5 seconds' } } } })
{
for (const server of servers) {
- const total = await countVideoViewsOf(server.serverNumber, videoIdServer1)
+ const total = await countVideoViewsOf(server.internalServerNumber, videoIdServer1)
expect(total).to.equal(2)
}
}
{
- const totalServer1 = await countVideoViewsOf(servers[0].serverNumber, videoIdServer2)
+ const totalServer1 = await countVideoViewsOf(servers[0].internalServerNumber, videoIdServer2)
expect(totalServer1).to.equal(0)
- const totalServer2 = await countVideoViewsOf(servers[1].serverNumber, videoIdServer2)
+ const totalServer2 = await countVideoViewsOf(servers[1].internalServerNumber, videoIdServer2)
expect(totalServer2).to.equal(2)
}
})
after(async function () {
+ await closeAllSequelize(servers)
+
await cleanupTests(servers)
})
})
doubleFollow,
execCLI,
flushAndRunMultipleServers,
- flushTests, generateHighBitrateVideo,
+ generateHighBitrateVideo,
getEnvCli,
getVideo,
getVideosList,
- killallServers, root,
+ root,
ServerInfo,
setAccessTokensToServers,
- uploadVideo, viewVideo, wait
+ uploadVideo,
+ viewVideo,
+ wait
} from '../../../shared/extra-utils'
import { waitJobs } from '../../../shared/extra-utils/server/jobs'
import { getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../helpers/ffmpeg-utils'
expect(file.size).to.be.below(5000000)
- const path = join(root(), 'test1', 'videos', video.uuid + '-' + file.resolution.id + '.mp4')
+ const path = join(root(), 'test' + servers[0].internalServerNumber, 'videos', video.uuid + '-' + file.resolution.id + '.mp4')
const bitrate = await getVideoFileBitrate(path)
const fps = await getVideoFileFPS(path)
const resolution = await getVideoFileResolution(path)
createUser,
doubleFollow,
flushAndRunMultipleServers,
- flushTests,
- getJSONfeed, getMyUserInformation,
+ getJSONfeed,
+ getMyUserInformation,
getXMLfeed,
- killallServers,
ServerInfo,
setAccessTokensToServers,
- uploadVideo, userLogin
+ uploadVideo,
+ userLogin
} from '../../../shared/extra-utils'
import * as libxmljs from 'libxmljs'
import { addVideoCommentThread } from '../../../shared/extra-utils/videos/video-comments'
describe('Test syndication feeds', () => {
let servers: ServerInfo[] = []
let userAccessToken: string
- let rootAccountUUID: string
- let rootChannelUUID: string
- let userAccountUUID: string
- let userChannelUUID: string
+ let rootAccountId: number
+ let rootChannelId: number
+ let userAccountId: number
+ let userChannelId: number
before(async function () {
this.timeout(120000)
{
const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
const user: User = res.body
- rootAccountUUID = user.account.uuid
- rootChannelUUID = user.videoChannels[0].uuid
+ rootAccountId = user.account.id
+ rootChannelId = user.videoChannels[0].id
}
{
const res = await getMyUserInformation(servers[0].url, userAccessToken)
const user: User = res.body
- userAccountUUID = user.account.uuid
- userChannelUUID = user.videoChannels[0].uuid
+ userAccountId = user.account.id
+ userChannelId = user.videoChannels[0].id
}
{
})
it('Should filter by account', async function () {
+ {
+ const json = await getJSONfeed(servers[0].url, 'videos', { accountId: rootAccountId })
+ const jsonObj = JSON.parse(json.text)
+ expect(jsonObj.items.length).to.be.equal(1)
+ expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
+ expect(jsonObj.items[ 0 ].author.name).to.equal('root')
+ }
+
+ {
+ const json = await getJSONfeed(servers[0].url, 'videos', { accountId: userAccountId })
+ const jsonObj = JSON.parse(json.text)
+ expect(jsonObj.items.length).to.be.equal(1)
+ expect(jsonObj.items[ 0 ].title).to.equal('user video')
+ expect(jsonObj.items[ 0 ].author.name).to.equal('john')
+ }
+
for (const server of servers) {
{
- const json = await getJSONfeed(server.url, 'videos', { accountId: rootAccountUUID })
+ const json = await getJSONfeed(server.url, 'videos', { accountName: 'root@localhost:' + servers[0].port })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
- expect(jsonObj.items[ 0 ].author.name).to.equal('root')
}
{
- const json = await getJSONfeed(server.url, 'videos', { accountId: userAccountUUID })
+ const json = await getJSONfeed(server.url, 'videos', { accountName: 'john@localhost:' + servers[0].port })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
expect(jsonObj.items[ 0 ].title).to.equal('user video')
- expect(jsonObj.items[ 0 ].author.name).to.equal('john')
}
}
+ })
+ it('Should filter by video channel', async function () {
{
- const json = await getJSONfeed(servers[0].url, 'videos', { accountName: 'root' })
+ const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: rootChannelId })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
+ expect(jsonObj.items[ 0 ].author.name).to.equal('root')
}
{
- const json = await getJSONfeed(servers[0].url, 'videos', { accountName: 'john' })
+ const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: userChannelId })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
expect(jsonObj.items[ 0 ].title).to.equal('user video')
+ expect(jsonObj.items[ 0 ].author.name).to.equal('john')
}
- })
- it('Should filter by video channel', async function () {
for (const server of servers) {
{
- const json = await getJSONfeed(server.url, 'videos', { videoChannelId: rootChannelUUID })
+ const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'root_channel@localhost:' + servers[0].port })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
- expect(jsonObj.items[ 0 ].author.name).to.equal('root')
}
{
- const json = await getJSONfeed(server.url, 'videos', { videoChannelId: userChannelUUID })
+ const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'john_channel@localhost:' + servers[0].port })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
expect(jsonObj.items[ 0 ].title).to.equal('user video')
- expect(jsonObj.items[ 0 ].author.name).to.equal('john')
}
}
-
- {
- const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelName: 'root_channel' })
- const jsonObj = JSON.parse(json.text)
- expect(jsonObj.items.length).to.be.equal(1)
- expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
- }
-
- {
- const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelName: 'john_channel' })
- const jsonObj = JSON.parse(json.text)
- expect(jsonObj.items.length).to.be.equal(1)
- expect(jsonObj.items[ 0 ].title).to.equal('user video')
- }
})
})
--- /dev/null
+{
+ "name": "@peertube/cli",
+ "version": "1.0.0",
+ "private": true,
+ "dependencies": {
+ "application-config": "^1.0.1",
+ "webtorrent-hybrid": "^2.1.0"
+ },
+ "summon": {
+ "silent": true
+ }
+}
import * as program from 'commander'
-import * as summon from 'summon-install'
import { join } from 'path'
import { execSync } from 'child_process'
-import { root } from '../helpers/core-utils'
-
-let videoURL
program
.name('watch')
.arguments('<url>')
- .option('-g, --gui <player>', 'player type', /^(airplay|stdout|chromecast|mpv|vlc|mplayer|ascii|xbmc)$/i, 'ascii')
- .option('-i, --invert', 'invert colors (ascii player only)', true)
- .option('-r, --resolution <res>', 'video resolution', /^(240|360|720|1080)$/i, '720')
+ .option('-g, --gui <player>', 'player type', /^(airplay|stdout|chromecast|mpv|vlc|mplayer|xbmc)$/i, 'vlc')
+ .option('-r, --resolution <res>', 'video resolution', '480')
.on('--help', function () {
console.log(' Available Players:')
console.log()
- console.log(' - ascii')
console.log(' - mpv')
console.log(' - mplayer')
console.log(' - vlc')
console.log(' - airplay')
console.log(' - chromecast')
console.log()
- console.log(' Note: \'ascii\' is the only option not using WebTorrent and not seeding back the video.')
console.log()
console.log(' Examples:')
console.log()
console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10')
console.log()
})
- .action((url) => {
- videoURL = url
+ .action((url, cmd) => {
+ run(url, cmd)
+ .catch(err => {
+ console.error(err)
+ process.exit(-1)
+ })
})
.parse(process.argv)
-if (!videoURL) {
- console.error('<url> positional argument is required.')
- process.exit(-1)
-} else { program['url'] = videoURL }
+async function run (url: string, program: any) {
+ if (!url) {
+ console.error('<url> positional argument is required.')
+ process.exit(-1)
+ }
-handler(program)
+ const cmd = 'node ' + join(__dirname, 'node_modules', 'webtorrent-hybrid', 'bin', 'cmd.js')
+ const args = ` --${program.gui} ` +
+ url.replace('videos/watch', 'download/torrents') +
+ `-${program.resolution}.torrent`
-function handler (argv) {
- if (argv['gui'] === 'ascii') {
- summon('peerterminal')
- const peerterminal = summon('peerterminal')
- peerterminal([ '--link', videoURL, '--invert', argv['invert'] ])
- } else {
- summon('webtorrent-hybrid')
- const CMD = 'node ' + join(root(), 'node_modules', 'webtorrent-hybrid', 'bin', 'cmd.js')
- const CMDargs = ` --${argv.gui} ` +
- argv['url'].replace('videos/watch', 'download/torrents') +
- `-${argv.resolution}.torrent`
- execSync(CMD + CMDargs)
- }
+ execSync(cmd + args)
}
--- /dev/null
+{
+ "extends": "../../tsconfig.json",
+ "exclude": [ ] // Overwrite exclude property
+}
--- /dev/null
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+abbrev@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+ integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+
+addr-to-ip-port@^1.0.1, addr-to-ip-port@^1.4.2:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/addr-to-ip-port/-/addr-to-ip-port-1.5.1.tgz#bfada13fd6aeeeac19f1e9f7d84b4bbab45e5208"
+ integrity sha512-bA+dyydTNuQtrEDJ0g9eR7XabNhvrM5yZY0hvTbNK3yvoeC73ZqMES6E1cEqH9WPxs4uMtMsOjfwS4FmluhsAA==
+
+airplay-js@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/airplay-js/-/airplay-js-0.3.0.tgz#16bac2ef91b31249382924bfdeeabaddc9db7398"
+ integrity sha1-FrrC75GzEkk4KSS/3uq63cnbc5g=
+ dependencies:
+ mdns-js "0.5.0"
+ plist-with-patches "0.5.1"
+
+ansi-regex@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+ integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
+
+ansi-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
+ integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
+
+application-config-path@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/application-config-path/-/application-config-path-0.1.0.tgz#193c5f0a86541a4c66fba1e2dc38583362ea5e8f"
+ integrity sha1-GTxfCoZUGkxm+6Hi3DhYM2LqXo8=
+
+application-config@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/application-config/-/application-config-1.0.1.tgz#5aa2e2a5ed6abd2e5d1d473d3596f574044fe9e7"
+ integrity sha1-WqLipe1qvS5dHUc9NZb1dARP6ec=
+ dependencies:
+ application-config-path "^0.1.0"
+ mkdirp "^0.5.1"
+
+aproba@^1.0.3:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
+ integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
+
+are-we-there-yet@~1.1.2:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
+ integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
+ dependencies:
+ delegates "^1.0.0"
+ readable-stream "^2.0.6"
+
+ascli@~0.3:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/ascli/-/ascli-0.3.0.tgz#5e66230e5219fe3e8952a4efb4f20fae596a813a"
+ integrity sha1-XmYjDlIZ/j6JUqTvtPIPrllqgTo=
+ dependencies:
+ colour latest
+ optjs latest
+
+async-limiter@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
+ integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==
+
+balanced-match@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+ integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+
+bencode@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/bencode/-/bencode-2.0.1.tgz#667a6a31c5e038d558608333da6b7c94e836c85b"
+ integrity sha512-2uhEl8FdjSBUyb69qDTgOEeeqDTa+n3yMQzLW0cOzNf1Ow5bwcg3idf+qsWisIKRH8Bk8oC7UXL8irRcPA8ZEQ==
+ dependencies:
+ safe-buffer "^5.1.1"
+
+binary-search@^1.3.4:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/binary-search/-/binary-search-1.3.5.tgz#479ad009589e0273cf54e5d74ab1546c489078ce"
+ integrity sha512-RHFP0AdU6KAB0CCZsRMU2CJTk2EpL8GLURT+4gilpjr1f/7M91FgUMnXuQLmf3OKLet34gjuNFwO7e4agdX5pw==
+
+bitfield@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/bitfield/-/bitfield-2.0.0.tgz#fbe6767592fe5b4c87ecf1d04126294cc1bfa837"
+ integrity sha512-4xM4DYejOHQ/qWBfeqBXNA4mJ12PwcOibFYnH1kYh5U9BHciCqEJBqGNVnMJXUhm8mflujNRLSv7IiVQxovgjw==
+
+bittorrent-dht@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/bittorrent-dht/-/bittorrent-dht-9.0.0.tgz#08d5ebb51ed91d7e3eea5c275554f4323fb523e5"
+ integrity sha512-X5ax4G/PLtEPfqOUjqDZ2nmPENndWRMK4sT2jcQ4sXor904zhR40r4KqTyTvWYAljh5/hPPqM9DCUUtqWzRXoQ==
+ dependencies:
+ bencode "^2.0.0"
+ buffer-equals "^1.0.3"
+ debug "^3.1.0"
+ inherits "^2.0.1"
+ k-bucket "^5.0.0"
+ k-rpc "^5.0.0"
+ last-one-wins "^1.0.4"
+ lru "^3.1.0"
+ randombytes "^2.0.5"
+ record-cache "^1.0.2"
+ safe-buffer "^5.0.1"
+ simple-sha1 "^2.1.0"
+
+bittorrent-peerid@^1.0.2:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/bittorrent-peerid/-/bittorrent-peerid-1.3.0.tgz#a435d3b267c887c586c528b53359845905d7c158"
+ integrity sha512-SYd5H3RbN1ex+TrWAKXkEkASFWxAR7Tk6iLt9tfAT9ehBvZb/Y3AQDVRVJynlrixcWpnmsLYKI7tkRWgp7ORoQ==
+
+bittorrent-protocol@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/bittorrent-protocol/-/bittorrent-protocol-3.0.1.tgz#d3948f4d2b09d538095f7e5f93f64ba5df6b5c2a"
+ integrity sha512-hnvOzAu9u+2H0OLLL5byoFdz6oz5f3bx5f7R+ItUohTHMq9TgUhEJfcjo7xWtQHSKOVciYWwYTJ4EjczF5RX2A==
+ dependencies:
+ bencode "^2.0.0"
+ bitfield "^2.0.0"
+ debug "^3.1.0"
+ randombytes "^2.0.5"
+ readable-stream "^2.3.2"
+ speedometer "^1.0.0"
+ unordered-array-remove "^1.0.2"
+ xtend "^4.0.0"
+
+bittorrent-tracker@^9.0.0:
+ version "9.11.0"
+ resolved "https://registry.yarnpkg.com/bittorrent-tracker/-/bittorrent-tracker-9.11.0.tgz#9911f9c14e5a29f84990a0c31b3d83dd16eb2876"
+ integrity sha512-T1zvW/kSeEnWT4I3JE+6c7aZbO5jtleZyQe911SyzIxFF9DvtUNWXud3p5ZUkXaoI2xXwfpvlks5VFj5SKEB+A==
+ dependencies:
+ bencode "^2.0.0"
+ bittorrent-peerid "^1.0.2"
+ bn.js "^4.4.0"
+ compact2string "^1.2.0"
+ debug "^4.0.1"
+ ip "^1.0.1"
+ lru "^3.0.0"
+ minimist "^1.1.1"
+ once "^1.3.0"
+ random-iterate "^1.0.1"
+ randombytes "^2.0.3"
+ run-parallel "^1.1.2"
+ run-series "^1.0.2"
+ safe-buffer "^5.0.0"
+ simple-get "^3.0.0"
+ simple-peer "^9.0.0"
+ simple-websocket "^7.0.1"
+ string2compact "^1.1.1"
+ uniq "^1.0.1"
+ unordered-array-remove "^1.0.2"
+ ws "^6.0.0"
+ optionalDependencies:
+ bufferutil "^4.0.0"
+ utf-8-validate "^5.0.1"
+
+blob-to-buffer@^1.2.6:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/blob-to-buffer/-/blob-to-buffer-1.2.8.tgz#78eeeb332f1280ed0ca6fb2b60693a8c6d36903a"
+ integrity sha512-re0AIxakF504MgeMtIyJkVcZ8T5aUxtp/QmTMlmjyb3P44E1BEv5x3LATBGApWAJATyXHtkXRD+gWTmeyYLiQA==
+
+block-stream2@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/block-stream2/-/block-stream2-1.1.0.tgz#c738e3a91ba977ebb5e1fef431e13ca11d8639e2"
+ integrity sha1-xzjjqRupd+u14f70MeE8oR2GOeI=
+ dependencies:
+ defined "^1.0.0"
+ inherits "^2.0.1"
+ readable-stream "^2.0.4"
+
+bn.js@^4.4.0:
+ version "4.11.8"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
+ integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+browserify-package-json@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/browserify-package-json/-/browserify-package-json-1.0.1.tgz#98dde8aa5c561fd6d3fe49bbaa102b74b396fdea"
+ integrity sha1-mN3oqlxWH9bT/km7qhArdLOW/eo=
+
+buffer-alloc-unsafe@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
+ integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
+
+buffer-alloc@^1.1.0, buffer-alloc@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
+ integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
+ dependencies:
+ buffer-alloc-unsafe "^1.1.0"
+ buffer-fill "^1.0.0"
+
+buffer-equals@^1.0.3, buffer-equals@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/buffer-equals/-/buffer-equals-1.0.4.tgz#0353b54fd07fd9564170671ae6f66b9cf10d27f5"
+ integrity sha1-A1O1T9B/2VZBcGca5vZrnPENJ/U=
+
+buffer-fill@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
+ integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
+
+buffer-from@^1.0.0, buffer-from@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
+ integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
+
+buffer-indexof@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c"
+ integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==
+
+bufferutil@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.1.tgz#3a177e8e5819a1243fe16b63a199951a7ad8d4a7"
+ integrity sha512-xowrxvpxojqkagPcWRQVXZl0YXhRhAtBEIq3VoER1NH5Mw1n1o0ojdspp+GS2J//2gCVyrzQDApQ4unGF+QOoA==
+ dependencies:
+ node-gyp-build "~3.7.0"
+
+bufferview@~1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/bufferview/-/bufferview-1.0.1.tgz#7afd74a45f937fa422a1d338c08bbfdc76cd725d"
+ integrity sha1-ev10pF+Tf6QiodM4wIu/3HbNcl0=
+
+"bytebuffer@~3 >=3.5":
+ version "3.5.5"
+ resolved "https://registry.yarnpkg.com/bytebuffer/-/bytebuffer-3.5.5.tgz#7a6faf1a13514b083f1fcf9541c4c9bfbe7e7fd3"
+ integrity sha1-em+vGhNRSwg/H8+VQcTJv75+f9M=
+ dependencies:
+ bufferview "~1"
+ long "~2 >=2.2.3"
+
+camelcase@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+ integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
+
+castv2-client@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/castv2-client/-/castv2-client-1.2.0.tgz#a9193b1a5448b8cb9a0415bd021c8811ed7b0544"
+ integrity sha1-qRk7GlRIuMuaBBW9AhyIEe17BUQ=
+ dependencies:
+ castv2 "~0.1.4"
+ debug "^2.2.0"
+
+castv2@~0.1.4:
+ version "0.1.9"
+ resolved "https://registry.yarnpkg.com/castv2/-/castv2-0.1.9.tgz#d0b0fab1fd06b0d9cca636886716ec1293a5905a"
+ integrity sha1-0LD6sf0GsNnMpjaIZxbsEpOlkFo=
+ dependencies:
+ debug "^2.2.0"
+ protobufjs "^3.2.2"
+
+chownr@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
+ integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==
+
+chromecasts@^1.5.3:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/chromecasts/-/chromecasts-1.9.1.tgz#67b162e8414d57d6106c49fe4a0e9b08f20bbd12"
+ integrity sha512-nsXv7ufgrpC8s5DUm6FJEa2XJ2VvE9FmbTVi6r4zGreTFTTSRSJjvqVEqLUFX/fGo/zbSre3zdoV+Pu9DGLz0A==
+ dependencies:
+ castv2-client "^1.1.0"
+ debug "^2.1.3"
+ dns-txt "^2.0.2"
+ mime "^1.3.4"
+ multicast-dns "^6.0.1"
+ simple-get "^2.0.0"
+ thunky "^0.1.0"
+ xml2js "^0.4.8"
+ optionalDependencies:
+ node-ssdp "^2.2.0"
+
+chunk-store-stream@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/chunk-store-stream/-/chunk-store-stream-3.0.1.tgz#8e0d739226dcb386f44447b82a005b597a1d41d9"
+ integrity sha512-GA1NIFDZKElhkjiO6QOyzfK1QbUt6M3gFhUU/aR05JYaDqXbU5d7U92cLvGKdItJEDfojky6NQefy5VL5PpDBA==
+ dependencies:
+ block-stream2 "^1.0.0"
+ readable-stream "^2.0.5"
+
+cliui@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+ integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
+ dependencies:
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+ wrap-ansi "^2.0.0"
+
+clivas@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/clivas/-/clivas-0.2.0.tgz#b8d19188b3243e390f302410bd0cb1622db82649"
+ integrity sha1-uNGRiLMkPjkPMCQQvQyxYi24Jkk=
+
+closest-to@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/closest-to/-/closest-to-2.0.0.tgz#bb2a860edb7769b62d04821748ae50da24dbefaa"
+ integrity sha1-uyqGDtt3abYtBIIXSK5Q2iTb76o=
+
+code-point-at@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+ integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
+
+colour@latest:
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778"
+ integrity sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=
+
+compact2string@^1.2.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/compact2string/-/compact2string-1.4.1.tgz#8d34929055f8300a13cfc030ad1832e2e53c2e25"
+ integrity sha512-3D+EY5nsRhqnOwDxveBv5T8wGo4DEvYxjDtPGmdOX+gfr5gE92c2RC0w2wa+xEefm07QuVqqcF3nZJUZ92l/og==
+ dependencies:
+ ipaddr.js ">= 0.1.5"
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+
+concat-stream@^1.4.8:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
+ integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
+ dependencies:
+ buffer-from "^1.0.0"
+ inherits "^2.0.3"
+ readable-stream "^2.2.2"
+ typedarray "^0.0.6"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+ integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
+
+core-util-is@~1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+ integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
+
+create-torrent@^3.23.1, create-torrent@^3.33.0:
+ version "3.33.0"
+ resolved "https://registry.yarnpkg.com/create-torrent/-/create-torrent-3.33.0.tgz#8a7a2aa2213a799c266c40e4c12f1468ede25105"
+ integrity sha512-KMd0KuvwVUg1grlRd5skG9ZkSbBYDDkAjDUMLnvxdRn0rL7ph3IwoOk7I8u1yLX4HYjGiLVlWYO55YWNNPjJFA==
+ dependencies:
+ bencode "^2.0.0"
+ block-stream2 "^1.0.0"
+ filestream "^4.0.0"
+ flatten "^1.0.2"
+ is-file "^1.0.0"
+ junk "^2.1.0"
+ minimist "^1.1.0"
+ multistream "^2.0.2"
+ once "^1.3.0"
+ piece-length "^1.0.0"
+ readable-stream "^3.0.2"
+ run-parallel "^1.0.0"
+ simple-sha1 "^2.0.0"
+
+debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+debug@^3.1.0, debug@^3.2.6:
+ version "3.2.6"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
+ integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
+ dependencies:
+ ms "^2.1.1"
+
+debug@^4.0.1, debug@^4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
+ integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
+ dependencies:
+ ms "^2.1.1"
+
+decamelize@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+ integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+
+decompress-response@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
+ integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
+ dependencies:
+ mimic-response "^1.0.0"
+
+deep-extend@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+ integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
+defined@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
+ integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=
+
+delegates@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+ integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
+
+detect-libc@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+ integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
+
+dlnacasts@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/dlnacasts/-/dlnacasts-0.1.0.tgz#f805211dcac74f6bb3a4d5d5541ad783b1b67d22"
+ integrity sha1-+AUhHcrHT2uzpNXVVBrXg7G2fSI=
+ dependencies:
+ debug "^2.1.3"
+ mime "^1.3.4"
+ node-ssdp "^2.7.1"
+ run-parallel "^1.1.6"
+ simple-get "^2.1.0"
+ thunky "^0.1.0"
+ upnp-mediarenderer-client "^1.2.2"
+ xml2js "^0.4.8"
+
+dns-packet@^1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a"
+ integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==
+ dependencies:
+ ip "^1.1.0"
+ safe-buffer "^5.0.1"
+
+dns-txt@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6"
+ integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=
+ dependencies:
+ buffer-indexof "^1.0.0"
+
+domexception@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90"
+ integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==
+ dependencies:
+ webidl-conversions "^4.0.2"
+
+ecstatic@^3.0.0:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.2.tgz#6d1dd49814d00594682c652adb66076a69d46c48"
+ integrity sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==
+ dependencies:
+ he "^1.1.1"
+ mime "^1.6.0"
+ minimist "^1.1.0"
+ url-join "^2.0.5"
+
+elementtree@^0.1.6, elementtree@~0.1.6:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/elementtree/-/elementtree-0.1.7.tgz#9ac91be6e52fb6e6244c4e54a4ac3ed8ae8e29c0"
+ integrity sha1-mskb5uUvtuYkTE5UpKw+2K6OKcA=
+ dependencies:
+ sax "1.1.4"
+
+end-of-stream@^1.1.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
+ integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
+ dependencies:
+ once "^1.4.0"
+
+error-ex@^1.2.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+ integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+ dependencies:
+ is-arrayish "^0.2.1"
+
+executable@^4.0.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c"
+ integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==
+ dependencies:
+ pify "^2.2.0"
+
+filestream@^4.0.0:
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/filestream/-/filestream-4.1.3.tgz#948fcaade8221f715f5ecaddc54862faaacc9325"
+ integrity sha1-lI/KregiH3FfXsrdxUhi+qrMkyU=
+ dependencies:
+ inherits "^2.0.1"
+ readable-stream "^2.0.5"
+ typedarray-to-buffer "^3.0.0"
+ xtend "^4.0.1"
+
+find-up@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+ integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
+ dependencies:
+ path-exists "^2.0.0"
+ pinkie-promise "^2.0.0"
+
+flatten@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
+ integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=
+
+fs-chunk-store@^1.6.2:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/fs-chunk-store/-/fs-chunk-store-1.7.0.tgz#1c4bcbe93c99af10aa04b65348f2bb27377a4010"
+ integrity sha512-KhjJmZAs2eqfhCb6PdPx4RcZtheGTz86tpTC5JTvqBn/xda+Nb+0C7dCyjOSN7T76H6a56LvH0SVXQMchLXDRw==
+ dependencies:
+ mkdirp "^0.5.1"
+ random-access-file "^2.0.1"
+ randombytes "^2.0.3"
+ rimraf "^2.4.2"
+ run-parallel "^1.1.2"
+ thunky "^1.0.1"
+
+fs-minipass@^1.2.5:
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07"
+ integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==
+ dependencies:
+ minipass "^2.2.1"
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+
+gauge@~2.7.3:
+ version "2.7.4"
+ resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+ integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
+ dependencies:
+ aproba "^1.0.3"
+ console-control-strings "^1.0.0"
+ has-unicode "^2.0.0"
+ object-assign "^4.1.0"
+ signal-exit "^3.0.0"
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+ wide-align "^1.1.0"
+
+get-browser-rtc@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/get-browser-rtc/-/get-browser-rtc-1.0.2.tgz#bbcd40c8451a7ed4ef5c373b8169a409dd1d11d9"
+ integrity sha1-u81AyEUaftTvXDc7gWmkCd0dEdk=
+
+get-caller-file@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
+ integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
+
+get-stdin@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
+ integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
+
+glob@^7.1.3:
+ version "7.1.4"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
+ integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+graceful-fs@^4.1.2:
+ version "4.1.15"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
+ integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
+
+has-unicode@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+ integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
+
+he@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+ integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
+hosted-git-info@^2.1.4:
+ version "2.7.1"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
+ integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==
+
+iconv-lite@^0.4.4:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+ignore-walk@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
+ integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==
+ dependencies:
+ minimatch "^3.0.4"
+
+immediate-chunk-store@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/immediate-chunk-store/-/immediate-chunk-store-2.0.0.tgz#f313fd0cc71396d8911ad031179e1cccfda3da18"
+ integrity sha512-5s6NiCGbtWc+OQA60jrre54w12U7tynIyUNjO5LJjNA5lWwvCv6640roq8Wk/wIuaqnd4Pgtp453OyJ7hbONkQ==
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+ integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
+
+ini@~1.3.0:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
+ integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
+
+invert-kv@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+ integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
+
+ip-set@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/ip-set/-/ip-set-1.0.2.tgz#be4f119f82c124836455993dfcd554639c7007de"
+ integrity sha512-Mb6kv78bTi4RNAIIWL8Bbre7hXOR2pNUi3j8FaQkLaitf/ZWxkq3/iIwXNYk2ACO3IMfdVdQrOkUtwZblO7uBA==
+ dependencies:
+ ip "^1.1.3"
+
+ip@^1.0.1, ip@^1.1.0, ip@^1.1.3:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
+ integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
+
+"ipaddr.js@>= 0.1.5", ipaddr.js@^1.0.1:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
+ integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
+
+is-arrayish@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+ integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
+
+is-ascii@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-ascii/-/is-ascii-1.0.0.tgz#f02ad0259a0921cd199ff21ce1b09e0f6b4e3929"
+ integrity sha1-8CrQJZoJIc0Zn/Ic4bCeD2tOOSk=
+
+is-file@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-file/-/is-file-1.0.0.tgz#28a44cfbd9d3db193045f22b65fce8edf9620596"
+ integrity sha1-KKRM+9nT2xkwRfIrZfzo7fliBZY=
+
+is-fullwidth-code-point@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+ integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+ integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
+
+is-typedarray@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+ integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
+
+is-utf8@^0.2.0:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+ integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
+
+isarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+ integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+
+junk@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/junk/-/junk-2.1.0.tgz#f431b4b7f072dc500a5f10ce7f4ec71930e70134"
+ integrity sha1-9DG0t/By3FAKXxDOf07HGTDnATQ=
+
+k-bucket@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/k-bucket/-/k-bucket-4.0.1.tgz#3fc2e5693f0b7bff90d7b6b476edd6087955d542"
+ integrity sha512-YvDpmY3waI999h1zZoW1rJ04fZrgZ+5PAlVmvwDHT6YO/Q1AOhdel07xsKy9eAvJjQ9xZV1wz3rXKqEfaWvlcQ==
+ dependencies:
+ inherits "^2.0.1"
+ randombytes "^2.0.3"
+
+k-bucket@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/k-bucket/-/k-bucket-5.0.0.tgz#ef7a401fcd4c37cd31dceaa6ae4440ca91055e01"
+ integrity sha512-r/q+wV/Kde62/tk+rqyttEJn6h0jR7x+incdMVSYTqK73zVxVrzJa70kJL49cIKen8XjIgUZKSvk8ktnrQbK4w==
+ dependencies:
+ randombytes "^2.0.3"
+
+k-rpc-socket@^1.7.2:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/k-rpc-socket/-/k-rpc-socket-1.8.0.tgz#9a4dd6a4f3795ed847ffa156579cc389990bd1f2"
+ integrity sha512-f/9TynsO8YYjZ6JjNNtSSH7CJcIHcio1buy3zqByGxb/GX8AWLdL6FZEWTrN8V3/J7W4/E0ZTQQ+Jt2rVq7ELg==
+ dependencies:
+ bencode "^2.0.0"
+ buffer-equals "^1.0.4"
+ safe-buffer "^5.1.1"
+
+k-rpc@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/k-rpc/-/k-rpc-5.0.0.tgz#a72651860c96db440579e4c9f38dce8a42b481a8"
+ integrity sha512-vCH2rQdfMOS+MlUuTSuar1pS2EMrltURf9LmAR9xR6Jik0XPlMX3vEixgqMn17wKmFVCublJqSJ4hJIP7oKZ3Q==
+ dependencies:
+ buffer-equals "^1.0.3"
+ k-bucket "^4.0.0"
+ k-rpc-socket "^1.7.2"
+ randombytes "^2.0.5"
+ safe-buffer "^5.1.1"
+
+last-one-wins@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/last-one-wins/-/last-one-wins-1.0.4.tgz#c1bfd0cbcb46790ec9156b8d1aee8fcb86cda22a"
+ integrity sha1-wb/Qy8tGeQ7JFWuNGu6Py4bNoio=
+
+lcid@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+ integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
+ dependencies:
+ invert-kv "^1.0.0"
+
+load-ip-set@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/load-ip-set/-/load-ip-set-2.1.0.tgz#2d50b737cae41de4e413d213991d4083a3e1784b"
+ integrity sha512-taz7U6B+F7Zq90dfIKwqsB1CrFKelSEmMGC68OUqem8Cgd1QZygQBYb2Fk9i6muBSfH4xwF/Pjt4KKlAdOyWZw==
+ dependencies:
+ ip-set "^1.0.0"
+ netmask "^1.0.6"
+ once "^1.3.0"
+ simple-get "^3.0.0"
+ split "^1.0.0"
+
+load-json-file@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+ integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
+ dependencies:
+ graceful-fs "^4.1.2"
+ parse-json "^2.2.0"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+ strip-bom "^2.0.0"
+
+"long@~2 >=2.2.3":
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/long/-/long-2.4.0.tgz#9fa180bb1d9500cdc29c4156766a1995e1f4524f"
+ integrity sha1-n6GAux2VAM3CnEFWdmoZleH0Uk8=
+
+lru@^3.0.0, lru@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/lru/-/lru-3.1.0.tgz#ea7fb8546d83733396a13091d76cfeb4c06837d5"
+ integrity sha1-6n+4VG2DczOWoTCR12z+tMBoN9U=
+ dependencies:
+ inherits "^2.0.1"
+
+magnet-uri@^5.1.3:
+ version "5.2.4"
+ resolved "https://registry.yarnpkg.com/magnet-uri/-/magnet-uri-5.2.4.tgz#7afe5b736af04445aff744c93a890a3710077688"
+ integrity sha512-VYaJMxhr8B9BrCiNINUsuhaEe40YnG+AQBwcqUKO66lSVaI9I3A1iH/6EmEwRI8OYUg5Gt+4lLE7achg676lrg==
+ dependencies:
+ thirty-two "^1.0.1"
+ uniq "^1.0.1"
+
+mdns-js-packet@~0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/mdns-js-packet/-/mdns-js-packet-0.2.0.tgz#642409e8183c7561cc60615bbd1420ec2fad7616"
+ integrity sha1-ZCQJ6Bg8dWHMYGFbvRQg7C+tdhY=
+ dependencies:
+ debug "^2.1.0"
+ qap "^3.1.2"
+
+mdns-js@0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/mdns-js/-/mdns-js-0.5.0.tgz#4c8abb6ba7cabdc892d39228c3faa2556e09cf87"
+ integrity sha1-TIq7a6fKvciS05Iow/qiVW4Jz4c=
+ dependencies:
+ debug "^2.1.1"
+ mdns-js-packet "~0.2.0"
+ semver "~5.1.0"
+
+mediasource@^2.1.0, mediasource@^2.2.2:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/mediasource/-/mediasource-2.3.0.tgz#4c7b49e7ea4fb88f1cc181d8fcf0d94649271dc6"
+ integrity sha512-fqm86UwHvAnneIv40Uy1sDQaFtAByq/k0SQ3uCtbnEeSQNT1s5TDHCZOD1VmYCHwfY1jL2NjoZVwzZKYqy3L7A==
+ dependencies:
+ inherits "^2.0.1"
+ readable-stream "^3.0.0"
+ to-arraybuffer "^1.0.1"
+
+memory-chunk-store@^1.2.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/memory-chunk-store/-/memory-chunk-store-1.3.0.tgz#ae99e7e3b58b52db43d49d94722930d39459d0c4"
+ integrity sha512-6LsOpHKKhxYrLhHmOJdBCUtSO7op5rUs1pag0fhjHo0QiXRyna0bwYf4EmQuL7InUeF2J7dUMPr6VMogRyf9NA==
+
+mime@^1.3.4, mime@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+ integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
+mime@^2.1.0, mime@^2.4.0:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.3.tgz#229687331e86f68924e6cb59e1cdd937f18275fe"
+ integrity sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==
+
+mimic-response@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
+ integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
+
+minimatch@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimist@0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+ integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
+
+minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+ integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
+
+minipass@^2.2.1, minipass@^2.3.4:
+ version "2.3.5"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848"
+ integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==
+ dependencies:
+ safe-buffer "^5.1.2"
+ yallist "^3.0.0"
+
+minizlib@^1.1.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614"
+ integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==
+ dependencies:
+ minipass "^2.2.1"
+
+mkdirp@^0.5.0, mkdirp@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+ integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
+ dependencies:
+ minimist "0.0.8"
+
+moment@^2.12.0:
+ version "2.24.0"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
+ integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
+
+mp4-box-encoding@^1.1.0, mp4-box-encoding@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/mp4-box-encoding/-/mp4-box-encoding-1.3.0.tgz#2a6f750947ff68c3a498fd76cd6424c53d995d48"
+ integrity sha512-U4pMLpjT/UzB8d36dxj6Mf1bG9xypEvgbuRIa1fztRXNKKTCAtRxsnFZhNOd7YDFOKtjBgssYGvo4H/Q3ZY1MA==
+ dependencies:
+ buffer-alloc "^1.2.0"
+ buffer-from "^1.1.0"
+ uint64be "^2.0.2"
+
+mp4-stream@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/mp4-stream/-/mp4-stream-2.0.3.tgz#30acee07709d323f8dcd87a07b3ce9c3c4bfb364"
+ integrity sha512-5NzgI0+bGakoZEwnIYINXqB3mnewkt3Y7jcvkXsTubnCNUSdM8cpP0Vemxf6FLg0qUN8fydTgNMVAc3QU8B92g==
+ dependencies:
+ buffer-alloc "^1.1.0"
+ inherits "^2.0.1"
+ mp4-box-encoding "^1.1.0"
+ next-event "^1.0.0"
+ readable-stream "^2.0.3"
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+
+ms@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
+ integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
+
+multicast-dns@^6.0.1:
+ version "6.2.3"
+ resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229"
+ integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==
+ dependencies:
+ dns-packet "^1.3.1"
+ thunky "^1.0.2"
+
+multistream@^2.0.2, multistream@^2.0.5:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/multistream/-/multistream-2.1.1.tgz#629d3a29bd76623489980d04519a2c365948148c"
+ integrity sha512-xasv76hl6nr1dEy3lPvy7Ej7K/Lx3O/FCvwge8PeVJpciPPoNCbaANcNiBug3IpdvTveZUcAV0DJzdnUDMesNQ==
+ dependencies:
+ inherits "^2.0.1"
+ readable-stream "^2.0.5"
+
+nan@*, nan@^2.3.2:
+ version "2.14.0"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
+ integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
+
+needle@^2.2.1:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
+ integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==
+ dependencies:
+ debug "^3.2.6"
+ iconv-lite "^0.4.4"
+ sax "^1.2.4"
+
+netmask@^1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35"
+ integrity sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=
+
+network-address@^1.0.0, network-address@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/network-address/-/network-address-1.1.2.tgz#4aa7bfd43f03f0b81c9702b13d6a858ddb326f3e"
+ integrity sha1-Sqe/1D8D8LgclwKxPWqFjdsybz4=
+
+next-event@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/next-event/-/next-event-1.0.0.tgz#e7778acde2e55802e0ad1879c39cf6f75eda61d8"
+ integrity sha1-53eKzeLlWALgrRh5w5z2917aYdg=
+
+node-cmake@2.3.2:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/node-cmake/-/node-cmake-2.3.2.tgz#e0fbc54b11405b07705e4d6d41865ae95ad289d0"
+ integrity sha1-4PvFSxFAWwdwXk1tQYZa6VrSidA=
+ dependencies:
+ nan "*"
+ which "^1.2.14"
+ yargs "^7.0.2"
+
+node-gyp-build@~3.7.0:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d"
+ integrity sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w==
+
+node-pre-gyp@0.11.x:
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054"
+ integrity sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==
+ dependencies:
+ detect-libc "^1.0.2"
+ mkdirp "^0.5.1"
+ needle "^2.2.1"
+ nopt "^4.0.1"
+ npm-packlist "^1.1.6"
+ npmlog "^4.0.2"
+ rc "^1.2.7"
+ rimraf "^2.6.1"
+ semver "^5.3.0"
+ tar "^4"
+
+node-ssdp@^2.2.0, node-ssdp@^2.7.1:
+ version "2.9.1"
+ resolved "https://registry.yarnpkg.com/node-ssdp/-/node-ssdp-2.9.1.tgz#2d6ba8e7eff9bf5b338564f91f7ac5d5cdddc55b"
+ integrity sha1-LWuo5+/5v1szhWT5H3rF1c3dxVs=
+ dependencies:
+ debug "^2.2.0"
+ ip "^1.0.1"
+
+nodebmc@0.0.7:
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/nodebmc/-/nodebmc-0.0.7.tgz#fae179165265509302cefbebeabd29bd4035184d"
+ integrity sha1-+uF5FlJlUJMCzvvr6r0pvUA1GE0=
+ dependencies:
+ mdns-js "0.5.0"
+
+nopt@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+ integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
+ dependencies:
+ abbrev "1"
+ osenv "^0.1.4"
+
+normalize-package-data@^2.3.2:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+ integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
+ dependencies:
+ hosted-git-info "^2.1.4"
+ resolve "^1.10.0"
+ semver "2 || 3 || 4 || 5"
+ validate-npm-package-license "^3.0.1"
+
+npm-bundled@^1.0.1:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd"
+ integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
+
+npm-packlist@^1.1.6:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc"
+ integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==
+ dependencies:
+ ignore-walk "^3.0.1"
+ npm-bundled "^1.0.1"
+
+npmlog@^4.0.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
+ integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
+ dependencies:
+ are-we-there-yet "~1.1.2"
+ console-control-strings "~1.1.0"
+ gauge "~2.7.3"
+ set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+ integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
+
+object-assign@^4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
+
+once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+ dependencies:
+ wrappy "1"
+
+open@0.0.5:
+ version "0.0.5"
+ resolved "https://registry.yarnpkg.com/open/-/open-0.0.5.tgz#42c3e18ec95466b6bf0dc42f3a2945c3f0cad8fc"
+ integrity sha1-QsPhjslUZra/DcQvOilFw/DK2Pw=
+
+optjs@latest:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/optjs/-/optjs-3.2.2.tgz#69a6ce89c442a44403141ad2f9b370bd5bb6f4ee"
+ integrity sha1-aabOicRCpEQDFBrS+bNwvVu29O4=
+
+os-homedir@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+ integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
+
+os-locale@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+ integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=
+ dependencies:
+ lcid "^1.0.0"
+
+os-tmpdir@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+ integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
+
+osenv@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
+ integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
+ dependencies:
+ os-homedir "^1.0.0"
+ os-tmpdir "^1.0.0"
+
+package-json-versionify@^1.0.2:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/package-json-versionify/-/package-json-versionify-1.0.4.tgz#5860587a944873a6b7e6d26e8e51ffb22315bf17"
+ integrity sha1-WGBYepRIc6a35tJujlH/siMVvxc=
+ dependencies:
+ browserify-package-json "^1.0.0"
+
+parse-json@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+ integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
+ dependencies:
+ error-ex "^1.2.0"
+
+parse-numeric-range@^0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-0.0.2.tgz#b4f09d413c7adbcd987f6e9233c7b4b210c938e4"
+ integrity sha1-tPCdQTx6282Yf26SM8e0shDJOOQ=
+
+parse-torrent@^6.0.0, parse-torrent@^6.1.2:
+ version "6.1.2"
+ resolved "https://registry.yarnpkg.com/parse-torrent/-/parse-torrent-6.1.2.tgz#99da5bdd23435a1cb7e8e7a63847c4efb21b1956"
+ integrity sha512-Z/vig84sHwtrTEbOzisT4xnYTFlOgAaLQccPruMPgRahZUppVE/BUXzAos3jZM7c64o0lfukQdQ4ozWa5lN39w==
+ dependencies:
+ bencode "^2.0.0"
+ blob-to-buffer "^1.2.6"
+ get-stdin "^6.0.0"
+ magnet-uri "^5.1.3"
+ simple-get "^3.0.1"
+ simple-sha1 "^2.0.0"
+ uniq "^1.0.1"
+
+path-exists@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+ integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
+ dependencies:
+ pinkie-promise "^2.0.0"
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+
+path-parse@^1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
+ integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+
+path-type@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+ integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
+ dependencies:
+ graceful-fs "^4.1.2"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+
+piece-length@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/piece-length/-/piece-length-1.0.0.tgz#4db7167157fd69fef14caf7262cd39f189b24508"
+ integrity sha1-TbcWcVf9af7xTK9yYs058YmyRQg=
+ dependencies:
+ closest-to "~2.0.0"
+
+pify@^2.0.0, pify@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+ integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
+
+pinkie-promise@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+ integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
+ dependencies:
+ pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+ integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
+
+plist-with-patches@0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/plist-with-patches/-/plist-with-patches-0.5.1.tgz#868aae2e0df8989b026562b35cbc19cfd8bb780d"
+ integrity sha1-hoquLg34mJsCZWKzXLwZz9i7eA0=
+ dependencies:
+ xmlbuilder "0.4.x"
+ xmldom "0.1.x"
+
+prettier-bytes@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/prettier-bytes/-/prettier-bytes-1.0.4.tgz#994b02aa46f699c50b6257b5faaa7fe2557e62d6"
+ integrity sha1-mUsCqkb2mcULYle1+qp/4lV+YtY=
+
+process-nextick-args@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
+ integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
+
+protobufjs@^3.2.2:
+ version "3.8.2"
+ resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-3.8.2.tgz#bc826e34c3af4697e8d0af7a669e4d612aedcd17"
+ integrity sha1-vIJuNMOvRpfo0K96Zp5NYSrtzRc=
+ dependencies:
+ ascli "~0.3"
+ bytebuffer "~3 >=3.5"
+
+pump@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+ integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
+qap@^3.1.2:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/qap/-/qap-3.3.1.tgz#11f9e8fa8890fe7cb99210c0f44d0613b7372cac"
+ integrity sha1-Efno+oiQ/ny5khDA9E0GE7c3LKw=
+
+random-access-file@^2.0.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/random-access-file/-/random-access-file-2.1.2.tgz#eeb32e50b9831f32060516862381152ae4e05aa6"
+ integrity sha512-dZo7HEcEPbZ/6XLXC4GXypiWvFbXVkdeMrJTi0B94pBJwddt/AvJh8GaQhso6KGYROGYCI/VWdHbmRDtkwT9pQ==
+ dependencies:
+ mkdirp "^0.5.1"
+ random-access-storage "^1.1.1"
+
+random-access-storage@^1.1.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/random-access-storage/-/random-access-storage-1.3.0.tgz#d27e4d897b79dc4358afc2bbe553044e5c8cfe35"
+ integrity sha512-pdS9Mcb9TB7oICypPRALlheaSuszuAKmLVEPKJMuYor7R/zDuHh5ALuQoS+ox31XRwQUL+tDwWH2GPdyspwelA==
+ dependencies:
+ inherits "^2.0.3"
+
+random-iterate@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/random-iterate/-/random-iterate-1.0.1.tgz#f7d97d92dee6665ec5f6da08c7f963cad4b2ac99"
+ integrity sha1-99l9kt7mZl7F9toIx/ljytSyrJk=
+
+randombytes@^2.0.3, randombytes@^2.0.5:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+ integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+ dependencies:
+ safe-buffer "^5.1.0"
+
+range-parser@^1.2.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+range-slice-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/range-slice-stream/-/range-slice-stream-2.0.0.tgz#1f25fc7a2cacf9ccd140c46f9cf670a1a7fe3ce6"
+ integrity sha512-PPYLwZ63lXi6Tv2EZ8w3M4FzC0rVqvxivaOVS8pXSp5FMIHFnvi4MWHL3UdFLhwSy50aNtJsgjY0mBC6oFL26Q==
+ dependencies:
+ readable-stream "^3.0.2"
+
+rc@^1.2.7:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+ integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+ dependencies:
+ deep-extend "^0.6.0"
+ ini "~1.3.0"
+ minimist "^1.2.0"
+ strip-json-comments "~2.0.1"
+
+read-pkg-up@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+ integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
+ dependencies:
+ find-up "^1.0.0"
+ read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+ integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
+ dependencies:
+ load-json-file "^1.0.0"
+ normalize-package-data "^2.3.2"
+ path-type "^1.0.0"
+
+readable-stream@^2.0.3, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.3.2, readable-stream@^2.3.4:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
+ integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.1.1"
+ util-deprecate "~1.0.1"
+
+readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.3.0.tgz#cb8011aad002eb717bf040291feba8569c986fb9"
+ integrity sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==
+ dependencies:
+ inherits "^2.0.3"
+ string_decoder "^1.1.1"
+ util-deprecate "^1.0.1"
+
+record-cache@^1.0.2:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/record-cache/-/record-cache-1.1.0.tgz#f8a467a691a469584b26e88d36b18afdb3932037"
+ integrity sha512-u8rbtLEJV7HRacl/ZYwSBFD8NFyB3PfTTfGLP37IW3hftQCwu6z4Q2RLyxo1YJUNRTEzJfpLpGwVuEYdaIkG9Q==
+
+render-media@^3.0.0:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/render-media/-/render-media-3.1.3.tgz#aa8c8cd3f720049370067180709b551d3c566254"
+ integrity sha512-K7ziKKlIcgYpAovRsABDiSaNn7TzDDyyuFGpRwM52cloNcajInB6sCxFPUEzOuTJUeyvKCqT/k5INOjpKLCjhQ==
+ dependencies:
+ debug "^3.1.0"
+ is-ascii "^1.0.0"
+ mediasource "^2.1.0"
+ stream-to-blob-url "^2.0.0"
+ videostream "^2.5.1"
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+ integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
+
+require-main-filename@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+ integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
+
+resolve@^1.10.0:
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.0.tgz#4014870ba296176b86343d50b60f3b50609ce232"
+ integrity sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==
+ dependencies:
+ path-parse "^1.0.6"
+
+rimraf@^2.4.2, rimraf@^2.6.1:
+ version "2.6.3"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
+ integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
+ dependencies:
+ glob "^7.1.3"
+
+run-parallel-limit@^1.0.3:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.0.5.tgz#c29a4fd17b4df358cb52a8a697811a63c984f1b7"
+ integrity sha512-NsY+oDngvrvMxKB3G8ijBzIema6aYbQMD2bHOamvN52BysbIGTnEY2xsNyfrcr9GhY995/t/0nQN3R3oZvaDlg==
+
+run-parallel@^1.0.0, run-parallel@^1.1.2, run-parallel@^1.1.6:
+ version "1.1.9"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
+ integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
+
+run-series@^1.0.2:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.8.tgz#2c4558f49221e01cd6371ff4e0a1e203e460fc36"
+ integrity sha512-+GztYEPRpIsQoCSraWHDBs9WVy4eVME16zhOtDB4H9J4xN0XRhknnmLOl+4gRgZtu8dpp9N/utSPjKH/xmDzXg==
+
+rusha@^0.8.1:
+ version "0.8.13"
+ resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.13.tgz#9a084e7b860b17bff3015b92c67a6a336191513a"
+ integrity sha1-mghOe4YLF7/zAVuSxnpqM2GRUTo=
+
+safe-buffer@^5.0.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+ integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+"safer-buffer@>= 2.1.2 < 3":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+sax@1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.4.tgz#74b6d33c9ae1e001510f179a91168588f1aedaa9"
+ integrity sha1-dLbTPJrh4AFRDxeakRaFiPGu2qk=
+
+sax@>=0.6.0, sax@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
+ integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
+
+"semver@2 || 3 || 4 || 5", semver@^5.3.0:
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
+ integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
+
+semver@~5.1.0:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19"
+ integrity sha1-oykqNz5vPgeY2gsgZBuanFvEfhk=
+
+set-blocking@^2.0.0, set-blocking@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+ integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+
+signal-exit@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+ integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
+
+simple-concat@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6"
+ integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=
+
+simple-get@^2.0.0, simple-get@^2.1.0:
+ version "2.8.1"
+ resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d"
+ integrity sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==
+ dependencies:
+ decompress-response "^3.3.0"
+ once "^1.3.1"
+ simple-concat "^1.0.0"
+
+simple-get@^3.0.0, simple-get@^3.0.1:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.0.3.tgz#924528ac3f9d7718ce5e9ec1b1a69c0be4d62efa"
+ integrity sha512-Wvre/Jq5vgoz31Z9stYWPLn0PqRqmBDpFSdypAnHu5AvRVCYPRYGnvryNLiXu8GOBNDH82J2FRHUGMjjHUpXFw==
+ dependencies:
+ decompress-response "^3.3.0"
+ once "^1.3.1"
+ simple-concat "^1.0.0"
+
+simple-peer@^9.0.0:
+ version "9.3.0"
+ resolved "https://registry.yarnpkg.com/simple-peer/-/simple-peer-9.3.0.tgz#85ecb126b23d8730f3904f199db65e84141e0f4e"
+ integrity sha512-5dLDfrRomrS2LuZUuH2aO7yTGtHFEl5Eb+8ZzqM0KC0lHcYUyJudUomP9ZY/lPUKBx2broL/Eee9bQ53yycEgQ==
+ dependencies:
+ debug "^4.0.1"
+ get-browser-rtc "^1.0.0"
+ inherits "^2.0.1"
+ randombytes "^2.0.3"
+ readable-stream "^2.3.4"
+
+simple-sha1@^2.0.0, simple-sha1@^2.0.8, simple-sha1@^2.1.0:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/simple-sha1/-/simple-sha1-2.1.2.tgz#de40cbd5aae278fde8e3bb3250a35d74c67326b1"
+ integrity sha512-TQl9rm4rdKAVmhO++sXAb8TNN0D6JAD5iyI1mqEPNpxUzTRrtm4aOG1pDf/5W/qCFihiaoK6uuL9rvQz1x1VKw==
+ dependencies:
+ rusha "^0.8.1"
+
+simple-websocket@^7.0.1:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/simple-websocket/-/simple-websocket-7.2.0.tgz#c3190555d74399372b96b51435f2d8c4b04611df"
+ integrity sha512-wdxFg1fHw1yqFKWDcw+yNb4VIYqtl+vknZMlpLhvZSlR6l7/iVuwozqo+Qtl73mB1IH5QnXzonD1S+hAaLNTvQ==
+ dependencies:
+ debug "^3.1.0"
+ inherits "^2.0.1"
+ randombytes "^2.0.3"
+ readable-stream "^2.0.5"
+ ws "^6.0.0"
+
+spdx-correct@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
+ integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==
+ dependencies:
+ spdx-expression-parse "^3.0.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-exceptions@^2.1.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977"
+ integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==
+
+spdx-expression-parse@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
+ integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==
+ dependencies:
+ spdx-exceptions "^2.1.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-license-ids@^3.0.0:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1"
+ integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==
+
+speedometer@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-1.1.0.tgz#a30b13abda45687a1a76977012c060f2ac8a7934"
+ integrity sha512-z/wAiTESw2XVPssY2XRcme4niTc4S5FkkJ4gknudtVoc33Zil8TdTxHy5torRcgqMqksJV2Yz8HQcvtbsnw0mQ==
+
+split@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9"
+ integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==
+ dependencies:
+ through "2"
+
+stream-to-blob-url@^2.0.0, stream-to-blob-url@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/stream-to-blob-url/-/stream-to-blob-url-2.1.1.tgz#e1ac97f86ca8e9f512329a48e7830ce9a50beef2"
+ integrity sha512-DKJPEmCmIZoBfGVle9IhSfERiWaN5cuOtmfPxP2dZbLDRZxkBWZ4QbYxEJOSALk1Kf+WjBgedAMO6qkkf7Lmrg==
+ dependencies:
+ stream-to-blob "^1.0.0"
+
+stream-to-blob@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/stream-to-blob/-/stream-to-blob-1.0.1.tgz#2dc1e09b71677a234d00445f8eb7ff70c4fe9948"
+ integrity sha512-aRy4neA4rf+qMtLT9fCRLPGWdrsIKtCx4kUdNTIPgPQ2hkHkdxbViVAvABMx9oRM6yCWfngHx6pwXfbYkVuPuw==
+ dependencies:
+ once "^1.3.3"
+
+stream-with-known-length-to-buffer@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/stream-with-known-length-to-buffer/-/stream-with-known-length-to-buffer-1.0.2.tgz#b8ea5a92086a1ed5d27fc4c529636682118c945b"
+ integrity sha512-UxSISjxmguvfYzZdq6d4XAjc3gAocqTIOS1CjgwkDkkGT/LMTsIYiV8agIw42IHFFHf8k4lPOoroCCf4W9oqzg==
+ dependencies:
+ once "^1.3.3"
+
+string-width@^1.0.1, string-width@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+ integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
+ dependencies:
+ code-point-at "^1.0.0"
+ is-fullwidth-code-point "^1.0.0"
+ strip-ansi "^3.0.0"
+
+"string-width@^1.0.2 || 2":
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
+ integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
+ dependencies:
+ is-fullwidth-code-point "^2.0.0"
+ strip-ansi "^4.0.0"
+
+string2compact@^1.1.1, string2compact@^1.2.5:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/string2compact/-/string2compact-1.3.0.tgz#22d946127b082d1203c51316af60117a337423c3"
+ integrity sha512-004ulKKANDuQilQsNxy2lisrpMG0qUJxBU+2YCEF7KziRyNR0Nredm2qk0f1V82nva59H3y9GWeHXE63HzGRFw==
+ dependencies:
+ addr-to-ip-port "^1.0.1"
+ ipaddr.js "^1.0.1"
+
+string_decoder@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
+ integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==
+ dependencies:
+ safe-buffer "~5.1.0"
+
+string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+ integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+ dependencies:
+ safe-buffer "~5.1.0"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
+ dependencies:
+ ansi-regex "^2.0.0"
+
+strip-ansi@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
+ integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
+ dependencies:
+ ansi-regex "^3.0.0"
+
+strip-bom@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+ integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
+ dependencies:
+ is-utf8 "^0.2.0"
+
+strip-json-comments@~2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+ integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+
+tar@^4:
+ version "4.4.8"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d"
+ integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==
+ dependencies:
+ chownr "^1.1.1"
+ fs-minipass "^1.2.5"
+ minipass "^2.3.4"
+ minizlib "^1.1.1"
+ mkdirp "^0.5.0"
+ safe-buffer "^5.1.2"
+ yallist "^3.0.2"
+
+thirty-two@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a"
+ integrity sha1-TKL//AKlEpDSdEueP1V2k8prYno=
+
+through@2:
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+ integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
+
+thunky@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/thunky/-/thunky-0.1.0.tgz#bf30146824e2b6e67b0f2d7a4ac8beb26908684e"
+ integrity sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=
+
+thunky@^1.0.1, thunky@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826"
+ integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==
+
+to-arraybuffer@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+ integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
+
+torrent-discovery@^9.1.1:
+ version "9.1.1"
+ resolved "https://registry.yarnpkg.com/torrent-discovery/-/torrent-discovery-9.1.1.tgz#56704e6747b24fe00dbb75b442d202051f78d37d"
+ integrity sha512-3mHf+bxVCVLrlkPJdAoMbPMY1hpTZVeWw5hNc2pPFm+HCc2DS0HgVFTBTSWtB8vQPWA1hSEZpqJ+3QfdXxDE1g==
+ dependencies:
+ bittorrent-dht "^9.0.0"
+ bittorrent-tracker "^9.0.0"
+ debug "^3.1.0"
+ run-parallel "^1.1.2"
+
+torrent-piece@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/torrent-piece/-/torrent-piece-2.0.0.tgz#6598ae67d93699e887f178db267ba16d89d7ec9b"
+ integrity sha512-H/Z/yCuvZJj1vl1IQHI8dvF2QrUuXRJoptT5DW5967/dsLpXlCg+uyhFR5lfNj5mNaYePUbKtnL+qKWZGXv4Nw==
+
+typedarray-to-buffer@^3.0.0:
+ version "3.1.5"
+ resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
+ integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
+ dependencies:
+ is-typedarray "^1.0.0"
+
+typedarray@^0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+ integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
+
+uint64be@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/uint64be/-/uint64be-2.0.2.tgz#ef4a179752fe8f9ddaa29544ecfc13490031e8e5"
+ integrity sha512-9QqdvpGQTXgxthP+lY4e/gIBy+RuqcBaC6JVwT5I3bDLgT/btL6twZMR0pI3/Fgah9G/pdwzIprE5gL6v9UvyQ==
+ dependencies:
+ buffer-alloc "^1.1.0"
+
+uniq@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
+ integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=
+
+unordered-array-remove@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz#c546e8f88e317a0cf2644c97ecb57dba66d250ef"
+ integrity sha1-xUbo+I4xegzyZEyX7LV9umbSUO8=
+
+upnp-device-client@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/upnp-device-client/-/upnp-device-client-1.0.2.tgz#91f84705f2349bf89082855fff4e3006ac435337"
+ integrity sha1-kfhHBfI0m/iQgoVf/04wBqxDUzc=
+ dependencies:
+ concat-stream "^1.4.8"
+ debug "^2.1.3"
+ elementtree "~0.1.6"
+ network-address "^1.0.0"
+
+upnp-mediarenderer-client@^1.2.2:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/upnp-mediarenderer-client/-/upnp-mediarenderer-client-1.2.4.tgz#0c63a51802082b6b03b596c475cc64fc1e0877c8"
+ integrity sha1-DGOlGAIIK2sDtZbEdcxk/B4Id8g=
+ dependencies:
+ debug "^2.1.3"
+ elementtree "^0.1.6"
+ upnp-device-client "^1.0.0"
+
+url-join@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728"
+ integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=
+
+ut_metadata@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/ut_metadata/-/ut_metadata-3.3.0.tgz#a0e0e861ebc39ed96e506601d1463ade3b548a7e"
+ integrity sha512-IK+ke9yL6a4oPLz/3oSW9TW7m9Wr4RG+5kW5aS2YulzEU1QDGAtago/NnOlno91fo3fSO7mnsqzn3NXNXdv8nA==
+ dependencies:
+ bencode "^2.0.0"
+ bitfield "^2.0.0"
+ debug "^3.1.0"
+ simple-sha1 "^2.0.0"
+
+ut_pex@^1.1.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/ut_pex/-/ut_pex-1.2.1.tgz#472ed0ea5e9bbc9148b833339d56d7b17cf3dad0"
+ integrity sha512-ZrxMCbffYtxQDqvREN9kBXK2CB9tPnd5PylHoqQX9ai+3HV9/S39FnA5JnhLOC82dxIQQg0nTN2wmhtAdGNtOA==
+ dependencies:
+ bencode "^2.0.0"
+ compact2string "^1.2.0"
+ inherits "^2.0.1"
+ string2compact "^1.2.5"
+
+utf-8-validate@^5.0.1:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.2.tgz#63cfbccd85dc1f2b66cf7a1d0eebc08ed056bfb3"
+ integrity sha512-SwV++i2gTD5qh2XqaPzBnNX88N6HdyhQrNNRykvcS0QKvItV9u3vPEJr+X5Hhfb1JC0r0e1alL0iB09rY8+nmw==
+ dependencies:
+ node-gyp-build "~3.7.0"
+
+util-deprecate@^1.0.1, util-deprecate@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
+
+validate-npm-package-license@^3.0.1:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
+ integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
+ dependencies:
+ spdx-correct "^3.0.0"
+ spdx-expression-parse "^3.0.0"
+
+videostream@^2.5.1:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/videostream/-/videostream-2.6.0.tgz#7f0b2b84bc457c12cfe599aa2345f5cc06241ab6"
+ integrity sha512-nSsullx1BYClJxVSt4Fa+Ulsv0Cf7UwaHq+4LQdLkAUdmqNhY1DlGxXDWVY2gui5XV4FvDiSbXmSbGryMrrUCQ==
+ dependencies:
+ binary-search "^1.3.4"
+ inherits "^2.0.1"
+ mediasource "^2.2.2"
+ mp4-box-encoding "^1.3.0"
+ mp4-stream "^2.0.0"
+ multistream "^2.0.2"
+ pump "^3.0.0"
+ range-slice-stream "^2.0.0"
+
+vlc-command@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vlc-command/-/vlc-command-1.1.2.tgz#61a9b4249a0001c0bcac8cdaf36d3a8e674cffce"
+ integrity sha512-KZ15RTHz96OEiQDA8oNFn1edYDWyKJIWI4gF74Am9woZo5XmVYryk5RYXSwOMvsaAgL5ejICEGCl0suQyDBu+Q==
+ dependencies:
+ run-parallel "^1.1.6"
+ winreg "^1.2.1"
+
+webidl-conversions@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
+ integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
+
+webtorrent-cli@^1.12.3:
+ version "1.12.3"
+ resolved "https://registry.yarnpkg.com/webtorrent-cli/-/webtorrent-cli-1.12.3.tgz#e6a1060cd3f104346da91e67763276ca897f238c"
+ integrity sha512-NnBAGkD64CRsl9edM9q0QU+ku6nCX32nM0U+YC8Gs/36c8y+5m9Tya3mWIux3oZKZ54yGiVtnok4tUpqDE5tMA==
+ dependencies:
+ clivas "^0.2.0"
+ create-torrent "^3.23.1"
+ dlnacasts "^0.1.0"
+ ecstatic "^3.0.0"
+ executable "^4.0.0"
+ mime "^2.1.0"
+ minimist "^1.2.0"
+ moment "^2.12.0"
+ network-address "^1.1.0"
+ open "0.0.5"
+ parse-torrent "^6.0.0"
+ prettier-bytes "^1.0.3"
+ vlc-command "^1.0.0"
+ webtorrent "0.x"
+ winreg "^1.0.1"
+ optionalDependencies:
+ airplay-js "^0.3.0"
+ chromecasts "^1.5.3"
+ nodebmc "0.0.7"
+
+webtorrent-hybrid@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/webtorrent-hybrid/-/webtorrent-hybrid-2.1.0.tgz#c14d33d6769667d8ae524ca2d9dfdcd18d4cfbf2"
+ integrity sha512-S8tUgUbPLwGazPrBMTqjsuxlmhaCZaiC+KlgS7ECRGaHVVZTJjKG2kUw8uf558DdZbsEA3jNxOOsMvXiA62sFw==
+ dependencies:
+ create-torrent "^3.33.0"
+ webtorrent "^0.x"
+ webtorrent-cli "^1.12.3"
+ wrtc "^0.3.3"
+
+webtorrent@0.x, webtorrent@^0.x:
+ version "0.103.1"
+ resolved "https://registry.yarnpkg.com/webtorrent/-/webtorrent-0.103.1.tgz#18ead369bbcaa60dc8ea138784c33451edd34479"
+ integrity sha512-rqMD8sAaPzrUzEpA6gDEOgcN9Xyz4WGrQiHoVY6HlymLoNSkScMnmnEX1bsdMcIU9iOrnUlghDEW9sJ9jYCmwQ==
+ dependencies:
+ addr-to-ip-port "^1.4.2"
+ bitfield "^2.0.0"
+ bittorrent-dht "^9.0.0"
+ bittorrent-protocol "^3.0.0"
+ chunk-store-stream "^3.0.1"
+ create-torrent "^3.33.0"
+ debug "^4.1.0"
+ end-of-stream "^1.1.0"
+ fs-chunk-store "^1.6.2"
+ immediate-chunk-store "^2.0.0"
+ load-ip-set "^2.1.0"
+ memory-chunk-store "^1.2.0"
+ mime "^2.4.0"
+ multistream "^2.0.5"
+ package-json-versionify "^1.0.2"
+ parse-numeric-range "^0.0.2"
+ parse-torrent "^6.1.2"
+ pump "^3.0.0"
+ random-iterate "^1.0.1"
+ randombytes "^2.0.3"
+ range-parser "^1.2.0"
+ readable-stream "^3.0.6"
+ render-media "^3.0.0"
+ run-parallel "^1.1.6"
+ run-parallel-limit "^1.0.3"
+ safe-buffer "^5.0.1"
+ simple-concat "^1.0.0"
+ simple-get "^3.0.1"
+ simple-peer "^9.0.0"
+ simple-sha1 "^2.0.8"
+ speedometer "^1.0.0"
+ stream-to-blob "^1.0.0"
+ stream-to-blob-url "^2.1.0"
+ stream-with-known-length-to-buffer "^1.0.0"
+ torrent-discovery "^9.1.1"
+ torrent-piece "^2.0.0"
+ uniq "^1.0.1"
+ unordered-array-remove "^1.0.2"
+ ut_metadata "^3.3.0"
+ ut_pex "^1.1.1"
+
+which-module@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+ integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=
+
+which@^1.2.14:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+ integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+ dependencies:
+ isexe "^2.0.0"
+
+wide-align@^1.1.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
+ integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
+ dependencies:
+ string-width "^1.0.2 || 2"
+
+winreg@^1.0.1, winreg@^1.2.1:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b"
+ integrity sha1-ugZWKbepJRMOFXeRCM9UCZDpjRs=
+
+wrap-ansi@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+ integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
+ dependencies:
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+
+wrtc@^0.3.3:
+ version "0.3.7"
+ resolved "https://registry.yarnpkg.com/wrtc/-/wrtc-0.3.7.tgz#2279f1cb3a83573e77b3d9b7e720071fab2ae4af"
+ integrity sha512-mDFNFqAB+3IYVKlP15vpGD0EhXjsQlj/GLNje4KLpClLSq8pyTG0xqJFoU+Oq43XvDIUMmIJ/r1aNfrjT7KUQw==
+ dependencies:
+ nan "^2.3.2"
+ node-cmake "2.3.2"
+ node-pre-gyp "0.11.x"
+ optionalDependencies:
+ domexception "^1.0.1"
+
+ws@^6.0.0:
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"
+ integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==
+ dependencies:
+ async-limiter "~1.0.0"
+
+xml2js@^0.4.8:
+ version "0.4.19"
+ resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7"
+ integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==
+ dependencies:
+ sax ">=0.6.0"
+ xmlbuilder "~9.0.1"
+
+xmlbuilder@0.4.x:
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-0.4.3.tgz#c4614ba74e0ad196e609c9272cd9e1ddb28a8a58"
+ integrity sha1-xGFLp04K0ZbmCcknLNnh3bKKilg=
+
+xmlbuilder@~9.0.1:
+ version "9.0.7"
+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"
+ integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=
+
+xmldom@0.1.x:
+ version "0.1.27"
+ resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9"
+ integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk=
+
+xtend@^4.0.0, xtend@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+ integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
+
+y18n@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+ integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
+
+yallist@^3.0.0, yallist@^3.0.2:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
+ integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
+
+yargs-parser@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
+ integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=
+ dependencies:
+ camelcase "^3.0.0"
+
+yargs@^7.0.2:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"
+ integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=
+ dependencies:
+ camelcase "^3.0.0"
+ cliui "^3.2.0"
+ decamelize "^1.1.1"
+ get-caller-file "^1.0.1"
+ os-locale "^1.4.0"
+ read-pkg-up "^1.0.1"
+ require-directory "^2.1.1"
+ require-main-filename "^1.0.1"
+ set-blocking "^2.0.0"
+ string-width "^1.0.2"
+ which-module "^1.0.0"
+ y18n "^3.2.1"
+ yargs-parser "^5.0.0"
--- /dev/null
+function isToday (d: Date) {
+ const today = new Date()
+
+ return areDatesEqual(d, today)
+}
+
+function isYesterday (d: Date) {
+ const yesterday = new Date()
+ yesterday.setDate(yesterday.getDate() - 1)
+
+ return areDatesEqual(d, yesterday)
+}
+
+function isThisWeek (d: Date) {
+ const minDateOfThisWeek = new Date()
+ minDateOfThisWeek.setHours(0, 0, 0)
+
+ // getDay() -> Sunday - Saturday : 0 - 6
+ // We want to start our week on Monday
+ let dayOfWeek = minDateOfThisWeek.getDay() - 1
+ if (dayOfWeek < 0) dayOfWeek = 6 // Sunday
+
+ minDateOfThisWeek.setDate(minDateOfThisWeek.getDate() - dayOfWeek)
+
+ return d >= minDateOfThisWeek
+}
+
+function isThisMonth (d: Date) {
+ const thisMonth = new Date().getMonth()
+
+ return d.getMonth() === thisMonth
+}
+
+function isLastMonth (d: Date) {
+ const now = new Date()
+
+ return getDaysDifferences(now, d) <= 30
+}
+
+function isLastWeek (d: Date) {
+ const now = new Date()
+
+ return getDaysDifferences(now, d) <= 7
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+ isYesterday,
+ isThisWeek,
+ isThisMonth,
+ isToday,
+ isLastMonth,
+ isLastWeek
+}
+
+// ---------------------------------------------------------------------------
+
+function areDatesEqual (d1: Date, d2: Date) {
+ return d1.getFullYear() === d2.getFullYear() &&
+ d1.getMonth() === d2.getMonth() &&
+ d1.getDate() === d2.getDate()
+}
+
+function getDaysDifferences (d1: Date, d2: Date) {
+ return (d1.getTime() - d2.getTime()) / (86400000)
+}
import { QueryTypes, Sequelize } from 'sequelize'
+import { ServerInfo } from '../server/servers'
let sequelizes: { [ id: number ]: Sequelize } = {}
-function getSequelize (serverNumber: number) {
- if (sequelizes[serverNumber]) return sequelizes[serverNumber]
+function getSequelize (internalServerNumber: number) {
+ if (sequelizes[internalServerNumber]) return sequelizes[internalServerNumber]
- const dbname = 'peertube_test' + serverNumber
+ const dbname = 'peertube_test' + internalServerNumber
const username = 'peertube'
const password = 'peertube'
const host = 'localhost'
logging: false
})
- sequelizes[serverNumber] = seq
+ sequelizes[internalServerNumber] = seq
return seq
}
-function setActorField (serverNumber: number, to: string, field: string, value: string) {
- const seq = getSequelize(serverNumber)
+function setActorField (internalServerNumber: number, to: string, field: string, value: string) {
+ const seq = getSequelize(internalServerNumber)
const options = { type: QueryTypes.UPDATE }
return seq.query(`UPDATE actor SET "${field}" = '${value}' WHERE url = '${to}'`, options)
}
-function setVideoField (serverNumber: number, uuid: string, field: string, value: string) {
- const seq = getSequelize(serverNumber)
+function setVideoField (internalServerNumber: number, uuid: string, field: string, value: string) {
+ const seq = getSequelize(internalServerNumber)
const options = { type: QueryTypes.UPDATE }
return seq.query(`UPDATE video SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options)
}
-function setPlaylistField (serverNumber: number, uuid: string, field: string, value: string) {
- const seq = getSequelize(serverNumber)
+function setPlaylistField (internalServerNumber: number, uuid: string, field: string, value: string) {
+ const seq = getSequelize(internalServerNumber)
const options = { type: QueryTypes.UPDATE }
return seq.query(`UPDATE "videoPlaylist" SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options)
}
-async function countVideoViewsOf (serverNumber: number, uuid: string) {
- const seq = getSequelize(serverNumber)
+async function countVideoViewsOf (internalServerNumber: number, uuid: string) {
+ const seq = getSequelize(internalServerNumber)
// tslint:disable
const query = `SELECT SUM("videoView"."views") AS "total" FROM "videoView" INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'`
return parseInt(total + '', 10)
}
-async function closeAllSequelize (servers: any[]) {
- for (let i = 1; i <= servers.length; i++) {
- if (sequelizes[ i ]) {
- await sequelizes[ i ].close()
- delete sequelizes[ i ]
+async function closeAllSequelize (servers: ServerInfo[]) {
+ for (const server of servers) {
+ if (sequelizes[ server.internalServerNumber ]) {
+ await sequelizes[ server.internalServerNumber ].close()
+ delete sequelizes[ server.internalServerNumber ]
}
}
}
function searchVideo (url: string, search: string) {
const path = '/api/v1/search/videos'
+
+ const query = { sort: '-publishedAt', search: search }
const req = request(url)
.get(path)
- .query({ sort: '-publishedAt', search })
+ .query(query)
.set('Accept', 'application/json')
return req.expect(200)
function searchVideoWithPagination (url: string, search: string, start: number, count: number, sort?: string) {
const path = '/api/v1/search/videos'
+ const query = {
+ start,
+ search,
+ count
+ }
+
const req = request(url)
.get(path)
- .query({ start })
- .query({ search })
- .query({ count })
+ .query(query)
if (sort) req.query({ sort })
function searchVideoWithSort (url: string, search: string, sort: string) {
const path = '/api/v1/search/videos'
+ const query = { search, sort }
+
return request(url)
.get(path)
- .query({ search })
- .query({ sort })
+ .query(query)
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
transcoding: {
enabled: true,
allowAdditionalExtensions: true,
+ allowAudioFiles: true,
threads: 1,
resolutions: {
'240p': false,
import * as request from 'supertest'
import { ServerInfo } from './servers'
import { waitJobs } from './jobs'
-import { makeGetRequest, makePostBodyRequest } from '..'
+import { makePostBodyRequest } from '../requests/requests'
function getFollowersListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) {
const path = '/api/v1/server/followers'
+ const query = {
+ start,
+ count,
+ sort,
+ search
+ }
+
return request(url)
.get(path)
- .query({ start })
- .query({ count })
- .query({ sort })
- .query({ search })
+ .query(query)
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
function getFollowingListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) {
const path = '/api/v1/server/following'
+ const query = {
+ start,
+ count,
+ sort,
+ search
+ }
+
return request(url)
.get(path)
- .query({ start })
- .query({ count })
- .query({ sort })
- .query({ search })
+ .query(query)
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
}
async function checkDirectoryIsEmpty (server: ServerInfo, directory: string) {
- const testDirectory = 'test' + server.serverNumber
+ const testDirectory = 'test' + server.internalServerNumber
const directoryPath = join(root(), testDirectory, directory)
}
async function waitUntilLog (server: ServerInfo, str: string, count = 1) {
- const logfile = join(root(), 'test' + server.serverNumber, 'logs/peertube.log')
+ const logfile = join(root(), 'test' + server.internalServerNumber, 'logs/peertube.log')
while (true) {
const buf = await readFile(logfile)
expect(account.followingCount).to.equal(followingCount, message)
}
-async function checkActorFilesWereRemoved (actorUUID: string, serverNumber: number) {
+async function checkActorFilesWereRemoved (filename: string, serverNumber: number) {
const testDirectory = 'test' + serverNumber
for (const directory of [ 'avatars' ]) {
const files = await readdir(directoryPath)
for (const file of files) {
- expect(file).to.not.contain(actorUUID)
+ expect(file).to.not.contain(filename)
}
}
}
}
}
- const commentUrl = `http://localhost:9001/videos/watch/${uuid};threadId=${threadId}`
+ const commentUrl = `http://localhost:${base.server.port}/videos/watch/${uuid};threadId=${threadId}`
function emailFinder (email: object) {
return email[ 'text' ].indexOf(commentUrl) !== -1
}
import * as request from 'supertest'
-import { makePostBodyRequest, makePutBodyRequest, updateAvatarRequest } from '../requests/requests'
+import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, updateAvatarRequest } from '../requests/requests'
-import { UserRole } from '../../index'
+import { UserCreate, UserRole } from '../../index'
import { NSFWPolicyType } from '../../models/videos/nsfw-policy.type'
import { ServerInfo, userLogin } from '..'
import { UserAdminFlag } from '../../models/users/user-flag.model'
+import { UserRegister } from '../../models/users/user-register.model'
type CreateUserArgs = { url: string,
accessToken: string,
.expect(specialStatus)
}
+function registerUserWithChannel (options: {
+ url: string,
+ user: { username: string, password: string },
+ channel: { name: string, displayName: string }
+}) {
+ const path = '/api/v1/users/register'
+ const body: UserRegister = {
+ username: options.user.username,
+ password: options.user.password,
+ email: options.user.username + '@example.com',
+ channel: options.channel
+ }
+
+ return makePostBodyRequest({
+ url: options.url,
+ path,
+ fields: body,
+ statusCodeExpected: 204
+ })
+}
+
function getMyUserInformation (url: string, accessToken: string, specialStatus = 200) {
const path = '/api/v1/users/me'
function getUsersListPaginationAndSort (url: string, accessToken: string, start: number, count: number, sort: string, search?: string) {
const path = '/api/v1/users'
+ const query = {
+ start,
+ count,
+ sort,
+ search
+ }
+
return request(url)
.get(path)
- .query({ start })
- .query({ count })
- .query({ sort })
- .query({ search })
+ .query(query)
.set('Accept', 'application/json')
.set('Authorization', 'Bearer ' + accessToken)
.expect(200)
getMyUserInformation,
getMyUserVideoRating,
deleteMe,
+ registerUserWithChannel,
getMyUserVideoQuotaUsed,
getUsersList,
getUsersListPaginationAndSort,
import * as request from 'supertest'
import { VideoChannelCreate, VideoChannelUpdate } from '../../models/videos'
-import { updateAvatarRequest } from '../requests/requests'
+import { makeGetRequest, updateAvatarRequest } from '../requests/requests'
import { getMyUserInformation, ServerInfo } from '..'
import { User } from '../..'
.expect('Content-Type', /json/)
}
-function getAccountVideoChannelsList (url: string, accountName: string, specialStatus = 200) {
+function getAccountVideoChannelsList (parameters: {
+ url: string,
+ accountName: string,
+ start?: number,
+ count?: number,
+ sort?: string,
+ specialStatus?: number
+}) {
+ const { url, accountName, start, count, sort = 'createdAt', specialStatus = 200 } = parameters
+
const path = '/api/v1/accounts/' + accountName + '/video-channels'
- return request(url)
- .get(path)
- .set('Accept', 'application/json')
- .expect(specialStatus)
- .expect('Content-Type', /json/)
+ return makeGetRequest({
+ url,
+ path,
+ query: {
+ start,
+ count,
+ sort
+ },
+ statusCodeExpected: specialStatus
+ })
}
function addVideoChannel (
attributes: VideoChannelUpdate,
expectedStatus = 204
) {
- const body = {}
+ const body: any = {}
const path = '/api/v1/video-channels/' + channelName
- if (attributes.displayName) body['displayName'] = attributes.displayName
- if (attributes.description) body['description'] = attributes.description
- if (attributes.support) body['support'] = attributes.support
+ if (attributes.displayName) body.displayName = attributes.displayName
+ if (attributes.description) body.description = attributes.description
+ if (attributes.support) body.support = attributes.support
+ if (attributes.bulkVideosSupportUpdate) body.bulkVideosSupportUpdate = attributes.bulkVideosSupportUpdate
return request(url)
.put(path)
async function checkPlaylistFilesWereRemoved (
playlistUUID: string,
- serverNumber: number,
+ internalServerNumber: number,
directories = [ 'thumbnails' ]
) {
- const testDirectory = 'test' + serverNumber
+ const testDirectory = 'test' + internalServerNumber
for (const directory of directories) {
const directoryPath = join(root(), testDirectory, directory)
.set('Accept', 'application/json')
.set('Authorization', 'Bearer ' + accessToken)
.field('name', attributes.name)
+ .field('support', attributes.support)
.field('nsfw', JSON.stringify(attributes.nsfw))
.field('commentsEnabled', JSON.stringify(attributes.commentsEnabled))
.field('downloadEnabled', JSON.stringify(attributes.downloadEnabled))
expect(video.nsfw).to.equal(attributes.nsfw)
expect(video.description).to.equal(attributes.description)
expect(video.account.id).to.be.a('number')
- expect(video.account.uuid).to.be.a('string')
expect(video.account.host).to.equal(attributes.account.host)
expect(video.account.name).to.equal(attributes.account.name)
expect(video.channel.displayName).to.equal(attributes.channel.displayName)
expect(file).not.to.be.undefined
let extension = extname(attributes.fixture)
- // Transcoding enabled on server 2, extension will always be .mp4
- if (attributes.account.host === 'localhost:9002') extension = '.mp4'
+ // Transcoding enabled: extension will always be .mp4
+ if (attributes.files.length > 1) extension = '.mp4'
const magnetUri = file.magnetUri
expect(file.magnetUri).to.have.lengthOf.above(2)
attributedTo: ActivityPubAttributedTo[]
support?: string
- uuid: string
publicKey: {
id: string
owner: string
export interface AccountSummary {
id: number
- uuid: string
name: string
displayName: string
url: string
export interface Actor {
id: number
- uuid: string
url: string
name: string
host: string
transcoding: {
enabled: boolean
allowAdditionalExtensions: boolean
+ allowAudioFiles: boolean
threads: number
resolutions: {
'240p': boolean
--- /dev/null
+export interface UserRegister {
+ username: string
+ password: string
+ email: string
+
+ channel?: {
+ name: string
+ displayName: string
+ }
+}
export interface VideoChannelUpdate {
- displayName: string
+ displayName?: string
description?: string
support?: string
+
+ bulkVideosSupportUpdate?: boolean
}
export interface VideoChannelSummary {
id: number
- uuid: string
name: string
displayName: string
url: string
import { VideoPlaylistPrivacy } from './video-playlist-privacy.model'
export interface VideoPlaylistUpdate {
- displayName: string
- privacy: VideoPlaylistPrivacy
+ displayName?: string
+ privacy?: VideoPlaylistPrivacy
description?: string
videoChannelId?: number
H_360P = 360,
H_480P = 480,
H_720P = 720,
- H_1080P = 1080
+ H_1080P = 1080,
+ H_4K = 2160
}
/**
// quality according to Google Live Encoder: 1,500 - 4,000 Kbps
// Quality according to YouTube Video Info: 1752 Kbps
return 1750 * 1000
- case VideoResolution.H_1080P: // fallthrough
- default:
+ case VideoResolution.H_1080P:
// quality according to Google Live Encoder: 3000 - 6000 Kbps
// Quality according to YouTube Video Info: 3277 Kbps
return 3300 * 1000
+ case VideoResolution.H_4K: // fallthrough
+ default:
+ // quality according to Google Live Encoder: 13000 - 34000 Kbps
+ return 15000 * 1000
}
}
}
```
externalDocs:
- url: https://docs.joinpeertube.org/api.html
+ url: https://docs.joinpeertube.org/#/api-rest-reference.html
tags:
- name: Accounts
description: >
- name: Videos
tags:
- Video
+ - Video Caption
- Video Channel
- Video Comment
- Video Following
content:
application/json:
schema:
- $ref: '#/components/schemas/Video'
+ $ref: '#/components/schemas/VideoListResponse'
x-code-samples:
- lang: JavaScript
source: |
content:
application/json:
schema:
- type: array
- items:
- $ref: '#/components/schemas/Video'
+ $ref: '#/components/schemas/VideoListResponse'
/users/me/subscriptions:
get:
summary: Get subscriptions of the current user
content:
application/json:
schema:
- type: array
- items:
- $ref: '#/components/schemas/Video'
+ $ref: '#/components/schemas/VideoListResponse'
'/users/me/subscriptions/{uri}':
get:
summary: Get subscription of the current user for a given uri
content:
application/json:
schema:
- type: array
- items:
- $ref: '#/components/schemas/Video'
+ $ref: '#/components/schemas/VideoListResponse'
/videos/categories:
get:
summary: Get list of video licences known by the server
description: Video preview file
type: string
privacy:
- $ref: '#/components/schemas/VideoPrivacy'
+ $ref: '#/components/schemas/VideoPrivacySet'
category:
description: Video category
type: string
description: Video preview file
type: string
privacy:
- $ref: '#/components/schemas/VideoPrivacy'
+ $ref: '#/components/schemas/VideoPrivacySet'
category:
description: Video category
type: string
type: array
items:
$ref: '#/components/schemas/VideoBlacklist'
+ /videos/{id}/captions:
+ get:
+ summary: Get list of video's captions
+ tags:
+ - Video Caption
+ parameters:
+ - $ref: '#/components/parameters/id2'
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ total:
+ type: integer
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/VideoCaption'
+ /videos/{id}/captions/{captionLanguage}:
+ put:
+ summary: Add or replace a video caption
+ tags:
+ - Video Caption
+ parameters:
+ - $ref: '#/components/parameters/id2'
+ - $ref: '#/components/parameters/captionLanguage'
+ requestBody:
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ captionfile:
+ description: The file to upload.
+ type: string
+ format: binary
+ responses:
+ '204':
+ $ref: '#/paths/~1users~1me/put/responses/204'
+ delete:
+ summary: Delete a video caption
+ tags:
+ - Video Caption
+ parameters:
+ - $ref: '#/components/parameters/id2'
+ - $ref: '#/components/parameters/captionLanguage'
+ responses:
+ '204':
+ $ref: '#/paths/~1users~1me/put/responses/204'
/video-channels:
get:
summary: Get list of video channels
'204':
$ref: '#/paths/~1users~1me/put/responses/204'
requestBody:
- $ref: '#/components/requestBodies/VideoChannelInput'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/VideoChannelCreate'
'/video-channels/{channelHandle}':
get:
summary: Get a video channel by its id
'204':
$ref: '#/paths/~1users~1me/put/responses/204'
requestBody:
- $ref: '#/components/requestBodies/VideoChannelInput'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/VideoChannelUpdate'
delete:
summary: Delete a video channel by its id
security:
get:
summary: Get videos of a video channel by its id
tags:
+ - Video
- Video Channel
parameters:
- $ref: '#/components/parameters/channelHandle'
content:
application/json:
schema:
- $ref: '#/components/schemas/Video'
+ $ref: '#/components/schemas/VideoListResponse'
'/accounts/{name}/video-channels':
get:
summary: Get video channels of an account by its name
schema:
$ref: '#/components/schemas/CommentThreadPostResponse'
delete:
- summary: 'Delete a comment in a comment therad by its id, of a video by its id'
+ summary: 'Delete a comment in a comment thread by its id, of a video by its id'
security:
- OAuth2: []
tags:
content:
application/json:
schema:
- type: array
- items:
- $ref: '#/components/schemas/Video'
+ $ref: '#/components/schemas/VideoListResponse'
servers:
- url: 'https://peertube.cpy.re/api/v1'
description: Live Test Server (live data - stable version)
description: The video id or uuid
schema:
type: string
+ captionLanguage:
+ name: captionLanguage
+ in: path
+ required: true
+ description: The caption language
+ schema:
+ type: string
channelHandle:
name: channelHandle
in: path
type: array
items:
type: string
- requestBodies:
- VideoChannelInput:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/VideoChannelInput'
securitySchemes:
OAuth2:
description: >
- Have an account with sufficient authorization levels
- - [Generate](https://docs.joinpeertube.org/lang/en/devdocs/rest.html) a
+ - [Generate](https://docs.joinpeertube.org/#/api-rest-getting-started) a
Bearer Token
- Make Authenticated Requests
type: string
label:
type: string
- VideoPrivacy:
- type: string
+ VideoPrivacySet:
+ type: integer
enum:
- - Public
- - Unlisted
- - Private
+ - 1
+ - 2
+ - 3
+ description: 'The video privacy (Public = 1, Unlisted = 2, Private = 3)'
+ VideoPrivacyConstant:
+ properties:
+ id:
+ type: integer
+ enum:
+ - 1
+ - 2
+ - 3
+ label:
+ type: string
Video:
properties:
id:
language:
$ref: '#/components/schemas/VideoConstantString'
privacy:
- $ref: '#/components/schemas/VideoPrivacy'
+ $ref: '#/components/schemas/VideoPrivacyConstant'
description:
type: string
duration:
type: array
items:
$ref: '#/components/schemas/VideoCommentThreadTree'
+ VideoCaption:
+ properties:
+ language:
+ $ref: '#/components/schemas/VideoConstantString'
+ captionPath:
+ type: string
Avatar:
properties:
path:
autoPlayVideo:
type: boolean
role:
+ type: integer
+ enum:
+ - 0
+ - 1
+ - 2
+ description: 'The user role (Admin = 0, Moderator = 1, User = 2)'
+ roleLabel:
type: string
enum:
- User
properties:
comment:
$ref: '#/components/schemas/VideoComment'
+ VideoListResponse:
+ properties:
+ total:
+ type: number
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/Video'
AddUser:
properties:
username:
description: 'The user daily video quota '
role:
type: integer
- format: int32
enum:
- 0
- 1
- 2
- description: 'The user role '
+ description: 'The user role (Admin = 0, Moderator = 1, User = 2)'
required:
- username
- password
type: string
description: 'The updated daily video quota of the user '
role:
- type: string
- description: 'The updated role of the user '
+ type: integer
+ enum:
+ - 0
+ - 1
+ - 2
+ description: 'The user role (Admin = 0, Moderator = 1, User = 2)'
required:
- id
- email
- username
- password
- email
- VideoChannelInput:
+ VideoChannelCreate:
properties:
name:
type: string
+ displayName:
+ type: string
+ description:
+ type: string
+ support:
+ type: string
+ required:
+ - name
+ - displayName
+ VideoChannelUpdate:
+ properties:
+ displayName:
+ type: string
description:
type: string
+ support:
+ type: string
+ bulkVideosSupportUpdate:
+ type: boolean
+ description: 'Update all videos support field of this channel'
```
-### List videos
+## List videos
```bash
$ curl https://peertube.example.com/api/v1/videos
+++ /dev/null
-# Client code documentation
-
-The client is a HTML/CSS/JavaScript web application (single page application -> SPA) developed with [TypeScript](https://www.typescriptlang.org/)/[Angular](https://angular.io/).
-
-
-## Technologies
-
- * [TypeScript](https://www.typescriptlang.org/) -> Language
- * [Angular](https://angular.io) -> JavaScript framework
- * [SASS](http://sass-lang.com/) -> CSS framework
- * [Webpack](https://webpack.js.org/) -> Source builder (compile TypeScript, SASS files, bundle them...)
- * [Bootstrap](http://getbootstrap.com/) -> CSS framework
- * [WebTorrent](https://webtorrent.io/) -> JavaScript library to make P2P in the browser
- * [VideoJS](http://videojs.com/) -> JavaScript player framework
-
-
-## Files
-
-The client files are in the `client` directory. The Webpack 2 configurations files are in `client/config` and the source files in `client/src`.
-The client modules description are in the [client/package.json](/client/package.json). There are many modules that are used to compile the web application in development or production mode.
-Here is the description of the useful `client` files directory:
-
- tslint.json -> TypeScript linter rules
- tsconfig.json -> TypeScript configuration for the compilation
- .bootstraprc -> Bootstrap configuration file (which module we need)
- config -> Webpack configuration files
- src
- |__ app -> TypeScript files for Angular application
- |__ assets -> static files (images...)
- |__ sass -> SASS files that are global for the application
- |__ standalone -> files outside the Angular application (embed HTML page...)
- |__ index.html -> root HTML file for our Angular application
- |__ main.ts -> Main TypeScript file that boostraps our Angular application
- |__ polyfills.ts -> Polyfills imports (ES 2015...)
-
-Details of the Angular application file structure. It tries to follow [the official Angular styleguide](https://angular.io/docs/ts/latest/guide/style-guide.html).
-
- app
- |__ +admin -> Admin components (followers, users...)
- |__ account -> Account components (password change...)
- |__ core -> Core components/services
- |__ header -> Header components (logo, search...)
- |__ login -> Login component
- |__ menu -> Menu component (on the left)
- |__ shared -> Shared components/services (search component, REST services...)
- |__ signup -> Signup form
- |__ videos -> Video components (list, watch, upload...)
- |__ app.component.{html,scss,ts} -> Main application component
- |__ app-routing.module.ts -> Main Angular routes
- |__ app.module.ts -> Angular root module that imports all submodules we need
-
-## Conventions
-
-Uses [TSLint](https://palantir.github.io/tslint/) for TypeScript linting and [Angular styleguide](https://angular.io/docs/ts/latest/guide/style-guide.html).
-
-## Concepts
-
-In a Angular application, we create components that we put together. Each component is defined by an HTML structure, a TypeScript file and optionally a SASS file.
-If you are not familiar with Angular I recommend you to read the [quickstart guide](https://angular.io/docs/ts/latest/quickstart.html).
-
-## Components tree
-
-![Components tree](/support/doc/development/client/components-tree.svg)
-
-## Newcomers
-
-The main client component is `app.component.ts`. You can begin to look at this file. Then you could navigate in the different submodules to see how components are built.
+++ /dev/null
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" width="1141px" height="311px" version="1.1" content="<mxfile userAgent="Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0" version="8.9.9" editor="www.draw.io" type="device"><diagram name="Page-1" id="8be7db5e-9885-9541-e5e4-cf9e4eb3a109">7Zpbb5swFMc/TaTtZQLMLY9d1nYP2zSp2u3RwQ54dTAypkn36WeDSSCmVdcR3FTpQwXHN/z7G59zHGZgsd5ec1hknxnCdOY5aDsDH2aeFzuB/K8M943Bd93GkHKCGlPHcEP+YG10tLUiCJe9ioIxKkjRNyYsz3EiejbIOdv0q60Y7Y9awBQbhpsEUtP6gyCRaasbzvcFHzFJMz107EVNwRImtylnVa7Hm3lgVf81xWvY9qUnWmYQsU3HBC5nYMEZE83VervAVKFtsTXtrh4o3T03x7l4SgNPT6gU9+3cMZIo9C3jImMpyyG93Fvf1/PDqgdH3mViTeWlKy/xloifyvwu0He/2pJc8PtOkbr9pTsoBeTiQqkmDTnLcWu7IpTqOjhHbY2EwrIkSWPUVdQQv7EQ93opwUowado//ifGCl1vxXKhq7nq3kSmKZas4omG4ulFCHmKdS1NTuHqNNOYrzFbYzlHWYFjCgW5668sqBdouqu3F0leaJ2GNQPOWbNnahZb08w9a/ZMzSJrmnlnzZ6pGbCmWTymZk/F9rC2gxyeRTSaiKAfvFKCPpiKYGiF4CO7yBR0/f+kq5t+ZUQO7Dk6k5jPdbCjEwm3DX7aLppn0K0ONNo9xtNkG3XreEyOl/RSTLWt6LHvIK10pxdFUWdw60K6Na1eDz6lMt1TkDcZEfimgPU8NjLh7KM+dFor6fcWjDJe9wOwiwIc1X6Ts1vcKZmHEYDhY27uDnOBt4+6MF0K/P5CbRO8TSd9bG1ZN3N0RmA76obz8Ko7hWAEmGs8tBWMtKHrOYD8Z80Ca5qN6wVe27vk29IFGP7jO0GYlTMvhGvlEPJlWewmdgQ3giCOV8mQGwmTGC9XI7mR+CDeaaOSKfyIbzC+REQFY2+qgjKIZPuqQFDgt5I6lQO/R+ROXqainnxjWvJDi2zWq3csgQIcI39IoNhbgnAkPx8c+vkofBcYEsUDCgUjKBQYCn0i5fFCp2mQ+laRhgbSH1Ak2YkzNcLRSZlGBtOLJJE+8tRXauBa3J1j891nKclPHOnu1wwbSHdBzznYa3/O6gZ77Wq3EIV70whz6pnTkGiuLdHARMcQr1A0YC3fnZuuGq2P6VUmSaNsZlHtrtlBesUoVd+knDZU9zCkBAbU+VBAGY3A1DWY1um/6nZZlfjk0Xr22AIzqfxWYn7qSA8DyyGkg/nPGEgHEqAlq15A+mPwG6D8INLQt3k4ZZ4ADpxCfVUf9nnOF6aOra7q7/Be6CnUfykRRTaVMM8JB5T4rB53l/a/Qg3mjk0NzB2mdYiLDOY5pkfcvyfB6zoTngzI2/03t823A/vvmsHlXw==</diagram></mxfile>"><defs/><g transform="translate(0.5,0.5)"><path d="M 390 80 L 390 104 L 130 104 L 130 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 130 126.88 L 126.5 119.88 L 130 121.63 L 133.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 280 104 L 280 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 280 126.88 L 276.5 119.88 L 280 121.63 L 283.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 560 104 L 560 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 560 126.88 L 556.5 119.88 L 560 121.63 L 563.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 430 104 L 430 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 430 126.88 L 426.5 119.88 L 430 121.63 L 433.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 690 104 L 690 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 690 126.88 L 686.5 119.88 L 690 121.63 L 693.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 820 104 L 820 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 820 126.88 L 816.5 119.88 L 820 121.63 L 823.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 950 104 L 950 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 950 126.88 L 946.5 119.88 L 950 121.63 L 953.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 1080 104 L 1080 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1080 126.88 L 1076.5 119.88 L 1080 121.63 L 1083.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><ellipse cx="390" cy="40" rx="60" ry="40" fill="#e1d5e7" stroke="#9673a6" pointer-events="none"/><g transform="translate(345.5,34.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="88" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 89px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">App component</div></div></foreignObject><text x="44" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">App component</text></switch></g><path d="M 430 208 L 430 232 L 370 232 L 370 250.13" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 370 255.38 L 366.5 248.38 L 370 250.13 L 373.5 248.38 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 430 208 L 430 232 L 470 232 L 470 250.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 470 255.88 L 466.5 248.88 L 470 250.63 L 473.5 248.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 430 208 L 430 232 L 570 232 L 570 250.13" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 570 255.38 L 566.5 248.38 L 570 250.13 L 573.5 248.38 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><ellipse cx="430" cy="168" rx="60" ry="40" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><g transform="translate(408.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="43" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 44px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Videos </div></div></foreignObject><text x="22" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Videos </text></switch></g><ellipse cx="570" cy="282" rx="40" ry="25" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(524.5,262.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="91" height="38" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 91px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Edit (upload/update)<div><br /></div></div></div></foreignObject><text x="46" y="25" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Edit (upload/update)<div><br></div></text></switch></g><ellipse cx="470" cy="282" rx="40" ry="25" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(459.5,275.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="21" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 22px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">List</div></div></foreignObject><text x="11" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">List</text></switch></g><ellipse cx="370" cy="282" rx="40" ry="25" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(352.5,275.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="34" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 35px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Watch</div></div></foreignObject><text x="17" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Watch</text></switch></g><ellipse cx="560" cy="168" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(537.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="45" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 46px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Account</div></div></foreignObject><text x="23" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Account</text></switch></g><ellipse cx="280" cy="168" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(263.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="32" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 33px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Login</div></div></foreignObject><text x="16" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Login</text></switch></g><path d="M 130 208 L 130 231 L 45 231 L 45 246.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 45 251.88 L 41.5 244.88 L 45 246.63 L 48.5 244.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 130 208 L 130 231 L 155 231 L 155 246.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 155 251.88 L 151.5 244.88 L 155 246.63 L 158.5 244.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 130 208 L 130 231 L 260 231 L 260 246.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 260 251.88 L 256.5 244.88 L 260 246.63 L 263.5 244.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><ellipse cx="130" cy="168" rx="60" ry="40" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><g transform="translate(111.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="36" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 37px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Admin</div></div></foreignObject><text x="18" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Admin</text></switch></g><ellipse cx="45" cy="282" rx="45" ry="28.5" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><g transform="translate(22.5,275.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="44" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 45px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Follows</div></div></foreignObject><text x="22" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Follows</text></switch></g><ellipse cx="155" cy="282" rx="45" ry="28.5" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><g transform="translate(116.5,275.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="77" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 78px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video abuses</div></div></foreignObject><text x="39" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Video abuses</text></switch></g><ellipse cx="260" cy="282" rx="40" ry="28.5" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><g transform="translate(243.5,275.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="33" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 34px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Users</div></div></foreignObject><text x="17" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Users</text></switch></g><ellipse cx="690" cy="168" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(673.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="33" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 34px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">About</div></div></foreignObject><text x="17" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">About</text></switch></g><ellipse cx="820" cy="168" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(773.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="92" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 93px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>Page Not Found</div></div></div></foreignObject><text x="46" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica"><div>Page Not Found</div></text></switch></g><ellipse cx="950" cy="168" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(916.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="66" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 67px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>My Account</div></div></div></foreignObject><text x="33" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica"><div>My Account</div></text></switch></g><ellipse cx="1080" cy="168" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(1034.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="90" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 91px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video Channels</div></div></foreignObject><text x="45" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Video Channels</text></switch></g></g></svg>
\ No newline at end of file
+++ /dev/null
-<mxfile userAgent="Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0" version="8.9.9" editor="www.draw.io" type="device"><diagram name="Page-1" id="8be7db5e-9885-9541-e5e4-cf9e4eb3a109">7Zpbb5swFMc/TaTtZQLMLY9d1nYP2zSp2u3RwQ54dTAypkn36WeDSSCmVdcR3FTpQwXHN/z7G59zHGZgsd5ec1hknxnCdOY5aDsDH2aeFzuB/K8M943Bd93GkHKCGlPHcEP+YG10tLUiCJe9ioIxKkjRNyYsz3EiejbIOdv0q60Y7Y9awBQbhpsEUtP6gyCRaasbzvcFHzFJMz107EVNwRImtylnVa7Hm3lgVf81xWvY9qUnWmYQsU3HBC5nYMEZE83VervAVKFtsTXtrh4o3T03x7l4SgNPT6gU9+3cMZIo9C3jImMpyyG93Fvf1/PDqgdH3mViTeWlKy/xloifyvwu0He/2pJc8PtOkbr9pTsoBeTiQqkmDTnLcWu7IpTqOjhHbY2EwrIkSWPUVdQQv7EQ93opwUowado//ifGCl1vxXKhq7nq3kSmKZas4omG4ulFCHmKdS1NTuHqNNOYrzFbYzlHWYFjCgW5668sqBdouqu3F0leaJ2GNQPOWbNnahZb08w9a/ZMzSJrmnlnzZ6pGbCmWTymZk/F9rC2gxyeRTSaiKAfvFKCPpiKYGiF4CO7yBR0/f+kq5t+ZUQO7Dk6k5jPdbCjEwm3DX7aLppn0K0ONNo9xtNkG3XreEyOl/RSTLWt6LHvIK10pxdFUWdw60K6Na1eDz6lMt1TkDcZEfimgPU8NjLh7KM+dFor6fcWjDJe9wOwiwIc1X6Ts1vcKZmHEYDhY27uDnOBt4+6MF0K/P5CbRO8TSd9bG1ZN3N0RmA76obz8Ko7hWAEmGs8tBWMtKHrOYD8Z80Ca5qN6wVe27vk29IFGP7jO0GYlTMvhGvlEPJlWewmdgQ3giCOV8mQGwmTGC9XI7mR+CDeaaOSKfyIbzC+REQFY2+qgjKIZPuqQFDgt5I6lQO/R+ROXqainnxjWvJDi2zWq3csgQIcI39IoNhbgnAkPx8c+vkofBcYEsUDCgUjKBQYCn0i5fFCp2mQ+laRhgbSH1Ak2YkzNcLRSZlGBtOLJJE+8tRXauBa3J1j891nKclPHOnu1wwbSHdBzznYa3/O6gZ77Wq3EIV70whz6pnTkGiuLdHARMcQr1A0YC3fnZuuGq2P6VUmSaNsZlHtrtlBesUoVd+knDZU9zCkBAbU+VBAGY3A1DWY1um/6nZZlfjk0Xr22AIzqfxWYn7qSA8DyyGkg/nPGEgHEqAlq15A+mPwG6D8INLQt3k4ZZ4ADpxCfVUf9nnOF6aOra7q7/Be6CnUfykRRTaVMM8JB5T4rB53l/a/Qg3mjk0NzB2mdYiLDOY5pkfcvyfB6zoTngzI2/03t823A/vvmsHlXw==</diagram></mxfile>
\ No newline at end of file
+++ /dev/null
-# Server code documentation
-
-The server is a web server developed with [TypeScript](https://www.typescriptlang.org/)/[Express](http://expressjs.com).
-
-
-## Technologies
-
- * [TypeScript](https://www.typescriptlang.org/) -> Language
- * [PostgreSQL](https://www.postgresql.org/) -> Database
- * [Redis](https://redis.io/) -> Job queue/cache
- * [Express](http://expressjs.com) -> Web server framework
- * [Sequelize](http://docs.sequelizejs.com/en/v3/) -> SQL ORM
- * [WebTorrent](https://webtorrent.io/) -> BitTorrent tracker and torrent creation
- * [Mocha](https://mochajs.org/) -> Test framework
-
-
-## Files
-
-The server main file is [server.ts](/server.ts).
-The server modules description are in the [package.json](/package.json) at the project root.
-All other server files are in the [server](/server) directory:
-
- server.ts -> app initialization, main routes configuration (static routes...)
- config -> server YAML configurations (for tests, production...)
- scripts -> Scripts files for npm run
- server
- |__ controllers -> API routes/controllers files
- |__ helpers -> functions used by different part of the project (logger, utils...)
- |__ initializers -> functions used at the server startup (installer, database, constants...)
- |__ lib -> library function (WebTorrent, OAuth2, ActivityPub...)
- |__ middlewares -> middlewares for controllers (requests validators, requests pagination...)
- |__ models -> Sequelize models for each SQL tables (videos, users, accounts...)
- |__ tests -> API tests and real world simulations (to test the decentralized feature...)
-
-
-## Conventions
-
-Uses [JavaScript Standard Style](http://standardjs.com/).
-
-## Architecture
-
-The server is composed by:
-
- * a REST API (relying on the Express framework) documented on http://docs.joinpeertube.org/api.html
- * a WebTorrent Tracker (slightly custom version of [webtorrent/bittorrent-tracker](https://github.com/webtorrent/bittorrent-tracker#server))
-
-A video is seeded by the server with the [WebSeed](http://www.bittorrent.org/beps/bep_0019.html) protocol (HTTP).
-
-![Architecture scheme](/support/doc/development/server/upload-video.png)
-
-When a user uploads a video, the REST API creates the torrent file and then adds it to its database.
-
-If a user wants to watch the video, the tracker will indicate all other users that are watching the video + the HTTP url for the WebSeed.
-
-## Newcomers
-
-The server entrypoint is [server.ts](/server.ts). Looking at this file is a good start.
-Then you can try to understand the [controllers](/server/controllers): they are the entrypoints of each API request.
+++ /dev/null
-<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" version="7.9.7" editor="www.draw.io" type="device"><diagram id="033390a3-e8de-cf4f-5be1-41b3d99c78ae" name="Page-1">3VpRc5s4EP41nmkekgGEwH6M3aS9md5Mpnbby6MA2dBgxIHs2P31J4EECGGbxLhNzu1MYLXC0re7364Wj8BsvfuUoTT8mwQ4HllGsBuBjyPLMm3LGvH/RrAvJeOxWQpWWRQIpVowj35hITSEdBMFOFcUKSExjVJV6JMkwT5VZCjLyLOqtiSx+q0pWmFNMPdRrEt/RAENxS4sp5Z/xtEqlN9sOpNyxEP+0yojm0R838gCy+JTDq+RfJbYaB6igDw3ROBuBGYZIbS8Wu9mOObYStjKefcHRqt1ZzihfSaAcsIWxRssV1ysi+4lFsVuMNc3R2D6HEYUz1Pk89FnZn0mC+k6FsPLKI5nJCZZMVfuHUxzmpEn3Bgxig8b0VcsNrHFGcW7hkjs4BMma0yzPVMRo7YAUzgbELfPteVcqRI2rGZPhBAJb1lVT64RYxcCtG4AbQ3AbznOmMQcFsixj32/C0hvDG04EJCmpSLpmjqUlU4TSmcAJOEhJAd2yd+CJJzAP4ckGGuI4YDxm7glGQ3JiiQovqul0xpTQ8UP7yL6DxffQHH3KJQYPNm+HLKgvH8U03KKMnrLuZgJEpJgKbuP+MLFAwKp4ccozyO/FAoV/pifmNK9SBBoQwkT1ev/QkgqrUwSKtRM85gNc7LJfIGKIG22qhWWWsJuHLCjhs5wjGi0VRPGWUwinawOgFmGEWV5kC0xxEUOzIr9sIwWMaNZTsxWPQ2iLbtc8cvbIKi1tyyHkmIWz8SIIg/l1SS2msY8zV+Ym1PVDTKcR7+QVyhw26UkSmixXTgdwY9MguJolXBTsiWywAVTHi4RS6q3YmAdBUHhazHycDytUmVXwjhtT+nlWlBWZYFYrZJau4LVuDEhtJR4vRa83tvK4uEPHJWGClkuc+ZabTeo1tDLMyaaY3y9my+Y5PbhL81yL2PDAOJxYHex4djygOMMw4aTsZqg3Q4ydOCFyNC5PBmaKhm6ChkabTKsqa7Jh+Yb4EOZpJqEODgfFlPZNtG+oSDYRA+kncyfjuJCjtuqa1v6zhge02cX5QpeG5J2V+Gs03H+lBfHD17GpBhn/O7DD+x9Xcyuupl4GtFFxfJpRnwSv0tydoYi52vGzsBUCcR6Q+QsY6bhCczAlQ01n1hkDFpe1/bKwy9jc2wyPne72HziuAANxOaOc5rOJ5dic0ODaBA2tw7SeXXzWNH+eyhtTdk2aVC5/SaoHMDW0cgelpqBXkffY+qHVV3sx1FJryhNY0aBNCLJu+RYyTwDFMAGtNQEe+2Y55GsXJB0xL28b7HAICQM9B7BILTgHq7y/j+08MdOvGbHiVfGJgOOhY446eYdefRDYTCLfYnxMy//0nCz9hIUxfnNzc2B+urMDMti0+ruHgWO58CBMixo9eE6D0zuhbpHpt7SlFB6NYqlgPugAqfz74bIgeu88M5bpmDZ6a4elE+Z42yrVELl49SvYGLvBW0K1S4iCptGFKL+XN3lIIRpL+MijEOmh5OB7A5PdrJNo8PscIjKytXM/rChdTdpk8YEcbqsG0v8JDPHOLjqCE9lrl/0sfhUqtbFJ2LzMhz+Lnga6jwN+tZvjZMTdCdqWpcvQi5b40G3dWBzjtR42uzW+xz7EhWDqb9u4PUYM3GHM38hK56LLpFPIP/XlU+c4jMMr1iGWnJXJNIgFjDpIBZzkITiaFB/K8iEP7emk3bsd0XgS19LaG8legWfrcfepGfoNQCFR4j63KJaDZC2kcq9iDnHmmTqY9qVebl/7TGvCDaJ6KV7sH0puZcXgA4G7ukFQ5HrOSci+Hsgfw/JFHQE9Ntoa7fz5Mm2NrxwW9vSqLrunTDv4ERmGaLs4xXg58Xi4UrztPfQPJH5f5AG9dh1Fbtcn9k8GbY5oh/ovosK/vQpuyrYZzJTc9VLHa6xc+Bw7U68oX4tBEGPw3XXKesVtRC7rX/LVZqu/sEcuPsP</diagram></mxfile>
\ No newline at end of file
$ cd /var/www/peertube/peertube-latest && NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run reset-password -- -u root
```
+Alternatively you can set the environment variable `PT_INITIAL_ROOT_PASSWORD`,
+to your own administrator password, although it must be 6 characters or more.
+
### What now?
Now your instance is up you can:
### Dependencies
-Install the [PeerTube dependencies](dependencies.md).
+Install the [PeerTube dependencies](dependencies.md) except PostgreSQL and Redis.
### Installation
```
$ git clone https://github.com/Chocobozzz/PeerTube.git
$ CLONE="$(pwd)/PeerTube"
-```
-
-Run ``yarn install --pure-lockfile``
-```
$ cd ${CLONE}
-$ yarn install --pure-lockfile
```
-Build server tools:
+Install dependencies and build CLI tools:
+
```
-$ cd ${CLONE}
-$ npm run build:server
+$ NOCLIENT=1 yarn install --pure-lockfile
+$ npm run setup:cli
```
### CLI wrapper
PEERTUBE_WEBSERVER_HTTPS=true
# If you need more than one IP as trust_proxy
# pass them as a comma separated array:
-PEERTUBE_TRUST_PROXY=["127.0.0.1"]
-#PEERTUBE_TRUST_PROXY=["127.0.0.1", "loopback", "192.168.1.0/24"]
+PEERTUBE_TRUST_PROXY=["127.0.0.1", "loopback", "172.18.0.0/16"]
#PEERTUBE_SMTP_USERNAME=
#PEERTUBE_SMTP_PASSWORD=
PEERTUBE_SMTP_HOSTNAME=postfix
1080:
__name: "PEERTUBE_TRANSCODING_1080P"
__format: "json"
+ 2160:
+ __name: "PEERTUBE_TRANSCODING_2160P"
+ __format: "json"
instance:
name: "PEERTUBE_INSTANCE_NAME"
labels:
traefik.enable: "false"
restart: "always"
+
+networks:
+ default:
+ ipam:
+ driver: default
+ config:
+ - subnet: 172.18.0.0/16
"typeRoots": [ "node_modules/@types", "server/typings" ]
},
"exclude": [
+ "server/tools/",
"client/node_modules",
"node_modules",
"dist",
# yarn lockfile v1
-"@babel/runtime@7.0.0":
+"@babel/code-frame@^7.0.0":
version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c"
- integrity sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8"
+ integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==
dependencies:
- regenerator-runtime "^0.12.0"
+ "@babel/highlight" "^7.0.0"
+
+"@babel/highlight@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4"
+ integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==
+ dependencies:
+ chalk "^2.0.0"
+ esutils "^2.0.2"
+ js-tokens "^4.0.0"
+
+"@babel/runtime@^7.0.0":
+ version "7.4.5"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.5.tgz#582bb531f5f9dc67d2fcb682979894f75e253f12"
+ integrity sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==
+ dependencies:
+ regenerator-runtime "^0.13.2"
"@samverschueren/stream-to-observable@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@types/async-lock/-/async-lock-1.1.1.tgz#81f218213bebcc5f740efe9648272c774a2e4b4b"
integrity sha512-TU1X8jmAU2BjwKryBFV/GDezz7Ge0xu9ZuYC7dy6wKj4hnL0JcxeseCOr/G2JkGylff6hdUBrR+Ee5ApAQeU5g==
-"@types/async@^2.0.40":
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/@types/async/-/async-2.4.1.tgz#43c3b2c60eab41c25ca0009c07ca7d619d943119"
- integrity sha512-C09BK/wXzbW+/JK9zckhe+FeSbg7NmvVjUWwApnw7ksRpUq3ecGLiq2Aw1LlY4Z/VmtdhSaIs7jO5/MWRYMcOA==
+"@types/async@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/async/-/async-3.0.0.tgz#d403560ee2aabccdb7936cb9a3fee5f147d626bd"
+ integrity sha512-DvEhEeG8ynipwkg7LtNHlO99+vEVbin+E+3YuzeJCM9TREewJ1B5fdZsQzykR7fKuh6rKh8mEir36zKd3uafOA==
"@types/bcrypt@^3.0.0":
version "3.0.0"
"@types/express" "*"
"@types/express-serve-static-core@*":
- version "4.16.2"
- resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.2.tgz#5ee8a22e602005be6767df6b2cba9879df3f75aa"
- integrity sha512-qgc8tjnDrc789rAQed8NoiFLV5VGcItA4yWNFphqGU0RcuuQngD00g3LHhWIK3HQ2XeDgVCmlNPDlqi3fWBHnQ==
+ version "4.16.6"
+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.6.tgz#66d4b29ece3e2fb6e5aac2232723002426e651bd"
+ integrity sha512-8wr3CA/EMybyb6/V8qvTRKiNkPmgUA26uA9XWD6hlA0yFDuqi4r2L0C2B0U2HAYltJamoYJszlkaWM31vrKsHg==
dependencies:
"@types/node" "*"
"@types/range-parser" "*"
"@types/express@*", "@types/express@^4.0.35":
- version "4.16.1"
- resolved "https://registry.yarnpkg.com/@types/express/-/express-4.16.1.tgz#d756bd1a85c34d87eaf44c888bad27ba8a4b7cf0"
- integrity sha512-V0clmJow23WeyblmACoxbHBu2JKlE5TiIme6Lem14FnPW9gsttyHtk6wq7njcdIWH1njAaFgR8gW09lgY98gQg==
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.0.tgz#49eaedb209582a86f12ed9b725160f12d04ef287"
+ integrity sha512-CjaMu57cjgjuZbh9DpkloeGxV45CnMGlVd+XpG7Gm9QgVrd7KFq+X4HY0vM+2v0bczS48Wg7bvnMY5TN+Xmcfw==
dependencies:
"@types/body-parser" "*"
"@types/express-serve-static-core" "*"
dependencies:
"@types/node" "*"
-"@types/fs-extra@^5.0.4":
- version "5.0.5"
- resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.0.5.tgz#080d90a792f3fa2c5559eb44bd8ef840aae9104b"
- integrity sha512-w7iqhDH9mN8eLClQOYTkhdYUOSpp25eXxfc6VbFOGtzxW34JcvctH2bKjj4jD4++z4R5iO5D+pg48W2e03I65A==
+"@types/fs-extra@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-7.0.0.tgz#9c4ad9e1339e7448a76698829def1f159c1b636c"
+ integrity sha512-ndoMMbGyuToTy4qB6Lex/inR98nPiNHacsgMPvy+zqMLgSxbt8VtWpDArpGp69h1fEDQHn1KB+9DWD++wgbwYA==
dependencies:
"@types/node" "*"
"@types/ioredis@*":
- version "4.0.10"
- resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.0.10.tgz#ca8bd95ca7d5fee32cbc5a0bf92fc29264bee237"
- integrity sha512-1ImAFcW5eg4f9UrftlVQPmGCkK1VyCqJ12c2wy3NlEQvzBC0GX64WlN01xj5iETqvsjczJHU+CRMPraBy9pX+g==
+ version "4.0.11"
+ resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.0.11.tgz#4acf9d7912944bcf1e96dd6adba2f16c07ed9ae7"
+ integrity sha512-spuEM4/UxlFH95NCrMojH9FTP3SLm8N2Itb9f0z0pca1IVdlPHobjps+KccEiUuYdfhzpdKOox8yGoqO9vahaw==
dependencies:
"@types/node" "*"
"@types/node" "*"
"@types/lodash@^4.14.64":
- version "4.14.123"
- resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.123.tgz#39be5d211478c8dd3bdae98ee75bb7efe4abfe4d"
- integrity sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q==
+ version "4.14.133"
+ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.133.tgz#430721c96da22dd1694443e68e6cec7ba1c1003d"
+ integrity sha512-/3JqnvPnY58GLzG3Y7fpphOhATV1DDZ/Ak3DQufjlRK5E4u+s0CfClfNFtAGBabw+jDGtRFbOZe+Z02ZMWCBNQ==
"@types/magnet-uri@*", "@types/magnet-uri@^5.1.1":
version "5.1.2"
"@types/node" "*"
"@types/mocha@^5.0.0":
- version "5.2.6"
- resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.6.tgz#b8622d50557dd155e9f2f634b7d68fd38de5e94b"
- integrity sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==
+ version "5.2.7"
+ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea"
+ integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==
"@types/morgan@^1.7.32":
version "1.7.35"
"@types/express" "*"
"@types/node@*":
- version "11.13.0"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.0.tgz#b0df8d6ef9b5001b2be3a94d909ce3c29a80f9e1"
- integrity sha512-rx29MMkRdVmzunmiA4lzBYJNnXsW/PhG4kMBy2ATsYaDjGGR75dCFEVVROKpNwlVdcUX3xxlghKQOeDPBJobng==
+ version "12.0.5"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.5.tgz#ac14404c33d1a789973c45379a67f7f7e58a01b9"
+ integrity sha512-CFLSALoE+93+Hcb5pFjp0J1uMrrbLRe+L1+gFwerJ776R3TACSF0kTVRQ7AvRa7aFx70nqYHAc7wQPlt9kY2Mg==
"@types/node@^10.0.8":
- version "10.14.4"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.4.tgz#1c586b991457cbb58fef51bc4e0cfcfa347714b5"
- integrity sha512-DT25xX/YgyPKiHFOpNuANIQIVvYEwCWXgK2jYYwqgaMrYE6+tq+DtmMwlD3drl6DJbUwtlIDnn0d7tIn/EbXBg==
+ version "10.14.8"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9"
+ integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw==
-"@types/nodemailer@^4.3.1":
- version "4.6.7"
- resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-4.6.7.tgz#ac3c594fac6daf7f71eb4d31c9e4c88b62dbcb87"
- integrity sha512-slR1wz8I8O20CHNBNhYhObRZ8zeG5FnfFUWLZKk1f0UDYaLZOsBjUfCC9VEFi7oSRCC886DfKmq1JncPDMOrng==
+"@types/nodemailer@^6.2.0":
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.2.0.tgz#369d3c6ff51201670f3e5469b00c1d204ec8f894"
+ integrity sha512-WGGEk/BGRLuYF3gyoTwbtKg5tCexZzb5lkTsis2k7GkAzlg4x2299/SC6Ssdj3X/5TzT1BHVc8zcFg/7KSzBLw==
dependencies:
"@types/node" "*"
+"@types/normalize-package-data@^2.4.0":
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
+ integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
+
"@types/oauth2-server@^3.0.8":
version "3.0.10"
resolved "https://registry.yarnpkg.com/@types/oauth2-server/-/oauth2-server-3.0.10.tgz#ea671a6ad3d02062aac5f7c1ba1fb9c468314db0"
integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
"@types/redis@*", "@types/redis@^2.8.5":
- version "2.8.12"
- resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.12.tgz#6405d7ece0d6cc037151b7141cef9ad3cd06f3ac"
- integrity sha512-eT5cGYr08OnF6OlAHdc2hVOBAKBpfQQNQHsWEvUwRPFiXRd+vv+hOHSSIo4xB7M5vZOZdjMT2OUlXYqo3YlIGQ==
+ version "2.8.13"
+ resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.13.tgz#fdd76d9a8b7c36ff24d8506a94ef2a890c87f498"
+ integrity sha512-p86cm5P6DMotUqCS6odQRz0JJwc5QXZw9eyH0ALVIqmq12yqtex5ighWyGFHKxak9vaA/GF/Ilu0KZ0MuXXUbg==
dependencies:
"@types/node" "*"
"@types/mime" "*"
"@types/sharp@^0.22.1":
- version "0.22.1"
- resolved "https://registry.yarnpkg.com/@types/sharp/-/sharp-0.22.1.tgz#4fccaa9cc580d859916bee693aa7ae7447d0e0ba"
- integrity sha512-Reri4hhX77JBx6HWt2a2CLO0xjHMFHDaeBYMslUsTSHGRFQnk+VpoH25g7/L6QzyyNNmxTekK+j+lFFjK3OkqA==
+ version "0.22.2"
+ resolved "https://registry.yarnpkg.com/@types/sharp/-/sharp-0.22.2.tgz#c9b613816ec000d94f153259b25ae41f874a75f5"
+ integrity sha512-oH49f42h3nf/qys0weYsaTGiMv67wPB769ynCoPfBAVwjjxFF3QtIPEe3MfhwyNjQAhQhTEfnmMKvVZfcFkhIw==
dependencies:
"@types/node" "*"
"@types/events" "*"
"@types/node" "*"
-JSONStream@^1.3.4, JSONStream@^1.3.5:
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
- integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
- dependencies:
- jsonparse "^1.2.0"
- through ">=2.2.7 <3"
-
-abbrev@1, abbrev@~1.1.1:
+abbrev@1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
mime-types "~2.1.6"
negotiator "0.5.3"
-accepts@~1.3.4, accepts@~1.3.5:
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2"
- integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I=
+accepts@~1.3.4, accepts@~1.3.7:
+ version "1.3.7"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
+ integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
dependencies:
- mime-types "~2.1.18"
- negotiator "0.6.1"
+ mime-types "~2.1.24"
+ negotiator "0.6.2"
acorn-jsx@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
-agent-base@4, agent-base@^4.1.0, agent-base@~4.2.1:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
- integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==
- dependencies:
- es6-promisify "^5.0.0"
-
-agentkeepalive@^3.4.1:
- version "3.5.2"
- resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz#a113924dd3fa24a0bc3b78108c450c2abee00f67"
- integrity sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==
- dependencies:
- humanize-ms "^1.2.1"
-
ajv-keywords@^1.0.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
+ansi-regex@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
+ integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
+
ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
-ansi-styles@^3.2.1:
+ansi-styles@^3.2.0, ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
-ansicolors@~0.3.2:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979"
- integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=
-
-ansistyles@~0.1.3:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539"
- integrity sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk=
-
any-observable@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b"
resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=
-application-config-path@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/application-config-path/-/application-config-path-0.1.0.tgz#193c5f0a86541a4c66fba1e2dc38583362ea5e8f"
- integrity sha1-GTxfCoZUGkxm+6Hi3DhYM2LqXo8=
-
-application-config@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/application-config/-/application-config-1.0.1.tgz#5aa2e2a5ed6abd2e5d1d473d3596f574044fe9e7"
- integrity sha1-WqLipe1qvS5dHUc9NZb1dARP6ec=
- dependencies:
- application-config-path "^0.1.0"
- mkdirp "^0.5.1"
-
-aproba@^1.0.3, aproba@^1.1.1, aproba@^1.1.2:
+aproba@^1.0.3:
version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
-"aproba@^1.1.2 || 2", aproba@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
- integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
-
-archy@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
- integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=
-
are-we-there-yet@~1.1.2:
version "1.1.5"
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
-asap@^2.0.0:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
- integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
-
asn1@~0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
async-each@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.2.tgz#8b8a7ca2a658f927e9f307d6d1a42f4199f0f735"
- integrity sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg==
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
+ integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
-async-limiter@~1.0.0:
+async-limiter@^1.0.0, async-limiter@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==
resolved "https://registry.yarnpkg.com/async/-/async-1.5.1.tgz#b05714f4b11b357bf79adaffdd06da42d0766c10"
integrity sha1-sFcU9LEbNXv3mtr/3QbaQtB2bBA=
-async@>=0.2.9, async@^2.0.0, async@^2.6.1:
+async@>=0.2.9, async@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/async/-/async-3.0.1.tgz#dfeb34657d1e63c94c0eee424297bf8a2c9a8182"
+ integrity sha512-ZswD8vwPtmBZzbn9xyi8XBQWXH3AvOQ43Za1KWYq7JeycrZuUYzx01KvHcVbXltjqH4y0MWrQ33008uLTqXuDw==
+
+async@^2.6.1:
version "2.6.2"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381"
integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
-babel-code-frame@^6.22.0:
- version "6.26.0"
- resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
- integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=
- dependencies:
- chalk "^1.1.3"
- esutils "^2.0.2"
- js-tokens "^3.0.2"
-
backo2@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
dependencies:
tweetnacl "^0.14.3"
-bcrypt@3.0.5:
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-3.0.5.tgz#37a296c48ebf39fe6b28e4da3a221bf80da5aa26"
- integrity sha512-m4o91nB+Ce8696Ao4R3B/WtVWTc1Lszgd098/OIjU9D/URmdYwT3ooBs9uv1b97J5YhZweTq9lldPefTYZ0TwA==
+bcrypt@3.0.6:
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-3.0.6.tgz#f607846df62d27e60d5e795612c4f67d70206eb2"
+ integrity sha512-taA5bCTfXe7FUjKroKky9EXpdhkVvhE5owfxfLYodbrAR1Ul3juLmIQmIQBK4L9a5BuUcE6cqmwT+Da20lF9tg==
dependencies:
- nan "2.13.1"
+ nan "2.13.2"
node-pre-gyp "0.12.0"
bencode@^2.0.0:
dependencies:
callsite "1.0.0"
-bin-links@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-1.1.2.tgz#fb74bd54bae6b7befc6c6221f25322ac830d9757"
- integrity sha512-8eEHVgYP03nILphilltWjeIjMbKyJo3wvp9K816pHbhP301ismzw15mxAAEVQ/USUwcP++1uNrbERbp8lOA6Fg==
- dependencies:
- bluebird "^3.5.0"
- cmd-shim "^2.0.2"
- gentle-fs "^2.0.0"
- graceful-fs "^4.1.11"
- write-file-atomic "^2.3.0"
-
binary-extensions@^1.0.0:
version "1.13.1"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
resolved "https://registry.yarnpkg.com/binary-search/-/binary-search-1.3.5.tgz#479ad009589e0273cf54e5d74ab1546c489078ce"
integrity sha512-RHFP0AdU6KAB0CCZsRMU2CJTk2EpL8GLURT+4gilpjr1f/7M91FgUMnXuQLmf3OKLet34gjuNFwO7e4agdX5pw==
-bindings@^1.3.0, bindings@^1.5.0:
+bindings@^1.3.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
dependencies:
file-uri-to-path "1.0.0"
-bindings@~1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11"
- integrity sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=
-
bindings@~1.3.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.1.tgz#21fc7c6d67c18516ec5aaa2815b145ff77b26ea5"
xtend "^4.0.0"
bittorrent-tracker@^9.0.0:
- version "9.10.1"
- resolved "https://registry.yarnpkg.com/bittorrent-tracker/-/bittorrent-tracker-9.10.1.tgz#5de14aac012a287af394d3cc9eda1ec6cc956f11"
- integrity sha512-n5zTL/g6Wt0rb2EnkiyiaGYhth7I/N0/xMqGUpvGX/7g1scDGBVPhJnXR8lfp3/OMj681fv40o4q/otECMtZSA==
+ version "9.11.0"
+ resolved "https://registry.yarnpkg.com/bittorrent-tracker/-/bittorrent-tracker-9.11.0.tgz#9911f9c14e5a29f84990a0c31b3d83dd16eb2876"
+ integrity sha512-T1zvW/kSeEnWT4I3JE+6c7aZbO5jtleZyQe911SyzIxFF9DvtUNWXud3p5ZUkXaoI2xXwfpvlks5VFj5SKEB+A==
dependencies:
bencode "^2.0.0"
bittorrent-peerid "^1.0.2"
bn.js "^4.4.0"
compact2string "^1.2.0"
- debug "^3.1.0"
- inherits "^2.0.1"
+ debug "^4.0.1"
ip "^1.0.1"
lru "^3.0.0"
minimist "^1.1.1"
uniq "^1.0.1"
unordered-array-remove "^1.0.2"
ws "^6.0.0"
- xtend "^4.0.0"
optionalDependencies:
bufferutil "^4.0.0"
utf-8-validate "^5.0.1"
inherits "^2.0.1"
readable-stream "^2.0.4"
-block-stream@*:
- version "0.0.9"
- resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
- integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=
- dependencies:
- inherits "~2.0.0"
-
bluebird@3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=
-bluebird@^3.0.5, bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.3:
- version "3.5.3"
- resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7"
- integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==
+bluebird@^3.0.5, bluebird@^3.5.0, bluebird@^3.5.3:
+ version "3.5.5"
+ resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f"
+ integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==
bn.js@=2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
-body-parser@1.18.3, body-parser@^1.12.4:
- version "1.18.3"
- resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4"
- integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=
+body-parser@1.19.0, body-parser@^1.12.4:
+ version "1.19.0"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
+ integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
dependencies:
- bytes "3.0.0"
+ bytes "3.1.0"
content-type "~1.0.4"
debug "2.6.9"
depd "~1.1.2"
- http-errors "~1.6.3"
- iconv-lite "0.4.23"
+ http-errors "1.7.2"
+ iconv-lite "0.4.24"
on-finished "~2.3.0"
- qs "6.5.2"
- raw-body "2.3.3"
- type-is "~1.6.16"
+ qs "6.7.0"
+ raw-body "2.4.0"
+ type-is "~1.6.17"
boxen@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
-builtins@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88"
- integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og=
-
bull@^3.4.2:
- version "3.7.0"
- resolved "https://registry.yarnpkg.com/bull/-/bull-3.7.0.tgz#ec9a8721a2cfb0421c501d28553ac1f9f025414d"
- integrity sha512-DHCALp+OOahK+q2hB3sZQew0CJn4W3zYIQsdMlnBCy7JYCnJ/bdj0MFHjo5k0ZhNZxzwhLErXt1yd3llV494UQ==
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/bull/-/bull-3.10.0.tgz#5879b1201d0ed0c987fa1f42114d3dc5abf3da68"
+ integrity sha512-LbQsc7c+eYd7IaJD7tS373yKLYttjTfoPZ+9xYYlPM5+gutAjofSTsESOGGyaxyX2lE1dkg+eWhUK5kAPl5Zow==
dependencies:
cron-parser "^2.7.3"
debuglog "^1.0.0"
- get-port latest
+ get-port "^5.0.0"
ioredis "^4.5.1"
lodash "^4.17.11"
- p-timeout "^2.0.1"
+ p-timeout "^3.1.0"
promise.prototype.finally "^3.1.0"
- semver "^5.6.0"
+ semver "^6.1.1"
util.promisify "^1.0.0"
uuid "^3.2.1"
dicer "0.2.5"
readable-stream "1.1.x"
-byline@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1"
- integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=
-
-byte-size@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-5.0.1.tgz#4b651039a5ecd96767e71a3d7ed380e48bed4191"
- integrity sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw==
-
-bytes@3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
- integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
-
-bytes@^3.0.0:
+bytes@3.1.0, bytes@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
-cacache@^11.0.1, cacache@^11.3.2:
- version "11.3.2"
- resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.2.tgz#2d81e308e3d258ca38125b676b98b2ac9ce69bfa"
- integrity sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==
- dependencies:
- bluebird "^3.5.3"
- chownr "^1.1.1"
- figgy-pudding "^3.5.1"
- glob "^7.1.3"
- graceful-fs "^4.1.15"
- lru-cache "^5.1.1"
- mississippi "^3.0.0"
- mkdirp "^0.5.1"
- move-concurrently "^1.0.1"
- promise-inflight "^1.0.1"
- rimraf "^2.6.2"
- ssri "^6.0.1"
- unique-filename "^1.1.1"
- y18n "^4.0.0"
-
cache-base@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
union-value "^1.0.0"
unset-value "^1.0.0"
-call-limit@~1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/call-limit/-/call-limit-1.1.0.tgz#6fd61b03f3da42a2cd0ec2b60f02bd0e71991fea"
- integrity sha1-b9YbA/PaQqLNDsK2DwK9DnGZH+o=
-
call-me-maybe@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
camelcase@^5.0.0:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.0.tgz#0a110882cbeba41f72f99fcf918f4a0a92a13ebf"
- integrity sha512-Y05ICatFYPAfykDIB7VdwSJ0LUl1yq/BwO2OpyGGLjiRe1fgzTwVypPiWnzkGFOVFHXrCXUNBl86bpjBhZWSJg==
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
+ integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
camelize@1.0.0:
version "1.0.0"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
chai-json-schema@^1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/chai-json-schema/-/chai-json-schema-1.5.0.tgz#6960719e40f71fd5b377c9282e5c9a46799474f6"
- integrity sha1-aWBxnkD3H9Wzd8koLlyaRnmUdPY=
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/chai-json-schema/-/chai-json-schema-1.5.1.tgz#d9ae4c8f8c6e24ff4d402ceddfaa865d1ca107f4"
+ integrity sha512-TR/xPDxRhqwFFCWg1HgL8nNWbpNfUwaib6pBN++QKpnd0t+o3+MBvAn5CM1mpdUMaM76oJAtUjGKdjGad01lIA==
dependencies:
jsonpointer.js "0.4.0"
- tv4 "~1.2.7"
+ tv4 "^1.3.0"
chai-xml@^0.3.2:
version "0.3.2"
strip-ansi "^3.0.0"
supports-color "^2.0.0"
-chalk@^2.0.1, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2:
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=
-chokidar@^2.1.0:
- version "2.1.5"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.5.tgz#0ae8434d962281a5f56c72869e79cb6d9d86ad4d"
- integrity sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A==
+chokidar@^2.1.5:
+ version "2.1.6"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5"
+ integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==
dependencies:
anymatch "^2.0.0"
async-each "^1.0.1"
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==
+circular-json@^0.5.9:
+ version "0.5.9"
+ resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d"
+ integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==
+
class-utils@^0.3.5:
version "0.3.6"
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
-cli-columns@^3.1.2:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/cli-columns/-/cli-columns-3.1.2.tgz#6732d972979efc2ae444a1f08e08fa139c96a18e"
- integrity sha1-ZzLZcpee/CrkRKHwjgj6E5yWoY4=
- dependencies:
- string-width "^2.0.0"
- strip-ansi "^3.0.1"
-
cli-cursor@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
dependencies:
restore-cursor "^2.0.0"
-cli-table3@^0.5.0, cli-table3@^0.5.1:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202"
- integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==
- dependencies:
- object-assign "^4.1.0"
- string-width "^2.1.1"
- optionalDependencies:
- colors "^1.1.2"
-
cli-table@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23"
strip-ansi "^4.0.0"
wrap-ansi "^2.0.0"
-clone@^1.0.2:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
- integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
+cliui@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
+ integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==
+ dependencies:
+ string-width "^3.1.0"
+ strip-ansi "^5.2.0"
+ wrap-ansi "^5.1.0"
closest-to@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.0.12.tgz#d5deff2a520717bc98313979b687309b2d368e29"
integrity sha512-21O0kGmvED5OJ7ZTdqQ5lQQ+sjuez33R+d35jZKLwqUb5mqcPHUsxOSzj61+LHVtxGZd1kShbQM3MjB/gBJkVg==
-cmd-shim@^2.0.2, cmd-shim@~2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb"
- integrity sha1-b8vamUg6j9FdfTChlspp1oii79s=
- dependencies:
- graceful-fs "^4.1.2"
- mkdirp "~0.5.0"
-
co-bluebird@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/co-bluebird/-/co-bluebird-1.1.0.tgz#c8b9f3a9320a7ed30987dcca1a5c3cff59655c7c"
color-convert "^1.9.1"
color-string "^1.5.2"
-color@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/color/-/color-3.1.0.tgz#d8e9fb096732875774c84bf922815df0308d0ffc"
- integrity sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg==
+color@^3.1.1:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10"
+ integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==
dependencies:
color-convert "^1.9.1"
color-string "^1.5.2"
integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==
colorspace@1.1.x:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.1.tgz#9ac2491e1bc6f8fb690e2176814f8d091636d972"
- integrity sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.2.tgz#e0128950d082b86a2168580796a0aa5d6c68d8c5"
+ integrity sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==
dependencies:
color "3.0.x"
text-hex "1.0.x"
-columnify@~1.5.4:
- version "1.5.4"
- resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb"
- integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=
- dependencies:
- strip-ansi "^3.0.0"
- wcwidth "^1.0.0"
-
combined-stream@^1.0.6, combined-stream@~1.0.6:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828"
- integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+ integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
dependencies:
delayed-stream "~1.0.0"
graceful-readlink ">= 1.0.0"
commander@^2.12.1, commander@^2.13.0, commander@^2.14.1, commander@^2.7.1, commander@^2.8.1, commander@^2.9.0:
- version "2.19.0"
- resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
- integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
+ version "2.20.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
+ integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
compact2string@^1.2.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3"
integrity sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=
-component-emitter@1.2.1, component-emitter@^1.2.0, component-emitter@^1.2.1:
+component-emitter@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
+component-emitter@^1.2.0, component-emitter@^1.2.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
+ integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
+
component-inherit@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
-concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.5.2:
+concat-stream@^1.4.6, concat-stream@^1.5.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
readable-stream "^2.2.2"
typedarray "^0.0.6"
-concurrently@^4.0.1:
+concurrently@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-4.1.0.tgz#17fdf067da71210685d9ea554423ef239da30d33"
integrity sha512-pwzXCE7qtOB346LyO9eFWpkFJVO3JQZ/qU/feGeaAHiX1M3Rw3zgXKc5cZ8vSH5DGygkjzLFDzA/pwoQDkRNGg==
tree-kill "^1.1.0"
yargs "^12.0.1"
-config-chain@^1.1.12:
- version "1.1.12"
- resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa"
- integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==
- dependencies:
- ini "^1.3.4"
- proto-list "~1.2.1"
-
config@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/config/-/config-3.0.1.tgz#c3118e2eb45fdfd135277339f87e2492559cb147"
- integrity sha512-TBNrrk2b6AybUohqXw2AydglFBL9b/+1GG93Di6Fm6x1SyVJ5PYgo+mqY2X0KpU9m0PJDSbFaC5H95utSphtLw==
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/config/-/config-3.1.0.tgz#c7d49c4171e8f6cb61c1d69e22647ffd60492548"
+ integrity sha512-t6oDeNQbsIWa+D/KF4959TANzjSHLv1BA/hvL8tHEA3OUSWgBXELKaONSI6nr9oanbKs0DXonjOWLcrtZ3yTAA==
dependencies:
json5 "^1.0.1"
write-file-atomic "^2.0.0"
xdg-basedir "^3.0.0"
-console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0:
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b"
integrity sha1-h0dsamfI2qh+Muh2Ft+IO6f7Bxs=
-content-disposition@0.5.2:
- version "0.5.2"
- resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
- integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ=
+content-disposition@0.5.3:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
+ integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
+ dependencies:
+ safe-buffer "5.1.2"
content-security-policy-builder@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
+cookie@0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
+ integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
+
cookiejar@^2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c"
integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==
-copy-concurrently@^1.0.0:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
- integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==
- dependencies:
- aproba "^1.1.1"
- fs-write-stream-atomic "^1.0.8"
- iferr "^0.1.5"
- mkdirp "^0.5.1"
- rimraf "^2.5.4"
- run-queue "^1.0.0"
-
copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
core-js@^2.5.7:
- version "2.6.5"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895"
- integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
+ integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
object-assign "^4"
vary "^1"
-cosmiconfig@^5.0.2, cosmiconfig@^5.0.7:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.0.tgz#45038e4d28a7fe787203aede9c25bca4a08b12c8"
- integrity sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g==
+cosmiconfig@^5.2.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
+ integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==
dependencies:
import-fresh "^2.0.0"
is-directory "^0.3.1"
- js-yaml "^3.13.0"
+ js-yaml "^3.13.1"
parse-json "^4.0.0"
create-error-class@^3.0.0:
simple-sha1 "^2.0.0"
cron-parser@^2.7.3:
- version "2.10.0"
- resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.10.0.tgz#d6bed39cfa6163930f89b1ade82df7b46f52b82b"
- integrity sha512-E181Gbg+wYT0hSikwBOokL7VHgJDYUlFsRFHIlnTP8GGefhcIyf8PSc2IXztmghj5mhAZupU0n3jKfEpZVEmVg==
+ version "2.11.0"
+ resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.11.0.tgz#c3bf477e01de6a56938d6625b92efd6cec30a8a5"
+ integrity sha512-L5LAGlvq2xmCLErhjQRX8IL5v72y8jhGOaxrarYOhse0kJjJGb/vY/0sV/c7F/SylJGkUIY2iZPPJXZD3glZqA==
dependencies:
is-nan "^1.2.1"
moment-timezone "^0.5.23"
resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2"
integrity sha1-IegLK+hYD5i0aPN5QwZisEbDStI=
-cyclist@~0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"
- integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=
-
d@1:
version "1.0.0"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
-deasync@^0.1.4:
- version "0.1.14"
- resolved "https://registry.yarnpkg.com/deasync/-/deasync-0.1.14.tgz#232ea2252b443948cad033d792eb3b24b0a3d828"
- integrity sha512-wN8sIuEqIwyQh72AG7oY6YQODCxIp1eXzEZlZznBuwDF8Q03Tdy9QNp1BNZXeadXoklNrw+Ip1fch+KXo/+ASw==
- dependencies:
- bindings "~1.2.1"
- node-addon-api "^1.6.0"
-
debug@2.2.0, debug@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da"
dependencies:
ms "0.7.2"
-debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3:
+debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.3.3:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
dependencies:
ms "2.0.0"
-debug@3.1.0, debug@~3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
- integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
- dependencies:
- ms "2.0.0"
-
-debug@3.2.6, debug@^3.1.0:
+debug@3.2.6, debug@^3.1.0, debug@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
dependencies:
ms "^2.1.1"
-debuglog@^1.0.0, debuglog@^1.0.1:
+debug@~3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
+ integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
+ dependencies:
+ ms "2.0.0"
+
+debuglog@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
-decamelize@^1.1.1, decamelize@^1.2.0:
+decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a"
integrity sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw==
-defaults@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
- integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=
- dependencies:
- clone "^1.0.2"
-
define-properties@^1.1.1, define-properties@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
denque@^1.1.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.0.tgz#79e2f0490195502107f24d9553f374837dabc916"
- integrity sha512-gh513ac7aiKrAgjiIBWZG0EASyDF9p4JMWwKA8YU5s9figrL5SRNEMT6FDynsegakuhWd1wVqTvqvqAoDxw7wQ==
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf"
+ integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==
depd@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
-descrevit@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/descrevit/-/descrevit-0.1.1.tgz#c0f5840de0a0f7b1b8b4078569b173327947d5da"
- integrity sha1-wPWEDeCg97G4tAeFabFzMnlH1do=
- dependencies:
- deasync "^0.1.4"
-
destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
-detect-file@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
- integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
-
-detect-indent@~5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d"
- integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50=
-
detect-libc@^1.0.2, detect-libc@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
-detect-newline@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2"
- integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=
-
-dezalgo@^1.0.0, dezalgo@~1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456"
- integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=
- dependencies:
- asap "^2.0.0"
- wrappy "1"
-
diagnostics@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a"
readable-stream "1.1.x"
streamsearch "0.1.2"
-diff@3.5.0, diff@^3.1.0, diff@^3.2.0:
+diff@3.5.0, diff@^3.2.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
+diff@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff"
+ integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==
+
dns-prefetch-control@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz#60ddb457774e178f1f9415f0cabb0e85b0b300b2"
integrity sha1-YN20V3dOF48flBXwyrsOhbCzALI=
-docopt@~0.6.2:
- version "0.6.2"
- resolved "https://registry.yarnpkg.com/docopt/-/docopt-0.6.2.tgz#b28e9e2220da5ec49f7ea5bb24a47787405eeb11"
- integrity sha1-so6eIiDaXsSffqW7JKR3h0Be6xE=
-
doctrine@0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523"
resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58"
integrity sha1-WTKJDcn04vGeXrAqIAJuXl78j1g=
-dot-json@^1.0.3:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/dot-json/-/dot-json-1.1.0.tgz#36dc7d40c00afaef2823b715b94325ba39f1bd89"
- integrity sha512-PiQZW9/C8xILPYK2bOye/cbPZrakNEkt28jFb8RlPCwsoMAHYYw9T8JoACxgttHL9Y2AmdqVvibbZJHtLgeqTQ==
- dependencies:
- docopt "~0.6.2"
- underscore-keypath "~0.0.22"
-
dot-prop@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
dependencies:
is-obj "^1.0.0"
-dotenv@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef"
- integrity sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==
-
dottie@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/dottie/-/dottie-2.0.1.tgz#697ad9d72004db7574d21f892466a3c285893659"
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
-duplexify@^3.2.0, duplexify@^3.4.2, duplexify@^3.5.0, duplexify@^3.6.0:
+duplexify@^3.2.0, duplexify@^3.5.0, duplexify@^3.6.0:
version "3.7.1"
resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
dependencies:
safe-buffer "^5.0.1"
-editor@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742"
- integrity sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=
-
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
hash.js "^1.0.0"
inherits "^2.0.1"
+emoji-regex@^7.0.1:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
+ integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
+
enabled@1.0.x:
version "1.0.2"
resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
-encoding@^0.1.11, encoding@^0.1.12, encoding@~0.1.12:
+encoding@^0.1.12, encoding@~0.1.12:
version "0.1.12"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=
resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88"
integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==
-err-code@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960"
- integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=
-
-errno@~0.1.7:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
- integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
- dependencies:
- prr "~1.0.1"
-
error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
is-symbol "^1.0.2"
es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.9, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
- version "0.10.49"
- resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.49.tgz#059a239de862c94494fec28f8150c977028c6c5e"
- integrity sha512-3NMEhi57E31qdzmYp2jwRArIUsj1HI/RxbQ4bgnSB+AIKIxsAmTiK83bYMifIcpWvEc3P1X30DhUKOqEtF/kvg==
+ version "0.10.50"
+ resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.50.tgz#6d0e23a0abdb27018e5ac4fd09b412bc5517a778"
+ integrity sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==
dependencies:
es6-iterator "~2.0.3"
es6-symbol "~3.1.1"
es6-symbol "~3.1.1"
event-emitter "~0.3.5"
-es6-promise@^4.0.3:
- version "4.2.6"
- resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f"
- integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==
-
-es6-promisify@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
- integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
- dependencies:
- es6-promise "^4.0.3"
-
es6-promisify@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.1.tgz#6edaa45f3bd570ffe08febce66f7116be4b1cdb6"
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
-expand-tilde@^2.0.0, expand-tilde@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
- integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=
- dependencies:
- homedir-polyfill "^1.0.1"
-
-expect-ct@0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/expect-ct/-/expect-ct-0.1.1.tgz#de84476a2dbcb85000d5903737e9bc8a5ba7b897"
- integrity sha512-ngXzTfoRGG7fYens3/RMb6yYoVLvLMfmsSllP/mZPxNHgFq41TmPSLF/nLY7fwoclI2vElvAmILFWGUYqdjfCg==
+expect-ct@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/expect-ct/-/expect-ct-0.2.0.tgz#3a54741b6ed34cc7a93305c605f63cd268a54a62"
+ integrity sha512-6SK3MG/Bbhm8MsgyJAylg+ucIOU71/FzyFalcfu5nY19dH8y/z0tBJU0wrNBXD4B27EoQtqPF/9wqH0iYAd04g==
express-oauth-server@^2.0.0:
version "2.0.0"
express "^4.13.3"
oauth2-server "3.0.0"
-express-rate-limit@^3.1.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-3.4.0.tgz#c053ee294feac6d3529863de549438749fd83ef1"
- integrity sha512-SktWQGHhTQfIOZykiVIaoqmHCptqq177fEbumVytWsMpEqe+g78IFrfzivJTimoCdMZ5+vYJ5/a/w1darXMv+A==
- dependencies:
- defaults "^1.0.3"
+express-rate-limit@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-4.0.4.tgz#a495338ae9e58c856b66d1346ec0d86f43ba2e43"
+ integrity sha512-DLRj2vMO7Xgai8qWKU9O6ZztF2bdDmfFNFi9k3G9BPzJ+7MG7eWaaBikbe0eBpNGSxU8JziwW0PQKG78aNWa6g==
express-validator@^5.0.0:
version "5.3.1"
vary "~1.0.1"
express@^4.12.4, express@^4.13.3:
- version "4.16.4"
- resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e"
- integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==
+ version "4.17.1"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
+ integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
dependencies:
- accepts "~1.3.5"
+ accepts "~1.3.7"
array-flatten "1.1.1"
- body-parser "1.18.3"
- content-disposition "0.5.2"
+ body-parser "1.19.0"
+ content-disposition "0.5.3"
content-type "~1.0.4"
- cookie "0.3.1"
+ cookie "0.4.0"
cookie-signature "1.0.6"
debug "2.6.9"
depd "~1.1.2"
encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
- finalhandler "1.1.1"
+ finalhandler "~1.1.2"
fresh "0.5.2"
merge-descriptors "1.0.1"
methods "~1.1.2"
on-finished "~2.3.0"
- parseurl "~1.3.2"
+ parseurl "~1.3.3"
path-to-regexp "0.1.7"
- proxy-addr "~2.0.4"
- qs "6.5.2"
- range-parser "~1.2.0"
+ proxy-addr "~2.0.5"
+ qs "6.7.0"
+ range-parser "~1.2.1"
safe-buffer "5.1.2"
- send "0.16.2"
- serve-static "1.13.2"
- setprototypeof "1.1.0"
- statuses "~1.4.0"
- type-is "~1.6.16"
+ send "0.17.1"
+ serve-static "1.14.1"
+ setprototypeof "1.1.1"
+ statuses "~1.5.0"
+ type-is "~1.6.18"
utils-merge "1.0.1"
vary "~1.1.2"
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz#04b26106cc56681f51a044cfc0d76cf0008ac2c2"
integrity sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==
-feature-policy@0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/feature-policy/-/feature-policy-0.2.0.tgz#22096de49ab240176878ffe2bde2f6ff04d48c43"
- integrity sha512-2hGrlv6efG4hscYVZeaYjpzpT6I2OZgYqE2yDUzeAcKj2D1SH0AsEzqJNXzdoglEddcIXQQYop3lD97XpG75Jw==
+feature-policy@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/feature-policy/-/feature-policy-0.3.0.tgz#7430e8e54a40da01156ca30aaec1a381ce536069"
+ integrity sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==
fecha@^2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==
-figgy-pudding@^3.4.1, figgy-pudding@^3.5.1:
- version "3.5.1"
- resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
- integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==
-
figures@^1.3.5, figures@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
on-finished "~2.3.0"
unpipe "~1.0.0"
-finalhandler@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
- integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==
+finalhandler@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
+ integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
dependencies:
debug "2.6.9"
encodeurl "~1.0.2"
escape-html "~1.0.3"
on-finished "~2.3.0"
- parseurl "~1.3.2"
- statuses "~1.4.0"
+ parseurl "~1.3.3"
+ statuses "~1.5.0"
unpipe "~1.0.0"
-find-npm-prefix@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf"
- integrity sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA==
-
-find-parent-dir@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.0.tgz#33c44b429ab2b2f0646299c5f9f718f376ff8d54"
- integrity sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=
-
-find-up@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
- integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
- dependencies:
- locate-path "^2.0.0"
-
-find-up@^3.0.0:
+find-up@3.0.0, find-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
dependencies:
locate-path "^3.0.0"
-findup-sync@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
- integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=
+find-up@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.0.0.tgz#c367f8024de92efb75f2d4906536d24682065c3a"
+ integrity sha512-zoH7ZWPkRdgwYCDVoQTzqjG8JSPANhtvLhh4KVUHyKnaUJJrNeFmWIkTcNuJmR3GLMEmGYEf2S2bjgx26JTF+Q==
dependencies:
- detect-file "^1.0.0"
- is-glob "^3.1.0"
- micromatch "^3.0.4"
- resolve-dir "^1.0.1"
+ locate-path "^5.0.0"
flat-cache@^1.2.1:
version "1.3.4"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=
-flexbuffer@0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/flexbuffer/-/flexbuffer-0.0.6.tgz#039fdf23f8823e440c38f3277e6fef1174215b30"
- integrity sha1-A5/fI/iCPkQMOPMnfm/vEXQhWzA=
-
fluent-ffmpeg@^2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz#c952de2240f812ebda0aa8006d7776ee2acf7d74"
async ">=0.2.9"
which "^1.1.1"
-flush-write-stream@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
- integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==
- dependencies:
- inherits "^2.0.3"
- readable-stream "^2.3.6"
-
fn-name@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7"
dependencies:
map-cache "^0.2.2"
-frameguard@3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-3.0.0.tgz#7bcad469ee7b96e91d12ceb3959c78235a9272e9"
- integrity sha1-e8rUae57lukdEs6zlZx4I1qScuk=
+frameguard@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-3.1.0.tgz#bd1442cca1d67dc346a6751559b6d04502103a22"
+ integrity sha512-TxgSKM+7LTA6sidjOiSZK9wxY0ffMPY3Wta//MqwmX0nZuEHc8QrkV8Fh3ZhMJeiH+Uyh/tcaarImRy8u77O7g==
fresh@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
-from2@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/from2/-/from2-1.3.0.tgz#88413baaa5f9a597cfde9221d86986cd3c061dfd"
- integrity sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0=
- dependencies:
- inherits "~2.0.1"
- readable-stream "~1.1.10"
-
-from2@^2.1.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
- integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=
- dependencies:
- inherits "^2.0.1"
- readable-stream "^2.0.0"
-
front-matter@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-2.1.2.tgz#f75983b9f2f413be658c93dfd7bd8ce4078f5cdb"
jsonfile "^3.0.0"
universalify "^0.1.0"
-fs-extra@^7.0.0:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
- integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
+fs-extra@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.0.1.tgz#90294081f978b1f182f347a440a209154344285b"
+ integrity sha512-W+XLrggcDzlle47X/XnS7FXrXu9sDo+Ze9zpndeBxdgv88FHLm1HtmkhEwavruS6koanBjp098rUpHs65EmG7A==
dependencies:
graceful-fs "^4.1.2"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-minipass@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
- integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07"
+ integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==
dependencies:
minipass "^2.2.1"
-fs-vacuum@^1.2.10, fs-vacuum@~1.2.10:
- version "1.2.10"
- resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36"
- integrity sha1-t2Kb7AekAxolSP35n17PHMizHjY=
- dependencies:
- graceful-fs "^4.1.2"
- path-is-inside "^1.0.1"
- rimraf "^2.5.2"
-
-fs-write-stream-atomic@^1.0.8, fs-write-stream-atomic@~1.0.10:
- version "1.0.10"
- resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9"
- integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=
- dependencies:
- graceful-fs "^4.1.2"
- iferr "^0.1.5"
- imurmurhash "^0.1.4"
- readable-stream "1 || 2"
-
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
fsevents@^1.2.7:
- version "1.2.7"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4"
- integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==
+ version "1.2.9"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f"
+ integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==
dependencies:
- nan "^2.9.2"
- node-pre-gyp "^0.10.0"
-
-fstream@^1.0.0, fstream@^1.0.2:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
- integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=
- dependencies:
- graceful-fs "^4.1.2"
- inherits "~2.0.0"
- mkdirp ">=0.5 0"
- rimraf "2"
+ nan "^2.12.1"
+ node-pre-gyp "^0.12.0"
function-bind@^1.1.1:
version "1.1.1"
dependencies:
is-property "^1.0.0"
-genfun@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537"
- integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==
-
-gentle-fs@^2.0.0, gentle-fs@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/gentle-fs/-/gentle-fs-2.0.1.tgz#585cfd612bfc5cd52471fdb42537f016a5ce3687"
- integrity sha512-cEng5+3fuARewXktTEGbwsktcldA+YsnUEaXZwcK/3pjSE1X9ObnTs+/8rYf8s+RnIcQm2D5x3rwpN7Zom8Bew==
- dependencies:
- aproba "^1.1.2"
- fs-vacuum "^1.2.10"
- graceful-fs "^4.1.11"
- iferr "^0.1.5"
- mkdirp "^0.5.1"
- path-is-inside "^1.0.2"
- read-cmd-shim "^1.0.1"
- slide "^1.1.6"
-
get-browser-rtc@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-browser-rtc/-/get-browser-rtc-1.0.2.tgz#bbcd40c8451a7ed4ef5c373b8169a409dd1d11d9"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
+get-caller-file@^2.0.1:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+ integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
get-func-name@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203"
integrity sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==
-get-port@latest:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119"
- integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==
+get-port@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.0.0.tgz#aa22b6b86fd926dd7884de3e23332c9f70c031a6"
+ integrity sha512-imzMU0FjsZqNa6BqOjbbW6w5BivHIuQKopjpPqcnx0AVHJQKCxK1O+Ab3OrVXhrekqfVMjwA9ZYu062R+KcIsQ==
+ dependencies:
+ type-fest "^0.3.0"
get-stdin@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
+get-stdin@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6"
+ integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==
+
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
-get-stream@^4.0.0, get-stream@^4.1.0:
+get-stream@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@7.1.3, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.3, glob@~7.1.1:
+glob@7.1.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
once "^1.3.0"
path-is-absolute "^1.0.0"
+glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.3, glob@~7.1.1:
+ version "7.1.4"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
+ integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
global-dirs@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
dependencies:
ini "^1.3.4"
-global-modules@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
- integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
- dependencies:
- global-prefix "^1.0.1"
- is-windows "^1.0.1"
- resolve-dir "^1.0.0"
-
-global-prefix@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
- integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=
- dependencies:
- expand-tilde "^2.0.2"
- homedir-polyfill "^1.0.1"
- ini "^1.3.4"
- is-windows "^1.0.1"
- which "^1.2.14"
-
globals@^9.2.0:
version "9.18.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
unzip-response "^2.0.1"
url-parse-lax "^1.0.0"
-graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
version "4.1.15"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
-has-unicode@^2.0.0, has-unicode@~2.0.1:
+has-unicode@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
platform "1.3.5"
helmet@^3.12.1:
- version "3.16.0"
- resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.16.0.tgz#7df41a4bfe4c83d90147c1e30d70893f92a9d97c"
- integrity sha512-rsTKRogc5OYGlvSHuq5QsmOsOzF6uDoMqpfh+Np8r23+QxDq+SUx90Rf8HyIKQVl7H6NswZEwfcykinbAeZ6UQ==
+ version "3.18.0"
+ resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.18.0.tgz#37666f7c861bd1ff3015e0cdb903a43501e3da3e"
+ integrity sha512-TsKlGE5UVkV0NiQ4PllV9EVfZklPjyzcMEMjWlyI/8S6epqgRT+4s4GHVgc25x0TixsKvp3L7c91HQQt5l0+QA==
dependencies:
depd "2.0.0"
dns-prefetch-control "0.1.0"
dont-sniff-mimetype "1.0.0"
- expect-ct "0.1.1"
- feature-policy "0.2.0"
- frameguard "3.0.0"
+ expect-ct "0.2.0"
+ feature-policy "0.3.0"
+ frameguard "3.1.0"
helmet-crossdomain "0.3.0"
helmet-csp "2.7.1"
hide-powered-by "1.0.0"
hpkp "2.0.0"
hsts "2.2.0"
ienoopen "1.1.0"
- nocache "2.0.0"
- referrer-policy "1.1.0"
+ nocache "2.1.0"
+ referrer-policy "1.2.0"
x-xss-protection "1.1.0"
hh-mm-ss@~1.2.0:
resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b"
integrity sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys=
-homedir-polyfill@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
- integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
- dependencies:
- parse-passwd "^1.0.0"
-
-hosted-git-info@^2.1.4, hosted-git-info@^2.6.0, hosted-git-info@^2.7.1:
+hosted-git-info@^2.1.4:
version "2.7.1"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==
dependencies:
depd "2.0.0"
-http-cache-semantics@^3.8.1:
- version "3.8.1"
- resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2"
- integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==
-
-http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
- version "1.6.3"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
- integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
+http-errors@1.7.2, http-errors@~1.7.2:
+ version "1.7.2"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
+ integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
dependencies:
depd "~1.1.2"
inherits "2.0.3"
- setprototypeof "1.1.0"
- statuses ">= 1.4.0 < 2"
+ setprototypeof "1.1.1"
+ statuses ">= 1.5.0 < 2"
+ toidentifier "1.0.0"
http-errors@~1.3.1:
version "1.3.1"
inherits "~2.0.1"
statuses "1"
-http-proxy-agent@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
- integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==
- dependencies:
- agent-base "4"
- debug "3.1.0"
-
http-signature@^1.2.0, http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
jsprim "^1.2.2"
sshpk "^1.7.0"
-https-proxy-agent@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
- integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==
- dependencies:
- agent-base "^4.1.0"
- debug "^3.1.0"
-
-humanize-ms@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
- integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=
- dependencies:
- ms "^2.0.0"
-
-husky@^1.0.0-rc.4:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/husky/-/husky-1.3.1.tgz#26823e399300388ca2afff11cfa8a86b0033fae0"
- integrity sha512-86U6sVVVf4b5NYSZ0yvv88dRgBSSXXmHaiq5pP4KDj5JVzdwKgBjEtUPOm8hcoytezFwbU+7gotXNhpHdystlg==
+husky@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/husky/-/husky-2.4.0.tgz#1bac7c44588f6e91f808b72efc82d24a57194f36"
+ integrity sha512-3k1wuZU20gFkphNWMjh2ISCFaqfbaLY7R9FST2Mj9HeRhUK9ydj9qQR8qfXlog3EctVGsyeilcZkIT7uBZDDVA==
dependencies:
- cosmiconfig "^5.0.7"
+ cosmiconfig "^5.2.0"
execa "^1.0.0"
find-up "^3.0.0"
- get-stdin "^6.0.0"
+ get-stdin "^7.0.0"
is-ci "^2.0.0"
- pkg-dir "^3.0.0"
+ pkg-dir "^4.1.0"
please-upgrade-node "^3.1.1"
- read-pkg "^4.0.1"
+ read-pkg "^5.1.1"
run-node "^1.0.0"
- slash "^2.0.0"
+ slash "^3.0.0"
i@0.3.x:
version "0.3.6"
resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d"
integrity sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=
-iconv-lite@0.4.23:
- version "0.4.23"
- resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
- integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==
- dependencies:
- safer-buffer ">= 2.1.2 < 3"
-
-iconv-lite@^0.4.4, iconv-lite@~0.4.13:
+iconv-lite@0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.1.0.tgz#411e5d530c982287dbdc3bb31e7a9c9e32630974"
integrity sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ==
-iferr@^0.1.5:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
- integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE=
-
-iferr@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/iferr/-/iferr-1.0.2.tgz#e9fde49a9da06dc4a4194c6c9ed6d08305037a6d"
- integrity sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg==
-
ignore-by-default@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416"
integrity sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=
-inflight@^1.0.4, inflight@~1.0.6:
+inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
+inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=
-ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
+ini@^1.3.4, ini@~1.3.0:
version "1.3.5"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
-init-package-json@^1.10.3:
- version "1.10.3"
- resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.10.3.tgz#45ffe2f610a8ca134f2bd1db5637b235070f6cbe"
- integrity sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==
- dependencies:
- glob "^7.1.1"
- npm-package-arg "^4.0.0 || ^5.0.0 || ^6.0.0"
- promzard "^0.3.0"
- read "~1.0.1"
- read-package-json "1 || 2"
- semver "2.x || 3.x || 4 || 5"
- validate-npm-package-license "^3.0.1"
- validate-npm-package-name "^3.0.0"
-
inquirer@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e"
strip-ansi "^3.0.0"
through "^2.3.6"
-invert-kv@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
- integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
-
invert-kv@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
ioredis@^4.5.1:
- version "4.9.0"
- resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.9.0.tgz#0c52de498363309ebd48b5f6695d9d432b0f6669"
- integrity sha512-YzfCLsN++Ct43QqGK9CWxaEK6OUvJ7rnENieAPNw3DVp/oF2uBrP2NJChbhO74Ng3LWA+i5zdIEUsZYr6dKDIQ==
+ version "4.9.5"
+ resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.9.5.tgz#0bbba0a9faae93485d3231e1b819d2d4e23271d9"
+ integrity sha512-L9MVfvX4F3LScTMEgriCGixzqinJsYy7Mt0NPX8RyuOTmx5JW0744pM4Ze2KVQcP3J0zvKYZ1LywAB6KIq7PYg==
dependencies:
cluster-key-slot "^1.0.6"
debug "^3.1.0"
denque "^1.1.0"
- flexbuffer "0.0.6"
lodash.defaults "^4.2.0"
lodash.flatten "^4.4.0"
redis-commands "1.4.0"
redis-parser "^3.0.0"
standard-as-callback "^2.0.1"
-ip-anonymize@^0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/ip-anonymize/-/ip-anonymize-0.0.6.tgz#d2c513e448e874e8cc380d03404691b94b018e68"
- integrity sha1-0sUT5EjodOjMOA0DQEaRuUsBjmg=
+ip-anonymize@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/ip-anonymize/-/ip-anonymize-0.1.0.tgz#5ead504d01871c5c28189a25382f852036b57f7e"
+ integrity sha512-cZJu+N5JKKFGMK0eEQWNaQMn2EhCysciVM6eotCJwfqotj16BTfVchKsJCH6mQAT9N0GC7oWRcsZ6Lb8dDiwTA==
ip-regex@^2.1.0:
version "2.1.0"
integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=
ip-set@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/ip-set/-/ip-set-1.0.1.tgz#633b66d0bd6c8d0de968d053263c9120d3b6727e"
- integrity sha1-Yztm0L1sjQ3paNBTJjyRINO2cn4=
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/ip-set/-/ip-set-1.0.2.tgz#be4f119f82c124836455993dfcd554639c7007de"
+ integrity sha512-Mb6kv78bTi4RNAIIWL8Bbre7hXOR2pNUi3j8FaQkLaitf/ZWxkq3/iIwXNYk2ACO3IMfdVdQrOkUtwZblO7uBA==
dependencies:
ip "^1.1.3"
-ip@^1.0.1, ip@^1.1.3, ip@^1.1.5:
+ip@^1.0.1, ip@^1.1.3:
version "1.1.5"
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.0.5.tgz#5fa78cf301b825c78abc3042d812723049ea23c7"
integrity sha1-X6eM8wG4JceKvDBC2BJyMEnqI8c=
-ipaddr.js@1.8.0:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e"
- integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4=
-
ipaddr.js@1.9.0, "ipaddr.js@>= 0.1.5", ipaddr.js@^1.0.1:
version "1.9.0"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==
is-my-json-valid@^2.10.0:
- version "2.19.0"
- resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175"
- integrity sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q==
+ version "2.20.0"
+ resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.20.0.tgz#1345a6fca3e8daefc10d0fa77067f54cedafd59a"
+ integrity sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA==
dependencies:
generate-function "^2.0.0"
generate-object-property "^1.1.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
-is-windows@^1.0.1, is-windows@^1.0.2:
+is-windows@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
iso-639-3@^1.0.1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/iso-639-3/-/iso-639-3-1.1.0.tgz#83722daf55490a707c318ae18a33ba3bab06c843"
- integrity sha512-l3BAnxNpyRIZA4mEzI2md/YVrxQ3hI8hiQe7TFyQknjyOh8vCzobZuAXTFHELco0FBkYRx4FkAlIqkKrHhnzgw==
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/iso-639-3/-/iso-639-3-1.2.0.tgz#eee1f5e6ca2bbb33e3ecc910857c1c12e8b295be"
+ integrity sha512-jNvD2P4JHNckQH7pc0R0SQ4oPCpyEtgs0nTtjB+DZCUDdygz0cOAxlcnq5KgNjjsqMHbR4Sbgwz2+DflzAZvlQ==
isobject@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
-js-tokens@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
- integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
-
-js-yaml@3.12.0:
- version "3.12.0"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
- integrity sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==
- dependencies:
- argparse "^1.0.7"
- esprima "^4.0.0"
+js-tokens@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+ integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-js-yaml@^3.12.1, js-yaml@^3.13.0, js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.5.4:
- version "3.13.0"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.0.tgz#38ee7178ac0eea2c97ff6d96fff4b18c7d8cf98e"
- integrity sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==
+js-yaml@3.13.1, js-yaml@^3.12.1, js-yaml@^3.13.1, js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.5.4:
+ version "3.13.1"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
+ integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
-json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
+json-parse-better-errors@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
semver "^5.5.0"
xmldom "0.1.19"
-jsonparse@^1.2.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
- integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=
-
jsonpointer.js@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/jsonpointer.js/-/jsonpointer.js-0.4.0.tgz#002cb123f767aafdeb0196132ce5c4f9941ccaba"
dependencies:
package-json "^4.0.0"
-lazy-property@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/lazy-property/-/lazy-property-1.0.0.tgz#84ddc4b370679ba8bd4cdcfa4c06b43d57111147"
- integrity sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc=
-
-lcid@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
- integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
- dependencies:
- invert-kv "^1.0.0"
-
lcid@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
prelude-ls "~1.1.2"
type-check "~0.3.2"
-libcipm@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/libcipm/-/libcipm-3.0.3.tgz#2e764effe0b90d458790dab3165794c804075ed3"
- integrity sha512-71V5CpTI+zFydTc5IjJ/tx8JHbXEJvmYF2zaSVW1V3X1rRnRjXqh44iuiyry1xgi3ProUQ1vX1uwFiWs00+2og==
- dependencies:
- bin-links "^1.1.2"
- bluebird "^3.5.1"
- figgy-pudding "^3.5.1"
- find-npm-prefix "^1.0.2"
- graceful-fs "^4.1.11"
- ini "^1.3.5"
- lock-verify "^2.0.2"
- mkdirp "^0.5.1"
- npm-lifecycle "^2.0.3"
- npm-logical-tree "^1.2.1"
- npm-package-arg "^6.1.0"
- pacote "^9.1.0"
- read-package-json "^2.0.13"
- rimraf "^2.6.2"
- worker-farm "^1.6.0"
-
-libnpm@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/libnpm/-/libnpm-2.0.1.tgz#a48fcdee3c25e13c77eb7c60a0efe561d7fb0d8f"
- integrity sha512-qTKoxyJvpBxHZQB6k0AhSLajyXq9ZE/lUsZzuHAplr2Bpv9G+k4YuYlExYdUCeVRRGqcJt8hvkPh4tBwKoV98w==
- dependencies:
- bin-links "^1.1.2"
- bluebird "^3.5.3"
- find-npm-prefix "^1.0.2"
- libnpmaccess "^3.0.1"
- libnpmconfig "^1.2.1"
- libnpmhook "^5.0.2"
- libnpmorg "^1.0.0"
- libnpmpublish "^1.1.0"
- libnpmsearch "^2.0.0"
- libnpmteam "^1.0.1"
- lock-verify "^2.0.2"
- npm-lifecycle "^2.1.0"
- npm-logical-tree "^1.2.1"
- npm-package-arg "^6.1.0"
- npm-profile "^4.0.1"
- npm-registry-fetch "^3.8.0"
- npmlog "^4.1.2"
- pacote "^9.2.3"
- read-package-json "^2.0.13"
- stringify-package "^1.0.0"
-
-libnpmaccess@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-3.0.1.tgz#5b3a9de621f293d425191aa2e779102f84167fa8"
- integrity sha512-RlZ7PNarCBt+XbnP7R6PoVgOq9t+kou5rvhaInoNibhPO7eMlRfS0B8yjatgn2yaHIwWNyoJDolC/6Lc5L/IQA==
- dependencies:
- aproba "^2.0.0"
- get-stream "^4.0.0"
- npm-package-arg "^6.1.0"
- npm-registry-fetch "^3.8.0"
-
-libnpmconfig@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/libnpmconfig/-/libnpmconfig-1.2.1.tgz#c0c2f793a74e67d4825e5039e7a02a0044dfcbc0"
- integrity sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA==
- dependencies:
- figgy-pudding "^3.5.1"
- find-up "^3.0.0"
- ini "^1.3.5"
-
-libnpmhook@^5.0.2:
- version "5.0.2"
- resolved "https://registry.yarnpkg.com/libnpmhook/-/libnpmhook-5.0.2.tgz#d12817b0fb893f36f1d5be20017f2aea25825d94"
- integrity sha512-vLenmdFWhRfnnZiNFPNMog6CK7Ujofy2TWiM2CrpZUjBRIhHkJeDaAbJdYCT6W4lcHtyrJR8yXW8KFyq6UAp1g==
- dependencies:
- aproba "^2.0.0"
- figgy-pudding "^3.4.1"
- get-stream "^4.0.0"
- npm-registry-fetch "^3.8.0"
-
-libnpmorg@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/libnpmorg/-/libnpmorg-1.0.0.tgz#979b868c48ba28c5820e3bb9d9e73c883c16a232"
- integrity sha512-o+4eVJBoDGMgRwh2lJY0a8pRV2c/tQM/SxlqXezjcAg26Qe9jigYVs+Xk0vvlYDWCDhP0g74J8UwWeAgsB7gGw==
- dependencies:
- aproba "^2.0.0"
- figgy-pudding "^3.4.1"
- get-stream "^4.0.0"
- npm-registry-fetch "^3.8.0"
-
-libnpmpublish@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-1.1.1.tgz#ff0c6bb0b4ad2bda2ad1f5fba6760a4af37125f0"
- integrity sha512-nefbvJd/wY38zdt+b9SHL6171vqBrMtZ56Gsgfd0duEKb/pB8rDT4/ObUQLrHz1tOfht1flt2zM+UGaemzAG5g==
- dependencies:
- aproba "^2.0.0"
- figgy-pudding "^3.5.1"
- get-stream "^4.0.0"
- lodash.clonedeep "^4.5.0"
- normalize-package-data "^2.4.0"
- npm-package-arg "^6.1.0"
- npm-registry-fetch "^3.8.0"
- semver "^5.5.1"
- ssri "^6.0.1"
-
-libnpmsearch@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/libnpmsearch/-/libnpmsearch-2.0.0.tgz#de05af47ada81554a5f64276a69599070d4a5685"
- integrity sha512-vd+JWbTGzOSfiOc+72MU6y7WqmBXn49egCCrIXp27iE/88bX8EpG64ST1blWQI1bSMUr9l1AKPMVsqa2tS5KWA==
- dependencies:
- figgy-pudding "^3.5.1"
- get-stream "^4.0.0"
- npm-registry-fetch "^3.8.0"
-
-libnpmteam@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/libnpmteam/-/libnpmteam-1.0.1.tgz#ff704b1b6c06ea674b3b1101ac3e305f5114f213"
- integrity sha512-gDdrflKFCX7TNwOMX1snWojCoDE5LoRWcfOC0C/fqF7mBq8Uz9zWAX4B2RllYETNO7pBupBaSyBDkTAC15cAMg==
- dependencies:
- aproba "^2.0.0"
- figgy-pudding "^3.4.1"
- get-stream "^4.0.0"
- npm-registry-fetch "^3.8.0"
-
-libnpx@^10.2.0:
- version "10.2.0"
- resolved "https://registry.yarnpkg.com/libnpx/-/libnpx-10.2.0.tgz#1bf4a1c9f36081f64935eb014041da10855e3102"
- integrity sha512-X28coei8/XRCt15cYStbLBph+KGhFra4VQhRBPuH/HHMkC5dxM8v24RVgUsvODKCrUZ0eTgiTqJp6zbl0sskQQ==
- dependencies:
- dotenv "^5.0.1"
- npm-package-arg "^6.0.0"
- rimraf "^2.6.2"
- safe-buffer "^5.1.0"
- update-notifier "^2.3.0"
- which "^1.3.0"
- y18n "^4.0.0"
- yargs "^11.0.0"
-
libxmljs@0.19.5:
version "0.19.5"
resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.19.5.tgz#b2f34cc12fd6a3e43670c604c42a902f339ea54d"
node-pre-gyp "~0.11.0"
lint-staged@^8.0.4:
- version "8.1.5"
- resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-8.1.5.tgz#372476fe1a58b8834eb562ed4c99126bd60bdd79"
- integrity sha512-e5ZavfnSLcBJE1BTzRTqw6ly8OkqVyO3GL2M6teSmTBYQ/2BuueD5GIt2RPsP31u/vjKdexUyDCxSyK75q4BDA==
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-8.2.0.tgz#3d4149a229580815c955047a7acd8f09054be5a9"
+ integrity sha512-DxguyxGOIfb67wZ6EOrqzjAbw6ZH9XK3YS74HO+erJf6+SAQeJJPN//GBOG5xhdt2THeuXjVPaHcCYOWGZwRbA==
dependencies:
chalk "^2.3.1"
commander "^2.14.1"
- cosmiconfig "^5.0.2"
+ cosmiconfig "^5.2.0"
debug "^3.1.0"
dedent "^0.7.0"
del "^3.0.0"
execa "^1.0.0"
- find-parent-dir "^0.3.0"
g-status "^2.0.2"
is-glob "^4.0.0"
is-windows "^1.0.2"
staged-git-files "1.1.2"
string-argv "^0.0.2"
stringify-object "^3.2.2"
- yup "^0.26.10"
+ yup "^0.27.0"
listr-silent-renderer@^1.1.1:
version "1.1.1"
simple-get "^3.0.0"
split "^1.0.0"
-locate-path@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
- integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
- dependencies:
- p-locate "^2.0.0"
- path-exists "^3.0.0"
-
locate-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
p-locate "^3.0.0"
path-exists "^3.0.0"
-lock-verify@^2.0.2, lock-verify@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/lock-verify/-/lock-verify-2.1.0.tgz#fff4c918b8db9497af0c5fa7f6d71555de3ceb47"
- integrity sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg==
- dependencies:
- npm-package-arg "^6.1.0"
- semver "^5.4.1"
-
-lockfile@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609"
- integrity sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==
- dependencies:
- signal-exit "^3.0.2"
-
-lodash._baseuniq@~4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
- integrity sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=
+locate-path@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
+ integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
dependencies:
- lodash._createset "~4.0.0"
- lodash._root "~3.0.0"
-
-lodash._createset@~4.0.0:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
- integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
-
-lodash._root@~3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
- integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=
+ p-locate "^4.1.0"
lodash.capitalize@^4.1.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9"
integrity sha1-+CbJtOKoUR2E46yinbBeGk87cqk=
-lodash.clonedeep@^4.5.0, lodash.clonedeep@~4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
- integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
-
lodash.defaults@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36"
integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY=
-lodash.union@~4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
- integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
-
-lodash.uniq@~4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
- integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
-
-lodash.without@~4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac"
- integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=
-
lodash@4.17.4:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
-lru-cache@4.1.x, lru-cache@^4.0.1, lru-cache@^4.1.2, lru-cache@^4.1.3, lru-cache@^4.1.5:
+lru-cache@4.1.x, lru-cache@^4.0.1:
version "4.1.5"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
pseudomap "^1.0.2"
yallist "^2.1.2"
-lru-cache@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
- integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
- dependencies:
- yallist "^3.0.2"
-
lru-queue@0.1:
version "0.1.0"
resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8"
integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==
-make-fetch-happen@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz#141497cb878f243ba93136c83d8aba12c216c083"
- integrity sha512-7R5ivfy9ilRJ1EMKIOziwrns9fGeAD4bAha8EB7BIiBBLHm2KeTUGCrICFt2rbHfzheTLynv50GnNTK1zDTrcQ==
- dependencies:
- agentkeepalive "^3.4.1"
- cacache "^11.0.1"
- http-cache-semantics "^3.8.1"
- http-proxy-agent "^2.1.0"
- https-proxy-agent "^2.2.1"
- lru-cache "^4.1.2"
- mississippi "^3.0.0"
- node-fetch-npm "^2.0.2"
- promise-retry "^1.1.1"
- socks-proxy-agent "^4.0.0"
- ssri "^6.0.0"
-
map-age-cleaner@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
dependencies:
object-visit "^1.0.0"
-marked-man@^0.4.2:
- version "0.4.2"
- resolved "https://registry.yarnpkg.com/marked-man/-/marked-man-0.4.2.tgz#4507ee0bafa04f46f9b48082f62b3593c8d667bb"
- integrity sha512-4AMgee2zyjzgybboMBjAfDQ1ZUnBFDmxTKld7xuEc9N5tY3T7CqQYqYfKAkUc73tNLeOdwKcR3N5p1toXLiHAA==
+marked-man@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/marked-man/-/marked-man-0.6.0.tgz#ac049f840cf633a0f679af58f321c7de3dd583d8"
+ integrity sha512-lqzGe2uPo0KPO5J5yyfZ6PbEpZS6VIMHIzltXNzdwTNBysD0pNLtTaGrtT5R4aFT8UaVR3Fuz9rN3SEFYnea5Q==
matcher@^1.0.0:
version "1.1.1"
crypt "~0.0.1"
is-buffer "~1.1.1"
-meant@~1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.1.tgz#66044fea2f23230ec806fb515efea29c44d2115d"
- integrity sha512-UakVLFjKkbbUwNWJ2frVLnnAtbb7D7DsloxRd3s/gDpI8rdv8W5Hp3NaDb+POBI1fQdeussER6NB8vpcRURvlg==
-
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
readable-stream "^3.0.0"
to-arraybuffer "^1.0.1"
-mem@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76"
- integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=
- dependencies:
- mimic-fn "^1.0.0"
-
mem@^4.0.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
-micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8:
+micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
snapdragon "^0.8.1"
to-regex "^3.0.2"
-mime-db@~1.38.0:
- version "1.38.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad"
- integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==
+mime-db@1.40.0:
+ version "1.40.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
+ integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
-mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.18, mime-types@~2.1.19, mime-types@~2.1.6:
- version "2.1.22"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd"
- integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==
+mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.6:
+ version "2.1.24"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
+ integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
dependencies:
- mime-db "~1.38.0"
+ mime-db "1.40.0"
mime@1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
integrity sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=
-mime@1.4.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
- integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
-
-mime@^1.3.4, mime@^1.4.1:
+mime@1.6.0, mime@^1.3.4, mime@^1.4.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
mime@^2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.0.tgz#e051fd881358585f3279df333fe694da0bcffdd6"
- integrity sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.3.tgz#229687331e86f68924e6cb59e1cdd937f18275fe"
+ integrity sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==
mimelib@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
-minipass@^2.2.1, minipass@^2.3.4, minipass@^2.3.5:
+minipass@^2.2.1, minipass@^2.3.5:
version "2.3.5"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848"
integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==
safe-buffer "^5.1.2"
yallist "^3.0.0"
-minizlib@^1.1.1:
+minizlib@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614"
integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==
dependencies:
minipass "^2.2.1"
-mississippi@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022"
- integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==
- dependencies:
- concat-stream "^1.5.0"
- duplexify "^3.4.2"
- end-of-stream "^1.1.0"
- flush-write-stream "^1.0.0"
- from2 "^2.1.0"
- parallel-transform "^1.1.0"
- pump "^3.0.0"
- pumpify "^1.3.3"
- stream-each "^1.1.0"
- through2 "^2.0.0"
-
mixin-deep@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
for-in "^1.0.2"
is-extendable "^1.0.1"
-mkdirp@0.5.1, mkdirp@0.x.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
+mkdirp@0.5.1, mkdirp@0.x.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
dependencies:
minimist "0.0.8"
+mocha-parallel-tests@^2.1.0:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/mocha-parallel-tests/-/mocha-parallel-tests-2.1.2.tgz#2f5c24022257e5fc6c63a6bd22d49c1487496b26"
+ integrity sha512-FatFg3MHLio9ir1oP6J0HNEo6R5344JC1y+We90iALdiT9F9xNPN0KbGXxRNlGlSl0GodfSESKbRzBvT9ctgIw==
+ dependencies:
+ circular-json "^0.5.9"
+ debug "^4.1.1"
+ uuid "^3.3.2"
+ yargs "^13.2.2"
+
mocha@^6.0.0:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.0.2.tgz#cdc1a6fdf66472c079b5605bac59d29807702d2c"
- integrity sha512-RtTJsmmToGyeTznSOMoM6TPEk1A84FQaHIciKrRqARZx+B5ccJ5tXlmJzEKGBxZdqk9UjpRsesZTUkZmR5YnuQ==
+ version "6.1.4"
+ resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.1.4.tgz#e35fada242d5434a7e163d555c705f6875951640"
+ integrity sha512-PN8CIy4RXsIoxoFJzS4QNnCH4psUCPWc4/rPrst/ecSJJbLBkubMiyGCP2Kj/9YnWbotFqAoeXyXMucj7gwCFg==
dependencies:
ansi-colors "3.2.3"
browser-stdout "1.3.1"
debug "3.2.6"
diff "3.5.0"
escape-string-regexp "1.0.5"
- findup-sync "2.0.0"
+ find-up "3.0.0"
glob "7.1.3"
growl "1.10.5"
he "1.2.0"
- js-yaml "3.12.0"
+ js-yaml "3.13.1"
log-symbols "2.2.0"
minimatch "3.0.4"
mkdirp "0.5.1"
ms "2.1.1"
- node-environment-flags "1.0.4"
+ node-environment-flags "1.0.5"
object.assign "4.1.0"
strip-json-comments "2.0.1"
supports-color "6.0.0"
which "1.3.1"
wide-align "1.1.3"
- yargs "12.0.5"
- yargs-parser "11.1.1"
+ yargs "13.2.2"
+ yargs-parser "13.0.0"
yargs-unparser "1.5.0"
moment-timezone@^0.5.21, moment-timezone@^0.5.23:
- version "0.5.23"
- resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.23.tgz#7cbb00db2c14c71b19303cb47b0fb0a6d8651463"
- integrity sha512-WHFH85DkCfiNMDX5D3X7hpNH3/PUhjTGcD0U1SgfBGZxJ3qUmJh5FdvaFjcClxOvB3rzdfj4oRffbI38jEnC1w==
+ version "0.5.25"
+ resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.25.tgz#a11bfa2f74e088327f2cd4c08b3e7bdf55957810"
+ integrity sha512-DgEaTyN/z0HFaVcVbSyVCUU6HeFdnNC3vE4c9cgu2dgMTvjBUBdBzWfasTBmAW45u5OIMeCJtU8yNjM22DHucw==
dependencies:
moment ">= 2.9.0"
on-finished "~2.3.0"
on-headers "~1.0.1"
-move-concurrently@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
- integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=
- dependencies:
- aproba "^1.1.1"
- copy-concurrently "^1.0.0"
- fs-write-stream-atomic "^1.0.8"
- mkdirp "^0.5.1"
- rimraf "^2.5.4"
- run-queue "^1.0.3"
-
mp4-box-encoding@^1.1.0, mp4-box-encoding@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/mp4-box-encoding/-/mp4-box-encoding-1.3.0.tgz#2a6f750947ff68c3a498fd76cd6424c53d995d48"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
-ms@2.1.1, ms@^2.0.0, ms@^2.1.1:
+ms@2.1.1, ms@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
-nan@2.13.1:
- version "2.13.1"
- resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.1.tgz#a15bee3790bde247e8f38f1d446edcdaeb05f2dd"
- integrity sha512-I6YB/YEuDeUZMmhscXKxGgZlFnhsn5y0hgOZBadkzfTRrZBtJDZeg6eQf7PYMIEclwmorTKK8GztsyOUSVBREA==
-
-nan@^2.10.0, nan@^2.13.1, nan@^2.9.2:
+nan@2.13.2:
version "2.13.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7"
integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==
+nan@^2.10.0, nan@^2.12.1, nan@^2.13.2:
+ version "2.14.0"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
+ integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
+
nan@~2.10.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
integrity sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY=
needle@^2.2.1:
- version "2.2.4"
- resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e"
- integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
+ integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==
dependencies:
- debug "^2.1.2"
+ debug "^3.2.6"
iconv-lite "^0.4.4"
sax "^1.2.4"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=
+negotiator@0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
+ integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
+
netmask@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
-nocache@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.0.0.tgz#202b48021a0c4cbde2df80de15a17443c8b43980"
- integrity sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA=
+nocache@2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f"
+ integrity sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==
node-abi@^2.7.0:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.7.1.tgz#a8997ae91176a5fbaa455b194976e32683cda643"
- integrity sha512-OV8Bq1OrPh6z+Y4dqwo05HqrRL9YNF7QVMRfq1/pguwKLG+q9UB/Lk0x5qXjO23JjJg+/jqCHSTaG1P3tfKfuw==
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.8.0.tgz#bd2e88dbe6a6871e6dd08553e0605779325737ec"
+ integrity sha512-1/aa2clS0pue0HjckL62CsbhWWU35HARvBDXcJtYKbYR7LnIutmpxmXbuDMV9kEviD2lP/wACOgWmmwljghHyQ==
dependencies:
semver "^5.4.1"
-node-addon-api@^1.6.0:
- version "1.6.2"
- resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.6.2.tgz#d8aad9781a5cfc4132cc2fecdbdd982534265217"
- integrity sha512-479Bjw9nTE5DdBSZZWprFryHGjUaQC31y1wHo19We/k0BZlrmhqQitWoUL0cD8+scljCbIUL+E58oRDEakdGGA==
-
-node-environment-flags@1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.4.tgz#0b784a6551426bfc16d3b2208424dcbc2b2ff038"
- integrity sha512-M9rwCnWVLW7PX+NUWe3ejEdiLYinRpsEre9hMkU/6NS4h+EEulYaDH1gCEZ2gyXsmw+RXYDaV2JkkTNcsPDJ0Q==
+node-environment-flags@1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a"
+ integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==
dependencies:
object.getownpropertydescriptors "^2.0.3"
-
-node-fetch-npm@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7"
- integrity sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==
- dependencies:
- encoding "^0.1.11"
- json-parse-better-errors "^1.0.0"
- safe-buffer "^5.1.1"
+ semver "^5.7.0"
node-forge@^0.7.1:
version "0.7.6"
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d"
integrity sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w==
-node-gyp@^3.8.0:
- version "3.8.0"
- resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
- integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==
- dependencies:
- fstream "^1.0.0"
- glob "^7.0.3"
- graceful-fs "^4.1.2"
- mkdirp "^0.5.0"
- nopt "2 || 3"
- npmlog "0 || 1 || 2 || 3 || 4"
- osenv "0"
- request "^2.87.0"
- rimraf "2"
- semver "~5.3.0"
- tar "^2.0.0"
- which "1"
-
-node-pre-gyp@0.12.0:
+node-pre-gyp@0.12.0, node-pre-gyp@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149"
integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==
semver "^5.3.0"
tar "^4"
-node-pre-gyp@^0.10.0:
- version "0.10.3"
- resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc"
- integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==
- dependencies:
- detect-libc "^1.0.2"
- mkdirp "^0.5.1"
- needle "^2.2.1"
- nopt "^4.0.1"
- npm-packlist "^1.1.6"
- npmlog "^4.0.2"
- rc "^1.2.7"
- rimraf "^2.6.1"
- semver "^5.3.0"
- tar "^4"
-
node-pre-gyp@~0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054"
nodemailer-fetch "1.6.0"
nodemailer@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.0.0.tgz#d9761128771739dc87c1fdd747f569b7f135cb02"
- integrity sha512-PMQJyLhoNAMoBU1hEh5aaUkpa/tcDNwzS7s7zow/myKfoEoZewMxUuWZqQ5yjYsAnvE484KSkYH5s6iPvcjhCg==
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.2.1.tgz#20d773925eb8f7a06166a0b62c751dc8290429f3"
+ integrity sha512-TagB7iuIi9uyNgHExo8lUDq3VK5/B0BpbkcjIgNvxbtVrjNqq0DwAOTuzALPVkK76kMhTSzIgHqg8X1uklVs6g==
nodemon@^1.18.6:
- version "1.18.10"
- resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.10.tgz#3ba63f64eb4c283cf3e4f75f30817e9d4f393afe"
- integrity sha512-we51yBb1TfEvZamFchRgcfLbVYgg0xlGbyXmOtbBzDwxwgewYS/YbZ5tnlnsH51+AoSTTsT3A2E/FloUbtH8cQ==
+ version "1.19.1"
+ resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.19.1.tgz#576f0aad0f863aabf8c48517f6192ff987cd5071"
+ integrity sha512-/DXLzd/GhiaDXXbGId5BzxP1GlsqtMGM9zTmkWrgXtSqjKmGSbLicM/oAy4FR0YWm14jCHRwnR31AHS2dYFHrg==
dependencies:
- chokidar "^2.1.0"
+ chokidar "^2.1.5"
debug "^3.1.0"
ignore-by-default "^1.0.1"
minimatch "^3.0.4"
resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2"
integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=
-"nopt@2 || 3":
- version "3.0.6"
- resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
- integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k=
- dependencies:
- abbrev "1"
-
-nopt@^4.0.1, nopt@~4.0.1:
+nopt@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
dependencies:
abbrev "1"
-normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.4.0, normalize-package-data@^2.5.0:
+normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
-npm-audit-report@^1.3.2:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/npm-audit-report/-/npm-audit-report-1.3.2.tgz#303bc78cd9e4c226415076a4f7e528c89fc77018"
- integrity sha512-abeqS5ONyXNaZJPGAf6TOUMNdSe1Y6cpc9MLBRn+CuUoYbfdca6AxOyXVlfIv9OgKX+cacblbG5w7A6ccwoTPw==
- dependencies:
- cli-table3 "^0.5.0"
- console-control-strings "^1.1.0"
-
npm-bundled@^1.0.1:
version "1.0.6"
resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd"
integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
-npm-cache-filename@~1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11"
- integrity sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE=
-
-npm-install-checks@~3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-3.0.0.tgz#d4aecdfd51a53e3723b7b2f93b2ee28e307bc0d7"
- integrity sha1-1K7N/VGlPjcjt7L5Oy7ijjB7wNc=
- dependencies:
- semver "^2.3.0 || 3.x || 4 || 5"
-
-npm-lifecycle@^2.0.3, npm-lifecycle@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-2.1.0.tgz#1eda2eedb82db929e3a0c50341ab0aad140ed569"
- integrity sha512-QbBfLlGBKsktwBZLj6AviHC6Q9Y3R/AY4a2PYSIRhSKSS0/CxRyD/PfxEX6tPeOCXQgMSNdwGeECacstgptc+g==
- dependencies:
- byline "^5.0.0"
- graceful-fs "^4.1.11"
- node-gyp "^3.8.0"
- resolve-from "^4.0.0"
- slide "^1.1.6"
- uid-number "0.0.6"
- umask "^1.1.0"
- which "^1.3.1"
-
-npm-logical-tree@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz#44610141ca24664cad35d1e607176193fd8f5b88"
- integrity sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg==
-
-"npm-package-arg@^4.0.0 || ^5.0.0 || ^6.0.0", npm-package-arg@^6.0.0, npm-package-arg@^6.1.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1"
- integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA==
- dependencies:
- hosted-git-info "^2.6.0"
- osenv "^0.1.5"
- semver "^5.5.0"
- validate-npm-package-name "^3.0.0"
-
-npm-packlist@^1.1.12, npm-packlist@^1.1.6, npm-packlist@^1.4.1:
+npm-packlist@^1.1.6:
version "1.4.1"
resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc"
integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==
dependencies:
which "^1.2.10"
-npm-pick-manifest@^2.2.3:
- version "2.2.3"
- resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz#32111d2a9562638bb2c8f2bf27f7f3092c8fae40"
- integrity sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA==
- dependencies:
- figgy-pudding "^3.5.1"
- npm-package-arg "^6.0.0"
- semver "^5.4.1"
-
-npm-profile@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-4.0.1.tgz#d350f7a5e6b60691c7168fbb8392c3603583f5aa"
- integrity sha512-NQ1I/1Q7YRtHZXkcuU1/IyHeLy6pd+ScKg4+DQHdfsm769TGq6HPrkbuNJVJS4zwE+0mvvmeULzQdWn2L2EsVA==
- dependencies:
- aproba "^1.1.2 || 2"
- figgy-pudding "^3.4.1"
- npm-registry-fetch "^3.8.0"
-
-npm-registry-fetch@^3.8.0, npm-registry-fetch@^3.9.0:
- version "3.9.0"
- resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.9.0.tgz#44d841780e2833f06accb34488f8c7450d1a6856"
- integrity sha512-srwmt8YhNajAoSAaDWndmZgx89lJwIZ1GWxOuckH4Coek4uHv5S+o/l9FLQe/awA+JwTnj4FJHldxhlXdZEBmw==
- dependencies:
- JSONStream "^1.3.4"
- bluebird "^3.5.1"
- figgy-pudding "^3.4.1"
- lru-cache "^4.1.3"
- make-fetch-happen "^4.0.1"
- npm-package-arg "^6.1.0"
-
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
dependencies:
path-key "^2.0.0"
-npm-user-validate@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-1.0.0.tgz#8ceca0f5cea04d4e93519ef72d0557a75122e951"
- integrity sha1-jOyg9c6gTU6TUZ73LQVXp1Ei6VE=
-
npm-which@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa"
npm-path "^2.0.2"
which "^1.2.10"
-npm@*:
- version "6.9.0"
- resolved "https://registry.yarnpkg.com/npm/-/npm-6.9.0.tgz#5296720486814a64a7fb082de00c4b5cfd11211f"
- integrity sha512-91V+zB5hDxO+Jyp2sUKS7juHlIM95dGQxTeQtmZI1nAI/7kjWXFipPrtwwKjhyKmV4GsS2LzJhrxRjGWsU9z/w==
- dependencies:
- JSONStream "^1.3.5"
- abbrev "~1.1.1"
- ansicolors "~0.3.2"
- ansistyles "~0.1.3"
- aproba "^2.0.0"
- archy "~1.0.0"
- bin-links "^1.1.2"
- bluebird "^3.5.3"
- byte-size "^5.0.1"
- cacache "^11.3.2"
- call-limit "~1.1.0"
- chownr "^1.1.1"
- ci-info "^2.0.0"
- cli-columns "^3.1.2"
- cli-table3 "^0.5.1"
- cmd-shim "~2.0.2"
- columnify "~1.5.4"
- config-chain "^1.1.12"
- detect-indent "~5.0.0"
- detect-newline "^2.1.0"
- dezalgo "~1.0.3"
- editor "~1.0.0"
- figgy-pudding "^3.5.1"
- find-npm-prefix "^1.0.2"
- fs-vacuum "~1.2.10"
- fs-write-stream-atomic "~1.0.10"
- gentle-fs "^2.0.1"
- glob "^7.1.3"
- graceful-fs "^4.1.15"
- has-unicode "~2.0.1"
- hosted-git-info "^2.7.1"
- iferr "^1.0.2"
- inflight "~1.0.6"
- inherits "~2.0.3"
- ini "^1.3.5"
- init-package-json "^1.10.3"
- is-cidr "^3.0.0"
- json-parse-better-errors "^1.0.2"
- lazy-property "~1.0.0"
- libcipm "^3.0.3"
- libnpm "^2.0.1"
- libnpmhook "^5.0.2"
- libnpx "^10.2.0"
- lock-verify "^2.1.0"
- lockfile "^1.0.4"
- lodash._baseuniq "~4.6.0"
- lodash.clonedeep "~4.5.0"
- lodash.union "~4.6.0"
- lodash.uniq "~4.5.0"
- lodash.without "~4.4.0"
- lru-cache "^4.1.5"
- meant "~1.0.1"
- mississippi "^3.0.0"
- mkdirp "~0.5.1"
- move-concurrently "^1.0.1"
- node-gyp "^3.8.0"
- nopt "~4.0.1"
- normalize-package-data "^2.5.0"
- npm-audit-report "^1.3.2"
- npm-cache-filename "~1.0.2"
- npm-install-checks "~3.0.0"
- npm-lifecycle "^2.1.0"
- npm-package-arg "^6.1.0"
- npm-packlist "^1.4.1"
- npm-pick-manifest "^2.2.3"
- npm-registry-fetch "^3.9.0"
- npm-user-validate "~1.0.0"
- npmlog "~4.1.2"
- once "~1.4.0"
- opener "^1.5.1"
- osenv "^0.1.5"
- pacote "^9.5.0"
- path-is-inside "~1.0.2"
- promise-inflight "~1.0.1"
- qrcode-terminal "^0.12.0"
- query-string "^6.2.0"
- qw "~1.0.1"
- read "~1.0.7"
- read-cmd-shim "~1.0.1"
- read-installed "~4.0.3"
- read-package-json "^2.0.13"
- read-package-tree "^5.2.2"
- readable-stream "^3.1.1"
- request "^2.88.0"
- retry "^0.12.0"
- rimraf "^2.6.3"
- safe-buffer "^5.1.2"
- semver "^5.6.0"
- sha "~2.0.1"
- slide "~1.1.6"
- sorted-object "~2.0.1"
- sorted-union-stream "~2.1.3"
- ssri "^6.0.1"
- stringify-package "^1.0.0"
- tar "^4.4.8"
- text-table "~0.2.0"
- tiny-relative-date "^1.3.0"
- uid-number "0.0.6"
- umask "~1.1.0"
- unique-filename "^1.1.1"
- unpipe "~1.0.0"
- update-notifier "^2.5.0"
- uuid "^3.3.2"
- validate-npm-package-license "^3.0.4"
- validate-npm-package-name "~3.0.0"
- which "^1.3.1"
- worker-farm "^1.6.0"
- write-file-atomic "^2.4.2"
-
-"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.1, npmlog@^4.0.2, npmlog@^4.1.2, npmlog@~4.1.2:
+npmlog@^4.0.1, npmlog@^4.0.2, npmlog@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
kind-of "^3.0.3"
object-keys@^1.0.11, object-keys@^1.0.12:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.0.tgz#11bd22348dd2e096a045ab06f6c85bcc340fa032"
- integrity sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+ integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
object-visit@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
-once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0, once@~1.4.0:
+once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
jsonschema-draft4 "^1.0.0"
swagger-schema-official "2.0.0-bab6bed"
-opener@^1.5.1:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed"
- integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==
-
optionator@^0.8.1:
version "0.8.2"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
-os-locale@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2"
- integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==
- dependencies:
- execa "^0.7.0"
- lcid "^1.0.0"
- mem "^1.1.0"
-
-os-locale@^3.0.0:
+os-locale@^3.0.0, os-locale@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
-osenv@0, osenv@^0.1.4, osenv@^0.1.5:
+osenv@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
p-is-promise@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5"
- integrity sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==
-
-p-limit@^1.1.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
- integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
- dependencies:
- p-try "^1.0.0"
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
+ integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==
-p-limit@^2.0.0:
+p-limit@^2.0.0, p-limit@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2"
integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==
dependencies:
p-try "^2.0.0"
-p-locate@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
- integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
- dependencies:
- p-limit "^1.1.0"
-
p-locate@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
dependencies:
p-limit "^2.0.0"
+p-locate@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
+ integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
+ dependencies:
+ p-limit "^2.2.0"
+
p-map@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==
p-map@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.0.0.tgz#be18c5a5adeb8e156460651421aceca56c213a50"
- integrity sha512-GO107XdrSUmtHxVoi60qc9tUl/KkNKm+X2CF4P9amalpGxv5YqVPJNfSb0wcA+syCopkZvYYIzW8OVTQW59x/w==
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
+ integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==
-p-timeout@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038"
- integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==
+p-timeout@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.1.0.tgz#198c1f503bb973e9b9727177a276c80afd6851f3"
+ integrity sha512-C27DYI+tCroT8J8cTEyySGydl2B7FlxrGNF5/wmMbl1V+jeehUCzEE/BVgzRebdm2K3ZitKOKx8YbdFumDyYmw==
dependencies:
p-finally "^1.0.0"
-p-try@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
- integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
-
p-try@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74"
integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==
-pacote@^9.1.0, pacote@^9.2.3, pacote@^9.5.0:
- version "9.5.0"
- resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.5.0.tgz#85f3013a3f6dd51c108b0ccabd3de8102ddfaeda"
- integrity sha512-aUplXozRbzhaJO48FaaeClmN+2Mwt741MC6M3bevIGZwdCaP7frXzbUOfOWa91FPHoLITzG0hYaKY363lxO3bg==
- dependencies:
- bluebird "^3.5.3"
- cacache "^11.3.2"
- figgy-pudding "^3.5.1"
- get-stream "^4.1.0"
- glob "^7.1.3"
- lru-cache "^5.1.1"
- make-fetch-happen "^4.0.1"
- minimatch "^3.0.4"
- minipass "^2.3.5"
- mississippi "^3.0.0"
- mkdirp "^0.5.1"
- normalize-package-data "^2.4.0"
- npm-package-arg "^6.1.0"
- npm-packlist "^1.1.12"
- npm-pick-manifest "^2.2.3"
- npm-registry-fetch "^3.8.0"
- osenv "^0.1.5"
- promise-inflight "^1.0.1"
- promise-retry "^1.1.1"
- protoduck "^5.0.1"
- rimraf "^2.6.2"
- safe-buffer "^5.1.2"
- semver "^5.6.0"
- ssri "^6.0.1"
- tar "^4.4.8"
- unique-filename "^1.1.1"
- which "^1.3.1"
-
-parallel-transform@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"
- integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=
- dependencies:
- cyclist "~0.2.2"
- inherits "^2.0.3"
- readable-stream "^2.1.5"
-
parse-json@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-0.0.2.tgz#b4f09d413c7adbcd987f6e9233c7b4b210c938e4"
integrity sha1-tPCdQTx6282Yf26SM8e0shDJOOQ=
-parse-passwd@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
- integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
-
parse-torrent@^6.0.0, parse-torrent@^6.1.2:
version "6.1.2"
resolved "https://registry.yarnpkg.com/parse-torrent/-/parse-torrent-6.1.2.tgz#99da5bdd23435a1cb7e8e7a63847c4efb21b1956"
dependencies:
better-assert "~1.0.0"
-parseurl@~1.3.1, parseurl@~1.3.2:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
- integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=
+parseurl@~1.3.1, parseurl@~1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
pascalcase@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
-path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.2:
+path-is-inside@^1.0.1, path-is-inside@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
integrity sha512-hod2zYQxM8Gt482q+qONGTYcg/qVcV32VHVPtktbBJs0us3Dj7xibISw0BAAXVMCzt8A/jhfJvpZaxUlqtqs0g==
pg-types@~2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.0.0.tgz#038ddc302a0340efcdb46d0581cc7caa2303cbba"
- integrity sha512-THUD7gQll5tys+5eQ8Rvs7DjHiIC3bLqixk3gMN9Hu8UrCBAOjf35FoI39rTGGc3lM2HU/R+Knpxvd11mCwOMA==
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.0.1.tgz#b8585a37f2a9c7b386747e44574799549e5f4933"
+ integrity sha512-b7y6QM1VF5nOeX9ukMQ0h8a9z89mojrBHXfJeSug4mhL0YpxNBm83ot2TROyoAmX/ZOX3UbwVO4EbH7i1ZZNiw==
dependencies:
pg-int8 "1.0.1"
postgres-array "~2.0.0"
postgres-bytea "~1.0.0"
- postgres-date "~1.0.0"
+ postgres-date "~1.0.4"
postgres-interval "^1.1.0"
pg@^7.4.1:
- version "7.9.0"
- resolved "https://registry.yarnpkg.com/pg/-/pg-7.9.0.tgz#04f0024d810544463f47dbb5aada2486aa7dcc36"
- integrity sha512-GkzteBFpsIoIBCSuomqik3IGvhqAtTr32jclR24RmUg170Jrn6ypwR97YalFHrsE1iaW8T0aAH13dmij8QUQ0g==
+ version "7.11.0"
+ resolved "https://registry.yarnpkg.com/pg/-/pg-7.11.0.tgz#a8b9ae9cf19199b7952b72957573d0a9c5e67c0c"
+ integrity sha512-YO4V7vCmEMGoF390LJaFaohWNKaA2ayoQOEZmiHVcAUF+YsRThpf/TaKCgSvsSE7cDm37Q/Cy3Gz41xiX/XjTw==
dependencies:
buffer-writer "2.0.0"
packet-reader "1.0.0"
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
-pkg-dir@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3"
- integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==
+pkg-dir@^4.1.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
+ integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
dependencies:
- find-up "^3.0.0"
+ find-up "^4.0.0"
pkginfo@0.3.x:
version "0.3.1"
resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35"
integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=
-postgres-date@~1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.3.tgz#e2d89702efdb258ff9d9cee0fe91bd06975257a8"
- integrity sha1-4tiXAu/bJY/52c7g/pG9BpdSV6g=
+postgres-date@~1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.4.tgz#1c2728d62ef1bff49abdd35c1f86d4bdf118a728"
+ integrity sha512-bESRvKVuTrjoBluEcpv2346+6kgB7UlnqWZsnbnCccTNq/pqfj1j6oBaN5+b/NrDXepYUT/HKadqv3iS9lJuVA==
postgres-interval@^1.1.0:
version "1.2.0"
dependencies:
xtend "^4.0.0"
-prebuild-install@^5.2.5:
- version "5.2.5"
- resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.2.5.tgz#c7485911fe98950b7f7cd15bb9daee11b875cc44"
- integrity sha512-6uZgMVg7yDfqlP5CPurVhtq3hUKBFNufiar4J5hZrlHTo59DDBEtyxw01xCdFss9j0Zb9+qzFVf/s4niayba3w==
+prebuild-install@^5.3.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.0.tgz#58b4d8344e03590990931ee088dd5401b03004c8"
+ integrity sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg==
dependencies:
detect-libc "^1.0.3"
expand-template "^2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=
-promise-inflight@^1.0.1, promise-inflight@~1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
- integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
-
-promise-retry@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d"
- integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=
- dependencies:
- err-code "^1.0.0"
- retry "^0.10.0"
-
promise.prototype.finally@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz#66f161b1643636e50e7cf201dc1b84a857f3864e"
utile "0.3.x"
winston "2.1.x"
-promzard@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee"
- integrity sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=
- dependencies:
- read "1"
-
-property-expr@^1.5.0:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-1.5.1.tgz#22e8706894a0c8e28d58735804f6ba3a3673314f"
- integrity sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==
-
-proto-list@~1.2.1:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
- integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=
-
-protoduck@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.1.tgz#03c3659ca18007b69a50fd82a7ebcc516261151f"
- integrity sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==
- dependencies:
- genfun "^5.0.0"
+property-expr@^1.5.0:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-1.5.1.tgz#22e8706894a0c8e28d58735804f6ba3a3673314f"
+ integrity sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==
proxy-addr@~1.0.10:
version "1.0.10"
forwarded "~0.1.0"
ipaddr.js "1.0.5"
-proxy-addr@~2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93"
- integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==
+proxy-addr@~2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
+ integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==
dependencies:
forwarded "~0.1.2"
- ipaddr.js "1.8.0"
-
-prr@~1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
- integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
+ ipaddr.js "1.9.0"
pseudomap@^1.0.2:
version "1.0.2"
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
psl@^1.1.24:
- version "1.1.31"
- resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184"
- integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==
+ version "1.1.32"
+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.32.tgz#3f132717cf2f9c169724b2b6caf373cf694198db"
+ integrity sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==
pstree.remy@^1.1.6:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.6.tgz#73a55aad9e2d95814927131fbf4dc1b62d259f47"
- integrity sha512-NdF35+QsqD7EgNEI5mkI/X+UwaxVEbQaz9f4IooEmMUv6ZPmlTQYGjBPJGgrlzNdjSvIy4MWMg6Q6vCgBO2K+w==
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.7.tgz#c76963a28047ed61542dc361aa26ee55a7fa15f3"
+ integrity sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==
pump@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
-qrcode-terminal@^0.12.0:
- version "0.12.0"
- resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819"
- integrity sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==
-
qs@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607"
integrity sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc=
-qs@6.5.2, qs@~6.5.2:
- version "6.5.2"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
- integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
-
-qs@^6.5.1:
+qs@6.7.0, qs@^6.5.1:
version "6.7.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
-query-string@^6.2.0:
- version "6.4.2"
- resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.4.2.tgz#8be1dbd105306aebf86022144f575a29d516b713"
- integrity sha512-DfJqAen17LfLA3rQ+H5S4uXphrF+ANU1lT2ijds4V/Tj4gZxA3gx5/tg1bz7kYCmwna7LyJNCYqO7jNRzo3aLw==
- dependencies:
- decode-uri-component "^0.2.0"
- split-on-first "^1.0.0"
- strict-uri-encode "^2.0.0"
-
-qw@~1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/qw/-/qw-1.0.1.tgz#efbfdc740f9ad054304426acb183412cc8b996d4"
- integrity sha1-77/cdA+a0FQwRCassYNBLMi5ltQ=
+qs@~6.5.2:
+ version "6.5.2"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
+ integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
random-access-file@^2.0.1:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/random-access-file/-/random-access-file-2.1.0.tgz#7b3b6623d47e2f89282e77f0c9c9ae6da3cd9039"
- integrity sha512-W2hY3DboLETMclybTVzyqCNVKx1MjqUwZPzkpkkMD2t9mbGEtkV2SKWPqAJ/FTrAtnWB7aGwl0NDUS82da0KdQ==
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/random-access-file/-/random-access-file-2.1.2.tgz#eeb32e50b9831f32060516862381152ae4e05aa6"
+ integrity sha512-dZo7HEcEPbZ/6XLXC4GXypiWvFbXVkdeMrJTi0B94pBJwddt/AvJh8GaQhso6KGYROGYCI/VWdHbmRDtkwT9pQ==
dependencies:
mkdirp "^0.5.1"
random-access-storage "^1.1.1"
dependencies:
safe-buffer "^5.1.0"
-range-parser@^1.2.0, range-parser@~1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
- integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=
+range-parser@^1.2.0, range-parser@~1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
range-parser@~1.0.3:
version "1.0.3"
dependencies:
readable-stream "^3.0.2"
-raw-body@2.3.3:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3"
- integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==
+raw-body@2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
+ integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
dependencies:
- bytes "3.0.0"
- http-errors "1.6.3"
- iconv-lite "0.4.23"
+ bytes "3.1.0"
+ http-errors "1.7.2"
+ iconv-lite "0.4.24"
unpipe "1.0.0"
rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
node-forge "^0.7.1"
semver "^5.4.1"
-read-cmd-shim@^1.0.1, read-cmd-shim@~1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b"
- integrity sha1-LV0Vd4ajfAVdIgd8MsU/gynpHHs=
- dependencies:
- graceful-fs "^4.1.2"
-
-read-installed@~4.0.3:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067"
- integrity sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=
- dependencies:
- debuglog "^1.0.1"
- read-package-json "^2.0.0"
- readdir-scoped-modules "^1.0.0"
- semver "2 || 3 || 4 || 5"
- slide "~1.1.3"
- util-extend "^1.0.1"
- optionalDependencies:
- graceful-fs "^4.1.2"
-
-"read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@^2.0.13:
- version "2.0.13"
- resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.0.13.tgz#2e82ebd9f613baa6d2ebe3aa72cefe3f68e41f4a"
- integrity sha512-/1dZ7TRZvGrYqE0UAfN6qQb5GYBsNcqS1C0tNK601CFOJmtHI7NIGXwetEPU/OtoFHZL3hDxm4rolFFVE9Bnmg==
- dependencies:
- glob "^7.1.1"
- json-parse-better-errors "^1.0.1"
- normalize-package-data "^2.0.0"
- slash "^1.0.0"
- optionalDependencies:
- graceful-fs "^4.1.2"
-
-read-package-tree@^5.2.2:
- version "5.2.2"
- resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.2.2.tgz#4b6a0ef2d943c1ea36a578214c9a7f6b7424f7a8"
- integrity sha512-rW3XWUUkhdKmN2JKB4FL563YAgtINifso5KShykufR03nJ5loGFlkUMe1g/yxmqX073SoYYTsgXu7XdDinKZuA==
- dependencies:
- debuglog "^1.0.1"
- dezalgo "^1.0.0"
- once "^1.3.0"
- read-package-json "^2.0.0"
- readdir-scoped-modules "^1.0.0"
-
read-pkg@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237"
parse-json "^4.0.0"
pify "^3.0.0"
-read@1, read@1.0.x, read@~1.0.1, read@~1.0.7:
+read-pkg@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.1.1.tgz#5cf234dde7a405c90c88a519ab73c467e9cb83f5"
+ integrity sha512-dFcTLQi6BZ+aFUaICg7er+/usEoqFdQxiEBsEMNGoipenihtxxtdrQuBXvyANCEI8VuUIVYFgeHGx9sLLvim4w==
+ dependencies:
+ "@types/normalize-package-data" "^2.4.0"
+ normalize-package-data "^2.5.0"
+ parse-json "^4.0.0"
+ type-fest "^0.4.1"
+
+read@1.0.x:
version "1.0.7"
resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4"
integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=
dependencies:
mute-stream "~0.0.4"
-"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.3, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.2, readable-stream@^2.3.4, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
- version "2.3.6"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
- integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.3"
- isarray "~1.0.0"
- process-nextick-args "~2.0.0"
- safe-buffer "~5.1.1"
- string_decoder "~1.1.1"
- util-deprecate "~1.0.1"
-
-readable-stream@1.1.x, "readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.1.13-1, readable-stream@~1.1.10:
+readable-stream@1.1.x, "readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.1.13-1:
version "1.1.14"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
isarray "0.0.1"
string_decoder "~0.10.x"
+readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.3, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.2, readable-stream@^2.3.4, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
+ integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.1.1"
+ util-deprecate "~1.0.1"
+
readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.3.0.tgz#cb8011aad002eb717bf040291feba8569c986fb9"
- integrity sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc"
+ integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
dependencies:
readable-stream "^1.1.13-1"
-readdir-scoped-modules@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747"
- integrity sha1-n6+jfShr5dksuuve4DDcm19AZ0c=
- dependencies:
- debuglog "^1.0.1"
- dezalgo "^1.0.0"
- graceful-fs "^4.1.2"
- once "^1.3.0"
-
readdirp@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
resolved "https://registry.yarnpkg.com/record-cache/-/record-cache-1.1.0.tgz#f8a467a691a469584b26e88d36b18afdb3932037"
integrity sha512-u8rbtLEJV7HRacl/ZYwSBFD8NFyB3PfTTfGLP37IW3hftQCwu6z4Q2RLyxo1YJUNRTEzJfpLpGwVuEYdaIkG9Q==
-redis-commands@1.4.0, redis-commands@^1.2.0:
+redis-commands@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.4.0.tgz#52f9cf99153efcce56a8f86af986bd04e988602f"
integrity sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw==
+redis-commands@^1.2.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.5.0.tgz#80d2e20698fe688f227127ff9e5164a7dd17e785"
+ integrity sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg==
+
redis-errors@^1.0.0, redis-errors@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad"
redis-commands "^1.2.0"
redis-parser "^2.6.0"
-referrer-policy@1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.1.0.tgz#35774eb735bf50fb6c078e83334b472350207d79"
- integrity sha1-NXdOtzW/UPtsB46DM0tHI1AgfXk=
+referrer-policy@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.2.0.tgz#b99cfb8b57090dc454895ef897a4cc35ef67a98e"
+ integrity sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA==
reflect-metadata@^0.1.12:
version "0.1.13"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
-regenerator-runtime@^0.12.0:
- version "0.12.1"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
- integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
+regenerator-runtime@^0.13.2:
+ version "0.13.2"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
+ integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==
regex-not@^1.0.0, regex-not@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
-request@^2.81.0, request@^2.83.0, request@^2.87.0, request@^2.88.0, request@~2.88.0:
+request@^2.81.0, request@^2.83.0, request@~2.88.0:
version "2.88.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
+require-main-filename@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
+ integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
+
require-uncached@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
caller-path "^0.1.0"
resolve-from "^1.0.0"
-resolve-dir@^1.0.0, resolve-dir@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
- integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=
- dependencies:
- expand-tilde "^2.0.0"
- global-modules "^1.0.0"
-
resolve-from@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
integrity sha1-six699nWiBvItuZTM17rywoYh0g=
-resolve-from@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
- integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
-
resolve-pkg@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-1.0.0.tgz#e19a15e78aca2e124461dc92b2e3943ef93494d9"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
resolve@^1.10.0, resolve@^1.3.2:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba"
- integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==
+ version "1.11.1"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e"
+ integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==
dependencies:
path-parse "^1.0.6"
dependencies:
any-promise "^1.3.0"
-retry@^0.10.0:
- version "0.10.1"
- resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4"
- integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=
-
-retry@^0.12.0:
- version "0.12.0"
- resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
- integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
-
revalidator@0.1.x:
version "0.1.8"
resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b"
integrity sha1-/s5hv6DBtSoga9axgZgYS91SOjs=
-rimraf@2, rimraf@2.x.x, rimraf@^2.2.8, rimraf@^2.4.2, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@~2.6.2:
+rimraf@2.x.x, rimraf@^2.2.8, rimraf@^2.4.2, rimraf@^2.6.1, rimraf@~2.6.2:
version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
-run-queue@^1.0.0, run-queue@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"
- integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=
- dependencies:
- aproba "^1.1.1"
-
run-series@^1.0.2:
version "1.1.8"
resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.8.tgz#2c4558f49221e01cd6371ff4e0a1e203e460fc36"
integrity sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=
rxjs@^6.3.3:
- version "6.4.0"
- resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504"
- integrity sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==
+ version "6.5.2"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7"
+ integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==
dependencies:
tslib "^1.9.0"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
sass-lint@^1.12.1:
- version "1.12.1"
- resolved "https://registry.yarnpkg.com/sass-lint/-/sass-lint-1.12.1.tgz#630f69c216aa206b8232fb2aa907bdf3336b6d83"
- integrity sha1-Yw9pwhaqIGuCMvsqqQe98zNrbYM=
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/sass-lint/-/sass-lint-1.13.1.tgz#5fd2b2792e9215272335eb0f0dc607f61e8acc8f"
+ integrity sha512-DSyah8/MyjzW2BWYmQWekYEKir44BpLqrCFsgs9iaWiVTcwZfwXHF586hh3D1n+/9ihUNMfd8iHAyb9KkGgs7Q==
dependencies:
commander "^2.8.1"
eslint "^2.7.0"
dependencies:
semver "^5.0.3"
-"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
+"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0:
version "5.7.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7"
integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=
-semver@~5.3.0:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
- integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
+semver@^6.0.0, semver@^6.1.1:
+ version "6.1.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.1.1.tgz#53f53da9b30b2103cd4f15eab3a18ecbcb210c9b"
+ integrity sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==
send@0.13.1:
version "0.13.1"
range-parser "~1.0.3"
statuses "~1.2.1"
-send@0.16.2:
- version "0.16.2"
- resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
- integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==
+send@0.17.1:
+ version "0.17.1"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
+ integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
dependencies:
debug "2.6.9"
depd "~1.1.2"
escape-html "~1.0.3"
etag "~1.8.1"
fresh "0.5.2"
- http-errors "~1.6.2"
- mime "1.4.1"
- ms "2.0.0"
+ http-errors "~1.7.2"
+ mime "1.6.0"
+ ms "2.1.1"
on-finished "~2.3.0"
- range-parser "~1.2.0"
- statuses "~1.4.0"
+ range-parser "~1.2.1"
+ statuses "~1.5.0"
sequelize-pool@^1.0.2:
version "1.0.2"
dependencies:
glob "7.1.2"
-sequelize@5.7.4:
- version "5.7.4"
- resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-5.7.4.tgz#1631faadff65f3a345b9757fca60429c65ba8e57"
- integrity sha512-CaVYpAgZQEsGDuZ+Oq6uIZy4pxQxscotuh5UGIaFRa0VkTIgV0IiF7vAhSv+1Wn+NvhKCvgJJ85M34BP3AdGNg==
+sequelize@5.8.7:
+ version "5.8.7"
+ resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-5.8.7.tgz#3af2fd6051277d5fb5b32054c7f8aac4c4a04107"
+ integrity sha512-1rubZM8fAyCt5ipyS+3HJ3Jbmb8WesLdPJ3jIbTD+78EbuPZILFEA5fK0mliVRBx7oM7oPULeVX0lxSRXBV1jw==
dependencies:
bluebird "^3.5.0"
cls-bluebird "^2.1.0"
validator "^10.11.0"
wkx "^0.4.6"
-serve-static@1.13.2:
- version "1.13.2"
- resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1"
- integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==
+serve-static@1.14.1:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
+ integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
dependencies:
encodeurl "~1.0.2"
escape-html "~1.0.3"
- parseurl "~1.3.2"
- send "0.16.2"
+ parseurl "~1.3.3"
+ send "0.17.1"
serve-static@~1.10.2:
version "1.10.3"
is-plain-object "^2.0.3"
split-string "^3.0.1"
-setprototypeof@1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
- integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
-
-sha@~2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae"
- integrity sha1-YDCCL70smCOUn49y7WQR7lzyWq4=
- dependencies:
- graceful-fs "^4.1.2"
- readable-stream "^2.0.2"
+setprototypeof@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
+ integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
sharp@^0.22.0:
- version "0.22.0"
- resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.22.0.tgz#cf4cfcb019941fd06ac24555d9f5bc84536d29be"
- integrity sha512-yInpiWYvVbE0hJylso2Q2A7QaYFBxGdSlVVHGeUf1F9JsQNAUpmaqdnX54TImgKbSCy9mQpEAoGm1pcKCZhCsQ==
+ version "0.22.1"
+ resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.22.1.tgz#a67c0e75567f03dd5a7861b901fec04072c5b0f4"
+ integrity sha512-lXzSk/FL5b/MpWrT1pQZneKe25stVjEbl6uhhJcTULm7PhmJgKKRbTDM/vtjyUuC/RLqL2PRyC4rpKwbv3soEw==
dependencies:
- bindings "^1.5.0"
- color "^3.1.0"
+ color "^3.1.1"
detect-libc "^1.0.3"
fs-copy-file-sync "^1.1.1"
- nan "^2.13.1"
+ nan "^2.13.2"
npmlog "^4.1.2"
- prebuild-install "^5.2.5"
- semver "^5.6.0"
+ prebuild-install "^5.3.0"
+ semver "^6.0.0"
simple-get "^3.0.3"
tar "^4.4.8"
tunnel-agent "^0.6.0"
simple-concat "^1.0.0"
simple-git@^1.85.0:
- version "1.110.0"
- resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.110.0.tgz#54eb179089d055a7783d32399246cebc9d9933e9"
- integrity sha512-UYY0rQkknk0P5eb+KW+03F4TevZ9ou0H+LoGaj7iiVgpnZH4wdj/HTViy/1tNNkmIPcmtxuBqXWiYt2YwlRKOQ==
+ version "1.113.0"
+ resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.113.0.tgz#668989728a1e9cf4ec6c72b69ea2eecc93489bea"
+ integrity sha512-i9WVsrK2u0G/cASI9nh7voxOk9mhanWY9eGtWBDSYql6m49Yk5/Fan6uZsDr/xmzv8n+eQ8ahKCoEr8cvU3h+g==
dependencies:
debug "^4.0.1"
ws "^6.0.0"
sitemap@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/sitemap/-/sitemap-2.1.0.tgz#1633cb88c196d755ad94becfb1c1bcacc6d3425a"
- integrity sha512-AkfA7RDVCITQo+j5CpXsMJlZ/8ENO2NtgMHYIh+YMvex2Hao/oe3MQgNa03p0aWY6srCfUA1Q02OgiWCAiuccA==
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/sitemap/-/sitemap-2.2.0.tgz#98b8502762c5d7e8c77c9be5061dce85b326f1b0"
+ integrity sha512-9Zoi3UBhSIt5jWENDRUbzsqLMJ+Fha3P2aQ2PRghmh0FOivtHsC4FAJdkAEKHvATajd74BWp/57Yh7kz/UA53Q==
dependencies:
lodash "^4.17.10"
url-join "^4.0.0"
xmlbuilder "^10.0.0"
-slash@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
- integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=
-
-slash@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
- integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==
+slash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+ integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
slice-ansi@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=
-slide@^1.1.6, slide@~1.1.3, slide@~1.1.6:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
- integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=
-
-smart-buffer@4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.2.tgz#5207858c3815cc69110703c6b94e46c15634395d"
- integrity sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==
-
smtp-connection@2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-2.3.1.tgz#d169c8f1c9a73854134cdabe6fb818237dfc4fba"
socket.io-client "2.2.0"
socket.io-parser "~3.3.0"
-socks-proxy-agent@^4.0.0:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz#3c8991f3145b2799e70e11bd5fbc8b1963116386"
- integrity sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==
- dependencies:
- agent-base "~4.2.1"
- socks "~2.3.2"
-
-socks@~2.3.2:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/socks/-/socks-2.3.2.tgz#ade388e9e6d87fdb11649c15746c578922a5883e"
- integrity sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ==
- dependencies:
- ip "^1.1.5"
- smart-buffer "4.0.2"
-
-sorted-object@~2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc"
- integrity sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw=
-
-sorted-union-stream@~2.1.3:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz#c7794c7e077880052ff71a8d4a2dbb4a9a638ac7"
- integrity sha1-x3lMfgd4gAUv9xqNSi27Sppjisc=
- dependencies:
- from2 "^1.3.0"
- stream-iterate "^1.1.0"
-
source-map-resolve@^0.5.0:
version "0.5.2"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
urix "^0.1.0"
source-map-support@^0.5.0, source-map-support@^0.5.6:
- version "0.5.11"
- resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.11.tgz#efac2ce0800355d026326a0ca23e162aeac9a4e2"
- integrity sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ==
+ version "0.5.12"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599"
+ integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
spdx-license-ids "^3.0.0"
spdx-license-ids@^3.0.0:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz#81c0ce8f21474756148bbb5f3bfc0f36bf15d76e"
- integrity sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1"
+ integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==
speedometer@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-1.1.0.tgz#a30b13abda45687a1a76977012c060f2ac8a7934"
integrity sha512-z/wAiTESw2XVPssY2XRcme4niTc4S5FkkJ4gknudtVoc33Zil8TdTxHy5torRcgqMqksJV2Yz8HQcvtbsnw0mQ==
-split-on-first@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.0.0.tgz#648af4ce9a28fbcaadd43274455f298b55025fc6"
- integrity sha512-mjA57TQtdWztVZ9THAjGNpgbuIrNfsNrGa5IyK94NoPaT4N14M+GI4jD7t4arLjFkYRQWdETC5RxFzLWouoB3A==
-
split-string@^3.0.1, split-string@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
safer-buffer "^2.0.2"
tweetnacl "~0.14.0"
-ssri@^6.0.0, ssri@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8"
- integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==
- dependencies:
- figgy-pudding "^3.5.1"
-
stack-trace@0.0.x:
version "0.0.10"
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
define-property "^0.2.5"
object-copy "^0.1.0"
-statuses@1, "statuses@>= 1.4.0 < 2":
+statuses@1, "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.2.1.tgz#dded45cc18256d51ed40aec142489d5c61026d28"
integrity sha1-3e1FzBglbVHtQK7BQkidXGECbSg=
-statuses@~1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
- integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
-
-stream-each@^1.1.0:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
- integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==
- dependencies:
- end-of-stream "^1.1.0"
- stream-shift "^1.0.0"
-
-stream-iterate@^1.1.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/stream-iterate/-/stream-iterate-1.2.0.tgz#2bd7c77296c1702a46488b8ad41f79865eecd4e1"
- integrity sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE=
- dependencies:
- readable-stream "^2.1.5"
- stream-shift "^1.0.0"
-
stream-shift@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952"
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
-strict-uri-encode@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
- integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=
-
string-argv@^0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.0.2.tgz#dac30408690c21f3c3630a3ff3a05877bdcbd736"
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
+string-width@^3.0.0, string-width@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
+ integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
+ dependencies:
+ emoji-regex "^7.0.1"
+ is-fullwidth-code-point "^2.0.0"
+ strip-ansi "^5.1.0"
+
string2compact@^1.1.1, string2compact@^1.2.5:
version "1.3.0"
resolved "https://registry.yarnpkg.com/string2compact/-/string2compact-1.3.0.tgz#22d946127b082d1203c51316af60117a337423c3"
is-obj "^1.0.1"
is-regexp "^1.0.0"
-stringify-package@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.0.tgz#e02828089333d7d45cd8c287c30aa9a13375081b"
- integrity sha512-JIQqiWmLiEozOC0b0BtxZ/AOUtdUZHCBPgqIZ2kSJJqGwgb9neo44XdTHUC4HZSGqi03hOeB7W/E8rAlKnGe9g==
-
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
dependencies:
ansi-regex "^3.0.0"
+strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
+ integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
+ dependencies:
+ ansi-regex "^4.1.0"
+
strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"
integrity sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=
-summon-install@^0.4.3:
- version "0.4.6"
- resolved "https://registry.yarnpkg.com/summon-install/-/summon-install-0.4.6.tgz#25673446e8b92f8bc0afabc464aa7b73fe946bd5"
- integrity sha512-xLiRo8z2srFItquk4VXGfC6AsELPmFCYev5pipARHVCikrgCBdjHMxs2ZGfVcsOOKwTgEL6bVFutf5yF43GBZw==
- dependencies:
- descrevit "^0.1.1"
- dot-json "^1.0.3"
- npm "*"
-
superagent@^3.8.3:
version "3.8.3"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
-synchronous-promise@^2.0.5:
- version "2.0.7"
- resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.7.tgz#3574b3d2fae86b145356a4b89103e1577f646fe3"
- integrity sha512-16GbgwTmFMYFyQMLvtQjvNWh30dsFe1cAW5Fg1wm5+dg84L9Pe36mftsIRU95/W2YsISxsz/xq4VB23sqpgb/A==
+synchronous-promise@^2.0.6:
+ version "2.0.9"
+ resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.9.tgz#b83db98e9e7ae826bf9c8261fd8ac859126c780a"
+ integrity sha512-LO95GIW16x69LuND1nuuwM4pjgFGupg7pZ/4lU86AmchPKrhk0o2tpMU2unXRrqo81iAFe1YJ0nAGEVwsrZAgg==
table@^3.7.8:
version "3.8.3"
to-buffer "^1.1.1"
xtend "^4.0.0"
-tar@^2.0.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
- integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=
- dependencies:
- block-stream "*"
- fstream "^1.0.2"
- inherits "2"
-
tar@^4, tar@^4.4.8:
- version "4.4.8"
- resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d"
- integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==
+ version "4.4.10"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1"
+ integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==
dependencies:
chownr "^1.1.1"
fs-minipass "^1.2.5"
- minipass "^2.3.4"
- minizlib "^1.1.1"
+ minipass "^2.3.5"
+ minizlib "^1.2.1"
mkdirp "^0.5.0"
safe-buffer "^5.1.2"
- yallist "^3.0.2"
+ yallist "^3.0.3"
term-size@^1.2.0:
version "1.2.0"
readable-stream ">=1.1.13-1 <1.2.0-0"
xtend ">=4.0.0 <4.1.0-0"
-through2@^2.0.0, through2@^2.0.3:
+through2@^2.0.3:
version "2.0.5"
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
readable-stream "~2.3.6"
xtend "~4.0.1"
-through@2, "through@>=2.2.7 <3", through@^2.3.6:
+through@2, through@^2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
es5-ext "~0.10.46"
next-tick "1"
-tiny-relative-date@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07"
- integrity sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A==
-
tmp@0.0.x:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
peek-stream "^1.1.1"
stream-splicer "^1.3.1"
+toidentifier@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
+ integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
+
toposort-class@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988"
resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
-ts-node@8.0.3:
- version "8.0.3"
- resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.0.3.tgz#aa60b836a24dafd8bf21b54766841a232fdbc641"
- integrity sha512-2qayBA4vdtVRuDo11DEFSsD/SFsBXQBRZZhbRGSIkmYmVkWjULn/GGMdG10KVqkaGndljfaTD8dKjWgcejO8YA==
+ts-node@8.2.0:
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.2.0.tgz#4a89754b00560bb24cd54526e1685fa38c45f240"
+ integrity sha512-m8XQwUurkbYqXrKqr3WHCW310utRNvV5OnRVeISeea7LoCWVcdfeB/Ntl8JYWFh+WRoUAdBgESrzKochQt7sMw==
dependencies:
arg "^4.1.0"
- diff "^3.1.0"
+ diff "^4.0.1"
make-error "^1.1.1"
source-map-support "^0.5.6"
yn "^3.0.0"
tsutils "^3.0.0"
tslint@^5.7.0:
- version "5.15.0"
- resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.15.0.tgz#6ffb180986d63afa1e531feb2a134dbf961e27d3"
- integrity sha512-6bIEujKR21/3nyeoX2uBnE8s+tMXCQXhqMmaIPJpHmXJoBJPTLcI7/VHRtUwMhnLVdwLqqY3zmd8Dxqa5CVdJA==
+ version "5.17.0"
+ resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.17.0.tgz#f9f0ce2011d8e90debaa6e9b4975f24cd16852b8"
+ integrity sha512-pflx87WfVoYepTet3xLfDOLDm9Jqi61UXIKePOuca0qoAZyrGWonDG9VTbji58Fy+8gciUn8Bt7y69+KEVjc/w==
dependencies:
- babel-code-frame "^6.22.0"
+ "@babel/code-frame" "^7.0.0"
builtin-modules "^1.1.1"
chalk "^2.3.0"
commander "^2.12.1"
diff "^3.2.0"
glob "^7.1.1"
- js-yaml "^3.13.0"
+ js-yaml "^3.13.1"
minimatch "^3.0.4"
mkdirp "^0.5.1"
resolve "^1.3.2"
tslib "^1.8.1"
tsutils@^3.0.0:
- version "3.9.1"
- resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.9.1.tgz#2a40dc742943c71eca6d5c1994fcf999956be387"
- integrity sha512-hrxVtLtPqQr//p8/msPT1X1UYXUjizqSit5d9AQ5k38TcV38NyecL5xODNxa73cLe/5sdiJ+w1FqzDhRBA/anA==
+ version "3.14.0"
+ resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.14.0.tgz#bf8d5a7bae5369331fa0f2b0a5a10bd7f7396c77"
+ integrity sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw==
dependencies:
tslib "^1.8.1"
dependencies:
safe-buffer "^5.0.1"
-tv4@~1.2.7:
- version "1.2.7"
- resolved "https://registry.yarnpkg.com/tv4/-/tv4-1.2.7.tgz#bd29389afc73ade49ae5f48142b5d544bf68d120"
- integrity sha1-vSk4mvxzreSa5fSBQrXVRL9o0SA=
+tv4@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/tv4/-/tv4-1.3.0.tgz#d020c846fadd50c855abb25ebaecc68fc10f7963"
+ integrity sha1-0CDIRvrdUMhVq7JeuuzGj8EPeWM=
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+type-fest@^0.3.0:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1"
+ integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==
+
+type-fest@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8"
+ integrity sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==
+
type-is@1.6.15:
version "1.6.15"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
media-typer "0.3.0"
mime-types "~2.1.15"
-type-is@^1.6.4, type-is@~1.6.16, type-is@~1.6.6:
- version "1.6.16"
- resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194"
- integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==
+type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18, type-is@~1.6.6:
+ version "1.6.18"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
dependencies:
media-typer "0.3.0"
- mime-types "~2.1.18"
+ mime-types "~2.1.24"
typedarray-to-buffer@^3.0.0:
version "3.1.5"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@^3.4.3:
- version "3.4.3"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.3.tgz#0eb320e4ace9b10eadf5bc6103286b0f8b7c224f"
- integrity sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ==
-
-uid-number@0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
- integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.1.tgz#ba72a6a600b2158139c5dd8850f700e231464202"
+ integrity sha512-64HkdiRv1yYZsSe4xC1WVgamNigVYjlssIoaH2HcZF0+ijsk5YK2g0G34w9wJkze8+5ow4STd22AynfO6ZYYLw==
uint64be@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa"
integrity sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=
-umask@^1.1.0, umask@~1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d"
- integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=
-
undefsafe@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76"
dependencies:
debug "^2.2.0"
-underscore-keypath@~0.0.22:
- version "0.0.22"
- resolved "https://registry.yarnpkg.com/underscore-keypath/-/underscore-keypath-0.0.22.tgz#48a528392bb6efc424be1caa56da4b5faccf264d"
- integrity sha1-SKUoOSu278QkvhyqVtpLX6zPJk0=
- dependencies:
- underscore "*"
-
-underscore@*:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961"
- integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==
-
union-value@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=
-unique-filename@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"
- integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==
- dependencies:
- unique-slug "^2.0.0"
-
-unique-slug@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6"
- integrity sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==
- dependencies:
- imurmurhash "^0.1.4"
-
unique-string@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068"
integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==
-update-notifier@^2.3.0, update-notifier@^2.5.0:
+update-notifier@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6"
integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
-util-extend@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f"
- integrity sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=
-
util.promisify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
-validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4:
+validate-npm-package-license@^3.0.1:
version "3.0.4"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
-validate-npm-package-name@^3.0.0, validate-npm-package-name@~3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e"
- integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34=
- dependencies:
- builtins "^1.0.3"
-
-validator@^10.0.0, validator@^10.11.0, validator@^10.2.0, validator@^10.4.0:
+validator@^10.0.0, validator@^10.11.0, validator@^10.4.0:
version "10.11.0"
resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228"
integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==
+validator@^11.0.0:
+ version "11.0.0"
+ resolved "https://registry.yarnpkg.com/validator/-/validator-11.0.0.tgz#fb10128bfb1fd14ce4ed36b79fc94289eae70667"
+ integrity sha512-+wnGLYqaKV2++nUv60uGzUJyJQwYVOin6pn1tgEiFCeCQO60yeu3Og9/yPccbBX574kxIcEJicogkzx6s6eyag==
+
vary@^1, vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
pump "^3.0.0"
range-slice-stream "^2.0.0"
-wcwidth@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
- integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
- dependencies:
- defaults "^1.0.3"
-
webfinger.js@^2.6.6:
version "2.7.0"
resolved "https://registry.yarnpkg.com/webfinger.js/-/webfinger.js-2.7.0.tgz#403354a14a65aeeba64c1408c18a387487cea106"
resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"
integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=
-which@1, which@1.3.1, which@^1.1.1, which@^1.2.10, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1:
+which@1.3.1, which@^1.1.1, which@^1.2.10, which@^1.2.9, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
-worker-farm@^1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0"
- integrity sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==
- dependencies:
- errno "~0.1.7"
-
wrap-ansi@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
string-width "^2.1.1"
strip-ansi "^4.0.0"
+wrap-ansi@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
+ integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==
+ dependencies:
+ ansi-styles "^3.2.0"
+ string-width "^3.0.0"
+ strip-ansi "^5.0.0"
+
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
-write-file-atomic@^2.0.0, write-file-atomic@^2.3.0, write-file-atomic@^2.4.2:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.2.tgz#a7181706dfba17855d221140a9c06e15fcdd87b9"
- integrity sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==
+write-file-atomic@^2.0.0:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481"
+ integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==
dependencies:
graceful-fs "^4.1.11"
imurmurhash "^0.1.4"
dependencies:
async-limiter "~1.0.0"
+ws@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.0.0.tgz#79351cbc3f784b3c20d0821baf4b4ff809ffbf51"
+ integrity sha512-cknCal4k0EAOrh1SHHPPWWh4qm93g1IuGGGwBjWkXmCG7LsDtL8w9w+YVfaF+KSVwiHQKDIMsSLBVftKf9d1pg==
+ dependencies:
+ async-limiter "^1.0.0"
+
ws@~6.1.0:
version "6.1.4"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8=
xliff@^4.0.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/xliff/-/xliff-4.3.0.tgz#de08098a63ead8afde0bae83f059b8cbf3badaf1"
- integrity sha512-YDGHMdgmzDOjDm9ys+CdesxC9NBaxOcARR8fdJKHS8qY+XbW6g0BAaRBj0ssC1H9s5lrY0m2uqLCu0HB58K2ag==
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/xliff/-/xliff-4.3.1.tgz#ae82d1c6283014aa7506c9957bcb3f95ed1ce505"
+ integrity sha512-SERrOPuKZ/5XyEiv+cXgIjidQq4vp6HYS0yBS2GwC1TDJiREFaUIin3qg4OBlD6jdFWdPOMwkXGackAvgZ6+LQ==
dependencies:
xml-js "1.6.11"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
-y18n@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
- integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
-
"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
-yallist@^3.0.0, yallist@^3.0.2:
+yallist@^3.0.0, yallist@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
-yargs-parser@11.1.1, yargs-parser@^11.1.1:
+yargs-parser@13.0.0:
+ version "13.0.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b"
+ integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==
+ dependencies:
+ camelcase "^5.0.0"
+ decamelize "^1.2.0"
+
+yargs-parser@^11.1.1:
version "11.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4"
integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==
camelcase "^5.0.0"
decamelize "^1.2.0"
+yargs-parser@^13.0.0, yargs-parser@^13.1.0:
+ version "13.1.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.0.tgz#7016b6dd03e28e1418a510e258be4bff5a31138f"
+ integrity sha512-Yq+32PrijHRri0vVKQEm+ys8mbqWjLiwQkMFNXEENutzLPP0bE4Lcd4iA3OQY5HF+GD3xXxf0MEHb8E4/SA3AA==
+ dependencies:
+ camelcase "^5.0.0"
+ decamelize "^1.2.0"
+
yargs-parser@^8.0.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950"
dependencies:
camelcase "^4.1.0"
-yargs-parser@^9.0.2:
- version "9.0.2"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077"
- integrity sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=
- dependencies:
- camelcase "^4.1.0"
-
yargs-unparser@1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d"
lodash "^4.17.11"
yargs "^12.0.5"
-yargs@12.0.5, yargs@^12.0.1, yargs@^12.0.5:
+yargs@13.2.2:
+ version "13.2.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.2.tgz#0c101f580ae95cea7f39d927e7770e3fdc97f993"
+ integrity sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==
+ dependencies:
+ cliui "^4.0.0"
+ find-up "^3.0.0"
+ get-caller-file "^2.0.1"
+ os-locale "^3.1.0"
+ require-directory "^2.1.1"
+ require-main-filename "^2.0.0"
+ set-blocking "^2.0.0"
+ string-width "^3.0.0"
+ which-module "^2.0.0"
+ y18n "^4.0.0"
+ yargs-parser "^13.0.0"
+
+yargs@^12.0.1, yargs@^12.0.5:
version "12.0.5"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"
integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==
y18n "^3.2.1 || ^4.0.0"
yargs-parser "^11.1.1"
-yargs@^11.0.0:
- version "11.1.0"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77"
- integrity sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==
+yargs@^13.2.2:
+ version "13.2.4"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83"
+ integrity sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==
dependencies:
- cliui "^4.0.0"
- decamelize "^1.1.1"
- find-up "^2.1.0"
- get-caller-file "^1.0.1"
- os-locale "^2.0.0"
+ cliui "^5.0.0"
+ find-up "^3.0.0"
+ get-caller-file "^2.0.1"
+ os-locale "^3.1.0"
require-directory "^2.1.1"
- require-main-filename "^1.0.1"
+ require-main-filename "^2.0.0"
set-blocking "^2.0.0"
- string-width "^2.0.0"
+ string-width "^3.0.0"
which-module "^2.0.0"
- y18n "^3.2.1"
- yargs-parser "^9.0.2"
+ y18n "^4.0.0"
+ yargs-parser "^13.1.0"
yeast@0.1.2:
version "0.1.2"
integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=
yn@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/yn/-/yn-3.0.0.tgz#0073c6b56e92aed652fbdfd62431f2d6b9a7a091"
- integrity sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q==
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.0.tgz#fcbe2db63610361afcc5eb9e0ac91e976d046114"
+ integrity sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg==
-youtube-dl@^1.12.2:
- version "1.13.1"
- resolved "https://registry.yarnpkg.com/youtube-dl/-/youtube-dl-1.13.1.tgz#2da47c0dad3c5391e2172b7811da46501b82edc4"
- integrity sha512-89mUKwOavaojNKQlyzW+A7Dph5G/oPYs6T/PTMcvgdRQ5E2+uDQgYPxWHQDMBhHOkxQaxvxQTiTPKQLdg0OI4w==
+youtube-dl@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/youtube-dl/-/youtube-dl-2.0.0.tgz#64f85beff21a5b0b5651437ea51d10effd3dad5a"
+ integrity sha512-1R5bcnBMVqQIk85wqTJ8pxPq5UbzxZXJy4KSaf3N1dedZG4uAzq5zuoiHcNcsGle5JtoHNpTWDBjTDhHO0SipQ==
dependencies:
hh-mm-ss "~1.2.0"
mkdirp "~0.5.1"
request "~2.88.0"
streamify "~0.2.9"
-yup@^0.26.10:
- version "0.26.10"
- resolved "https://registry.yarnpkg.com/yup/-/yup-0.26.10.tgz#3545839663289038faf25facfc07e11fd67c0cb1"
- integrity sha512-keuNEbNSnsOTOuGCt3UJW69jDE3O4P+UHAakO7vSeFMnjaitcmlbij/a3oNb9g1Y1KvSKH/7O1R2PQ4m4TRylw==
+yup@^0.27.0:
+ version "0.27.0"
+ resolved "https://registry.yarnpkg.com/yup/-/yup-0.27.0.tgz#f8cb198c8e7dd2124beddc2457571329096b06e7"
+ integrity sha512-v1yFnE4+u9za42gG/b/081E7uNW9mUj3qtkmelLbW5YPROZzSH/KUUyJu9Wt8vxFJcT9otL/eZopS0YK1L5yPQ==
dependencies:
- "@babel/runtime" "7.0.0"
+ "@babel/runtime" "^7.0.0"
fn-name "~2.0.1"
- lodash "^4.17.10"
+ lodash "^4.17.11"
property-expr "^1.5.0"
- synchronous-promise "^2.0.5"
+ synchronous-promise "^2.0.6"
toposort "^2.0.2"
z-schema@^3.24.2: