doctype html html head meta(http-equiv="Content-Type" content="text/html;charset=utf-8") meta(http-equiv="Cache-Control" content="no-cache") meta(http-equiv="referrer" content="no-referrer") meta(http-equiv="viewport" content="width=device-width,initial-scale=1,user-scalable=no") title VRCX link(rel="dns-prefetch" href="https://fonts.gstatic.com") link(rel="preconnect" href="https://api.vrchat.cloud") link(rel="preconnect" href="https://d348imysud55la.cloudfront.net") link(rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans+JP|Noto+Sans+KR&display=swap") link(rel="stylesheet" href="app.css") body .x-app#x-app(style="display:none") //- login .x-login-container(v-show="!API.isLoggedIn") div(style="width:300px;margin:auto") el-form(ref="loginForm" :model="loginForm" :rules="loginForm.rules" v-loading="loginForm.loading" @submit.native.prevent="login()") el-form-item(label="Username or Email" prop="username" required) el-input(v-model="loginForm.username" name="username" placeholder="Username or Email" clearable) el-form-item(label="Password" prop="password" required) el-input(type="password" v-model="loginForm.password" name="password" placeholder="Password" clearable show-password) el-form-item(style="margin-top:35px") el-button(native-type="submit" type="primary" :loading="loginForm.loading" style="width:100%") Login el-form-item el-button(:loading="loginForm.loading" style="width:100%" @click="loginWithSteam()") Login with Steam div(style="text-align:center;font-size:12px") p © 2019-2020 #[a(href="https://github.com/pypy-vrc" target="_blank") pypy] (mina#5656) p VRCX is an assistant application for provide information about manage friendship. this application uses unofficial VRChat API (VRCSDK). p VRCX isn't endorsed by VRChat and doesn't reflect the views or opinions of VRChat or anyone officially involved in producing or managing VRChat. VRChat is trademark of VRChat Inc. VRChat Β© VRChat Inc. p pypy is not responsible for any problems caused by VRCX. Use at your own risk! //- menu .x-menu-container el-menu(ref="menu" collapse @select="selectMenu") mixin menuitem(index, name, icon) el-menu-item(index=index) i(class=icon) template(#title) span= name +menuitem('feed', 'Feed', 'el-icon-news') +menuitem('gameLog', 'Game Log', 'el-icon-s-data') +menuitem('search', 'Search', 'el-icon-search') +menuitem('favorite', 'Favorite', 'el-icon-star-off') +menuitem('friendLog', 'Friend Log', 'el-icon-notebook-2') +menuitem('moderation', 'Moderation', 'el-icon-finished') +menuitem('notification', 'Notification', 'el-icon-bell') +menuitem('more', 'More', 'el-icon-s-tools') //- feed .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'feed'") data-tables(v-bind="feedTable") template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") div(style="flex:none;margin-right:10px") el-switch(v-model="feedTable.filters[2].value" active-color="#13ce66") el-select(v-model="feedTable.filters[0].value" multiple clearable collapse-tags style="flex:1" placeholder="Filter") el-option(v-once v-for="type in ['GPS', 'Online', 'Offline', 'Status', 'Avatar']" :key="type" :label="type" :value="type") el-input(v-model="feedTable.filters[1].value" placeholder="Search" style="flex:none;width:150px;margin:0 10px") el-button(type="default" @click="clearFeed()" icon="el-icon-delete" circle style="flex:none") el-table-column(type="expand") template(v-once #default="scope") div(style="position:relative;font-size:14px") template(v-if="scope.row.type === 'GPS'") location(:location="scope.row.location[1]") el-tag(type="info" effect="plain" size="mini" style="margin-left:5px") {{ scope.row.time | timeToText }} br span i.el-icon-right location(:location="scope.row.location[0]") template(v-else-if="scope.row.type === 'Offline'") location(:location="scope.row.location") el-tag(type="info" effect="plain" size="mini" style="margin-left:5px") {{ scope.row.time | timeToText }} template(v-else-if="scope.row.type === 'Online'") location(:location="scope.row.location") template(v-else-if="scope.row.type === 'Avatar'") template(v-if="scope.row.avatar[0] === Object(scope.row.avatar[0])") //- high resolution (v2) 2020.07.12~ el-popover(placement="right" width="500px" trigger="click") img.x-link(slot="reference" v-lazy="scope.row.avatar[1].currentAvatarThumbnailImageUrl" style="flex:none;width:160px;height:120px;border-radius:4px") img.x-link(v-lazy="scope.row.avatar[1].currentAvatarImageUrl" style="width:500px;height:375px" @click="showAvatarAuthorDialog(scope.row.userId, scope.row.avatar[1].currentAvatarImageUrl)") span(style="position:relative;top:-50px;margin:0 5px") i.el-icon-right el-popover(placement="right" width="500px" trigger="click") img.x-link(slot="reference" v-lazy="scope.row.avatar[0].currentAvatarThumbnailImageUrl" style="flex:none;width:160px;height:120px;border-radius:4px") img.x-link(v-lazy="scope.row.avatar[0].currentAvatarImageUrl" style="width:500px;height:375px" @click="showAvatarAuthorDialog(scope.row.userId, scope.row.avatar[0].currentAvatarImageUrl)") template(v-else) //- legacy el-popover(placement="right" width="500px" trigger="click") img.x-link(slot="reference" v-lazy="scope.row.avatar[1]" style="flex:none;width:160px;height:120px;border-radius:4px") img(v-lazy="scope.row.avatar[1]" style="width:500px;height:375px") span(style="position:relative;top:-50px;margin:0 5px") i.el-icon-right el-popover(placement="right" width="500px" trigger="click") img.x-link(slot="reference" v-lazy="scope.row.avatar[0]" style="flex:none;width:160px;height:120px;border-radius:4px") img(v-lazy="scope.row.avatar[0]" style="width:500px;height:375px") template(v-else-if="scope.row.type === 'Status'") el-tooltip(placement="top") template(#content) span(v-if="scope.row.status[1].status === 'active'") Online span(v-else-if="scope.row.status[1].status === 'join me'") Join Me span(v-else-if="scope.row.status[1].status === 'ask me'") Ask Me span(v-else-if="scope.row.status[1].status === 'busy'") Do Not Disturb span(v-else) Offline i.x-user-status(:class="userStatusClass(scope.row.status[1])") span(v-text="scope.row.status[1].statusDescription") br span i.el-icon-right el-tooltip(placement="top") template(#content) span(v-if="scope.row.status[0].status === 'active'") Online span(v-else-if="scope.row.status[0].status === 'join me'") Join Me span(v-else-if="scope.row.status[0].status === 'ask me'") Ask Me span(v-else-if="scope.row.status[0].status === 'busy'") Do Not Disturb span(v-else) Offline i.x-user-status(:class="userStatusClass(scope.row.status[0])") span(v-text="scope.row.status[0].statusDescription") el-table-column(label="Date" prop="created_at" sortable="custom" width="100") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('YYYY-MM-DD HH24:MI:SS') }} span {{ scope.row.created_at | formatDate('MM-DD HH24:MI') }} el-table-column(label="Type" prop="type" width="80") el-table-column(label="User" prop="displayName") template(v-once #default="scope") span.x-link(v-text="scope.row.displayName" @click="showUserDialog(scope.row.userId)") el-table-column(label="Detail") template(v-once #default="scope") template(v-if="scope.row.type === 'GPS'") location(:location="scope.row.location[0]") template(v-else-if="scope.row.type === 'Offline' || scope.row.type === 'Online'") location(:location="scope.row.location") template(v-else-if="scope.row.type === 'Status'") el-tooltip(placement="top") template(#content) span(v-if="scope.row.status[0].status === 'active'") Online span(v-else-if="scope.row.status[0].status === 'join me'") Join Me span(v-else-if="scope.row.status[0].status === 'ask me'") Ask Me span(v-else-if="scope.row.status[0].status === 'busy'") Do Not Disturb span(v-else) Offline i.x-user-status(:class="userStatusClass(scope.row.status[0])") span(v-text="scope.row.status[0].statusDescription") //- gameLog .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'gameLog'") data-tables(v-bind="gameLogTable") template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") el-select(v-model="gameLogTable.filters[0].value" multiple clearable collapse-tags style="flex:1" placeholder="Filter") el-option(v-once v-for="type in ['Location', 'OnPlayerJoined', 'OnPlayerLeft', 'Notification']" :key="type" :label="type" :value="type") el-input(v-model="gameLogTable.filters[1].value" placeholder="Search" style="flex:none;width:150px;margin:0 10px") el-button(type="default" @click="resetGameLog()" icon="el-icon-refresh" circle style="flex:none") el-table-column(type="expand") template(v-once #default="scope") template(v-if="scope.row.type === 'Notification'") span(v-text="scope.row.data") el-table-column(label="Date" prop="created_at" sortable="custom" width="100") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('YYYY-MM-DD HH24:MI:SS') }} span {{ scope.row.created_at | formatDate('MM-DD HH24:MI') }} el-table-column(label="Type" prop="type" width="120") el-table-column(label="Detail" prop="data") template(v-once #default="scope") location(v-if="scope.row.type === 'Location'" :location="scope.row.data") span.x-link(v-else-if="scope.row.type !== 'Notification'" v-text="scope.row.data" @click="lookupUser(scope.row.data)") //- search .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'search'") div(style="margin:0 0 10px;display:flex;align-items:center") el-input(v-model="searchText" clearable placeholder="Search" @keyup.native.13="search()" style="flex:1") el-button(type="default" @click="clearSearch()" icon="el-icon-delete" circle style="flex:none;margin-left:10px") el-tabs(ref="searchTab" type="card" style="margin-top:15px") el-tab-pane(label="User" v-loading="isSearchUserLoading" style="min-height:60px") .x-friend-list .x-friend-item(v-for="user in searchUserResults" :key="user.id" @click="showUserDialog(user.id)") template(v-once) .avatar //img(v-if="user.userIcon" v-lazy="user.userIcon") No userIcon from search, API bug? img(v-lazy="user.currentAvatarThumbnailImageUrl") .detail span.name(v-text="user.displayName" :class="user.trustClass") span.extra(v-text="user.username" style="font-family:monospace") el-button-group(style="margin-top:15px") el-button(v-if="searchUserParams.offset" @click="moreSearchUser(-1)" icon="el-icon-back" size="small") Prev el-button(v-if="searchUserResults.length" @click="moreSearchUser(1)" icon="el-icon-right" size="small") Next el-tab-pane(label="World" v-loading="isSearchWorldLoading" style="min-height:60px") el-dropdown(@command="(row) => searchWorld(row)" size="small" trigger="click" style="margin-bottom:15px") el-button(size="small") Search by Category #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") el-dropdown-item(v-for="row in API.cachedConfig.dynamicWorldRows" :key="row.index" v-text="row.name" :command="row") .x-friend-list .x-friend-item(v-for="world in searchWorldResults" :key="world.id" @click="showWorldDialog(world.id)") template(v-once) .avatar img(v-lazy="world.thumbnailImageUrl") .detail span.name(v-text="world.name") span.extra(v-if="world.occupants") {{ world.authorName }} ({{ world.occupants }}) span.extra(v-else v-text="world.authorName") el-button-group(style="margin-top:15px") el-button(v-if="searchWorldParams.offset" @click="moreSearchWorld(-1)" icon="el-icon-back" size="small") Prev el-button(v-if="searchWorldResults.length" @click="moreSearchWorld(1)" icon="el-icon-right" size="small") Next el-tab-pane(label="Avatar" v-loading="isSearchAvatarLoading" style="min-height:60px") el-dropdown(@command="(command) => searchAvatar(command)" size="small" trigger="click" style="margin-bottom:15px") el-button(size="small") Search by Category #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") el-dropdown-item(command="updated") Updated Recently el-dropdown-item(command="created") New el-dropdown-item(command="mine") Mine span(style="margin-left:10px;font-size:12px;color:#909399") Avatar search is not possible. .x-friend-list .x-friend-item(v-for="avatar in searchAvatarResults" :key="avatar.id" @click="showAvatarDialog(avatar.id)") template(v-once) .avatar img(v-lazy="avatar.thumbnailImageUrl") .detail span.name(v-text="avatar.name") span.extra(v-text="avatar.authorName") el-button-group(style="margin-top:15px") el-button(v-if="searchAvatarParams.offset" @click="moreSearchAvatar(-1)" icon="el-icon-back" size="small") Prev el-button(v-if="searchAvatarResults.length" @click="moreSearchAvatar(1)" icon="el-icon-right" size="small") Next //- favorite .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'favorite'") el-button(type="default" :loading="API.isFavoriteLoading" @click="API.refreshFavorites()" size="small" icon="el-icon-refresh" circle style="position:relative;float:right;z-index:1") el-tabs(type="card" v-loading="API.isFavoriteLoading") el-tab-pane(label="Friend") el-collapse(style="border:0") el-collapse-item(v-for="group in API.favoriteFriendGroups" :key="group.name") template(slot="title") span(v-text="group.displayName" style="font-weight:bold;font-size:14px;margin-left:10px") span(style="color:#909399;font-size:12px;margin-left:10px") {{ group.count }}/{{ group.capacity }} el-button(@click.stop="changeFavoriteGroupName(group)" size="mini" icon="el-icon-edit" circle style="margin-left:10px") el-button(@click.stop="clearFavoriteGroup(group)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") .x-friend-list(v-if="group.count" style="margin-top:10px") .x-friend-item(v-for="favorite in favoriteFriends" v-if="favorite.groupKey === group.key" :key="favorite.id" @click="showUserDialog(favorite.id)") template(v-if="favorite.ref") .avatar(:class="userStatusClass(favorite.ref)") img(v-if="favorite.ref.userIcon" v-lazy="favorite.ref.userIcon") img(v-else v-lazy="favorite.ref.currentAvatarThumbnailImageUrl") .detail span.name(v-text="favorite.ref.displayName" :class="favorite.ref.$trustClass") location.extra(v-if="favorite.ref.location !== 'offline'" :location="favorite.ref.location" :link="false") span(v-else v-text="favorite.ref.statusDescription") template(v-else) span(v-text="favorite.name || favorite.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="deleteFavorite(favorite.id)" style="margin-left:5px") el-tab-pane(label="World") el-collapse(style="border:0") el-collapse-item(v-for="group in API.favoriteWorldGroups" :key="group.name") template(slot="title") span(v-text="group.displayName" style="font-weight:bold;font-size:14px;margin-left:10px") span(style="color:#909399;font-size:12px;margin-left:10px") {{ group.count }}/{{ group.capacity }} el-button(@click.stop="changeFavoriteGroupName(group)" size="mini" icon="el-icon-edit" circle style="margin-left:10px") el-button(@click.stop="clearFavoriteGroup(group)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") .x-friend-list(v-if="group.count" style="margin-top:10px") .x-friend-item(v-for="favorite in favoriteWorlds" v-if="favorite.groupKey === group.key" :key="favorite.id" @click="showWorldDialog(favorite.id)") template(v-if="favorite.ref") .avatar img(v-lazy="favorite.ref.thumbnailImageUrl") .detail span.name(v-text="favorite.ref.name") span.extra(v-if="favorite.ref.occupants") {{ favorite.ref.authorName }} ({{ favorite.ref.occupants }}) span.extra(v-else v-text="favorite.ref.authorName") template(v-else) span(v-text="favorite.name || favorite.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="deleteFavorite(favorite.id)" style="margin-left:5px") el-tab-pane(label="Avatar") el-collapse(style="border:0") el-collapse-item(v-for="group in API.favoriteAvatarGroups" :key="group.name") template(slot="title") span(v-text="group.displayName" style="font-weight:bold;font-size:14px;margin-left:10px") span(style="color:#909399;font-size:12px;margin-left:10px") {{ group.count }}/{{ group.capacity }} //- el-button(@click.stop="changeFavoriteGroupName(group)" size="mini" icon="el-icon-edit" circle style="margin-left:10px") el-button(@click.stop="clearFavoriteGroup(group)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") .x-friend-list(v-if="group.count" style="margin-top:10px") .x-friend-item(v-for="favorite in favoriteAvatars" v-if="favorite.groupKey === group.key" :key="favorite.id" @click="showAvatarDialog(favorite.id)") template(v-if="favorite.ref") .avatar img(v-lazy="favorite.ref.thumbnailImageUrl") .detail span.name(v-text="favorite.ref.name") span.extra(v-text="favorite.ref.authorName") template(v-else) span(v-text="favorite.name || favorite.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="deleteFavorite(favorite.id)" style="margin-left:5px") //- friendLog .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'friendLog'") data-tables(v-bind="friendLogTable") template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") el-select(v-model="friendLogTable.filters[0].value" multiple clearable collapse-tags style="flex:1" placeholder="Filter") el-option(v-once v-for="type in ['Friend', 'Unfriend', 'FriendRequest', 'CancelFriendRequest', 'DisplayName', 'TrustLevel']" :key="type" :label="type" :value="type") el-input(v-model="friendLogTable.filters[1].value" placeholder="Search" style="flex:none;width:150px;margin-left:10px") el-table-column(label="Date" prop="created_at" sortable="custom" width="100") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('YYYY-MM-DD HH24:MI:SS') }} span {{ scope.row.created_at | formatDate('MM-DD HH24:MI') }} el-table-column(label="Type" prop="type" width="150") el-table-column(label="User" prop="displayName") template(v-once #default="scope") span(v-if="scope.row.type === 'DisplayName'") {{ scope.row.previousDisplayName }} #[i.el-icon-right] |   span.x-link(v-text="scope.row.displayName || scope.row.userId" @click="showUserDialog(scope.row.userId)") template(v-if="scope.row.type === 'TrustLevel'") br span ({{ scope.row.previousTrustLevel }} #[i.el-icon-right] {{ scope.row.trustLevel }}) el-table-column(label="Action" width="80" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-close" size="mini" @click="deleteFriendLog(scope.row)") //- moderation .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'moderation'") data-tables(v-bind="playerModerationTable" v-loading="API.isPlayerModerationsLoading") template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") el-select(v-model="playerModerationTable.filters[0].value" multiple clearable collapse-tags style="flex:1" placeholder="Filter") el-option(v-once v-for="type in ['block', 'mute', 'unmute', 'hideAvatar', 'showAvatar']" :key="type" :label="type" :value="type") el-input(v-model="playerModerationTable.filters[1].value" placeholder="Search" style="flex:none;width:150px;margin:0 10px") el-button(type="default" :loading="API.isPlayerModerationsLoading" @click="API.refreshPlayerModerations()" icon="el-icon-refresh" circle style="flex:none") el-table-column(label="Date" prop="created" sortable="custom" width="100") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created | formatDate('YYYY-MM-DD HH24:MI:SS') }} span {{ scope.row.created | formatDate('MM-DD HH24:MI') }} el-table-column(label="Type" prop="type" width="100") el-table-column(label="Source" prop="sourceDisplayName") template(v-once #default="scope") span.x-link(v-text="scope.row.sourceDisplayName" @click="showUserDialog(scope.row.sourceUserId)") el-table-column(label="Target" prop="targetDisplayName") template(v-once #default="scope") span.x-link(v-text="scope.row.targetDisplayName" @click="showUserDialog(scope.row.targetUserId)") el-table-column(label="Action" width="80" align="right") template(v-once #default="scope") el-button(v-if="scope.row.sourceUserId === API.currentUser.id" type="text" icon="el-icon-close" size="mini" @click="deletePlayerModeration(scope.row)") //- notification .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'notification'" v-loading="API.isNotificationsLoading") data-tables(v-bind="notificationTable") template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") el-select(v-model="notificationTable.filters[0].value" multiple clearable collapse-tags style="flex:1" placeholder="Filter") el-option(v-once v-for="type in ['requestInvite', 'invite', 'friendRequest', 'message']" :key="type" :label="type" :value="type") el-input(v-model="notificationTable.filters[1].value" placeholder="Search" style="flex:none;width:150px;margin:0 10px") el-button(type="default" :loading="API.isNotificationsLoading" @click="API.refreshNotifications()" icon="el-icon-refresh" circle style="flex:none") el-table-column(label="Date" prop="created_at" sortable="custom" width="100") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('YYYY-MM-DD HH24:MI:SS') }} span {{ scope.row.created_at | formatDate('MM-DD HH24:MI') }} el-table-column(label="Type" prop="type" width="120") template(v-once #default="scope") el-tooltip(placement="top" v-if="scope.row.type === 'invite'") template(#content) span(v-text="API.parseInviteLocation(scope.row)") span.x-link(v-text="scope.row.type" @click="showWorldDialog(scope.row.details.worldId)") span(v-else v-text="scope.row.type") el-table-column(label="User" prop="senderUsername") template(v-once #default="scope") span.x-link(v-text="scope.row.senderUsername" @click="showUserDialog(scope.row.senderUserId)") el-table-column(label="Action" width="80" align="right") template(v-once #default="scope") el-button(v-if="scope.row.type === 'friendRequest'" type="text" icon="el-icon-check" size="mini" @click="acceptNotification(scope.row)") el-button(type="text" icon="el-icon-close" size="mini" @click="hideNotification(scope.row)") //- more .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'more'") div span(style="font-weight:bold") VRCX .x-friend-list(style="margin-top:10px") .x-friend-item .detail span.name Version span.extra(v-text="appVersion") .x-friend-item(@click="checkAppVersion()") .detail span.name Latest Version span.extra(v-if="latestAppVersion" v-text="latestAppVersion") span.extra(v-else) Click to refresh .x-friend-item(@click="openExternalLink('https://github.com/pypy-vrc/VRCX')") .detail span.name Repository URL span.extra https://github.com/pypy-vrc/VRCX div(style="margin-top:30px") span(style="font-weight:bold") Game Info .x-friend-list(style="margin-top:10px") .x-friend-item .detail(@click="API.getVisits()") span.name Online Users span.extra(v-if="visits") {{visits}} users online. span.extra(v-else) Click to refresh div(style="margin-top:5px") el-button-group el-button(size="small" icon="el-icon-s-operation" @click="showLaunchOptions()") Launch Options div(style="margin-top:30px") span(style="font-weight:bold") Config JSON el-button(type="default" @click="refreshConfigTreeData()" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") el-button(type="default" @click="configTreeData = []" size="mini" icon="el-icon-delete" circle style="margin-left:0") el-tree(:data="configTreeData" style="margin-top:5px;font-size:12px") template(#default="scope") span span(v-text="scope.data.key" style="font-weight:bold;margin-right:5px") span(v-if="!scope.data.children" v-text="scope.data.value") div(style="margin-top:30px") span(style="font-weight:bold") My Profile .x-friend-list(style="margin-top:10px") .x-friend-item(@click="showUserDialog(API.currentUser.id)") .avatar img(v-if="API.currentUser.userIcon" v-lazy="API.currentUser.userIcon") img(v-else v-lazy="API.currentUser.currentAvatarThumbnailImageUrl") .detail span.name(v-text="API.currentUser.displayName") span.extra(v-text="API.currentUser.username") .x-friend-item .detail span.name Last Login span.extra {{ API.currentUser.last_login | formatDate('YYYY-MM-DD HH24:MI:SS') }} .x-friend-item .detail span.name Two-Factor Auth (2FA) span.extra {{ API.currentUser.twoFactorAuthEnabled ? 'Enabled' : 'Disabled' }} div(style="margin-top:10px") el-button(size="small" icon="el-icon-switch-button" @click="logout()") Logout el-button(size="small" icon="el-icon-printer" @click="showExportFriendsListDialog()") Export Friends List div(style="margin-top:30px") span(style="font-weight:bold") Past Display Names data-tables(v-bind="pastDisplayNameTable" style="margin-top:5px") el-table-column(label="Date" prop="updated_at" sortable="custom") template(v-once #default="scope") span {{ scope.row.updated_at | formatDate('YYYY-MM-DD HH24:MI:SS') }} el-table-column(label="Name" prop="displayName") div(v-if="API.currentUser.$isVRCPlus" style="margin-top:30px") span(style="font-weight:bold") VRCPlus Icons el-button(type="default" @click="displayVRCPlusIconsTable()" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") el-button(type="default" @click="setVRCPlusIcon('')" size="mini" icon="el-icon-close" circle style="margin:0") input(type="file" @change="onFileChange") br .x-friend-item(v-for="icon in VRCPlusIconsTable" :key="icon.id" style="display:inline-block;") .vrcplus-icon(style="" @click="setVRCPlusIcon(icon.id)" :class="{ 'current-vrcplus-icon': 'https://api.vrchat.cloud/api/1/file/' + icon.id + '/1' === API.currentUser.userIcon }") img(v-if="icon.versions[1].file.url" v-lazy="icon.versions[1].file.url") el-button(type="default" @click="deleteVRCPlusIcon(icon.id)" size="mini" icon="el-icon-delete" circle style="float:right;") div(style="margin-top:30px") span(style="font-weight:bold") Current User JSON el-button(type="default" @click="refreshCurrentUserTreeData()" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") el-button(type="default" @click="currentUserTreeData = []" size="mini" icon="el-icon-delete" circle style="margin-left:0") el-tree(:data="currentUserTreeData" style="margin-top:5px;font-size:12px") template(#default="scope") span span(v-text="scope.data.key" style="font-weight:bold;margin-right:5px") span(v-if="!scope.data.children" v-text="scope.data.value") div(style="margin-top:30px") span(style="font-weight:bold") Direct Access div(style="margin-top:5px") el-button-group el-button(size="small" @click="promptUserDialog()") User el-button(size="small" @click="promptWorldDialog()") World el-button(size="small" @click="promptAvatarDialog()") Avatar div(style="margin-top:30px") span(style="font-weight:bold") Friends Sort Option div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") VIP el-switch(v-model="orderFriendsGroup0" inactive-text="by name" active-text="by state") div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") ONLINE el-switch(v-model="orderFriendsGroup1" inactive-text="by name" active-text="by state") div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") ACTIVE el-switch(v-model="orderFriendsGroup2" inactive-text="by name" active-text="by state") div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") OFFLINE el-switch(v-model="orderFriendsGroup3" inactive-text="by name" active-text="by state") div(style="margin-top:30px") span(style="font-weight:bold") Dark Mode div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Enable el-switch(v-model="isDarkMode") div(style="margin-top:30px") span(style="font-weight:bold") Discord Presence div(style="font-size:12px;margin-top:5px") span * Only works when VRChat is running. div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Enable el-switch(v-model="discordActive") div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Instance details el-switch(v-model="discordInstance" :disabled="!discordActive") div(style="margin-top:30px") span(style="font-weight:bold") SteamVR Overlay div(style="font-size:12px;margin-top:5px") span * It runs automatically when VRChat is running. br span Vive or Other Controller: Grab Button br span Oculus Controller: B Button br div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Enable el-switch(v-model="openVR") div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Force Run el-switch(v-model="openVRAlways" :disabled="!openVR") div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Hide VR Devices el-switch(v-model="hideDevicesFromFeed" :disabled="!openVR") div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Hide Online/Offline el-switch(v-model="hideLoginsFromFeed" :disabled="!openVR") div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Hide Private Worlds el-switch(v-model="hidePrivateFromFeed" :disabled="!openVR") div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Minimal Feed Icons el-switch(v-model="minimalFeed" :disabled="!openVR") div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Overlay Notifications el-switch(v-model="overlayNotifications" :disabled="!openVR") div(style="font-size:12px;margin-top:5px") el-button(size="small" icon="el-icon-time" @click="promptNotificationTimeout()" :disabled="!overlayNotifications || !openVR") Notification Timeout el-button(size="small" icon="el-icon-rank" @click="showNotificationPositionDialog()" :disabled="!overlayNotifications || !openVR") Notification Position div(style="font-size:12px;margin-top:5px") span Join/Leave Notifications br el-radio-group(v-model="notificationJoinLeaveFilter" size="mini" @change="changeNotificationJoinLeaveFilter" :disabled="!overlayNotifications || !openVR") el-radio(label="VIP" v-model="notificationJoinLeaveFilter") VIP el-radio(label="Friends" v-model="notificationJoinLeaveFilter") Friends el-radio(label="Everyone" v-model="notificationJoinLeaveFilter") Everyone el-radio(label="Off" v-model="notificationJoinLeaveFilter") Off div(style="font-size:12px;margin-top:5px") span Online/Offline Notifications br el-radio-group(v-model="notificationOnlineOfflineFilter" size="mini" @change="changeNotificationOnlineOfflineFilter" :disabled="!overlayNotifications || !openVR") el-radio(label="VIP" v-model="notificationOnlineOfflineFilter") VIP el-radio(label="Friends" v-model="notificationOnlineOfflineFilter") Friends el-radio(label="Off" v-model="notificationOnlineOfflineFilter") Off div(style="margin-top:30px") span(style="font-weight:bold") Window div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Start at Windows startup el-switch(v-model="isStartAtWindowsStartup") div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Start as minimized state el-switch(v-model="isStartAsMinimizedState") div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Close to tray el-switch(v-model="isCloseToTray") div(style="margin-top:45px;border-top:1px solid #eee;padding-top:30px") span(style="font-weight:bold") Legal Notice div(style="margin-top:5px;font-size:12px") p © 2019-2020 #[a(href="https://github.com/pypy-vrc" target="_blank") pypy] (mina#5656) p VRCX is an assistant application for provide information about manage friendship. this application uses unofficial VRChat API (VRCSDK). p VRCX isn't endorsed by VRChat and doesn't reflect the views or opinions of VRChat or anyone officially involved in producing or managing VRChat. VRChat is trademark of VRChat Inc. VRChat Β© VRChat Inc. p pypy is not responsible for any problems caused by VRCX. Use at your own risk! div(style="margin-top:5px;font-size:12px") el-button(@click="ossDialog = true" size="small") Open Source Software Notice //- friends .x-aside-container el-select(v-model="quickSearch" clearable placeholder="Search" filterable remote :remote-method="quickSearchRemoteMethod" popper-class="x-quick-search" @change="quickSearchChange" @visible-change="quickSearchVisibleChange" style="flex:none;padding:10px") el-option(v-for="item in quickSearchItems" :key="item.value" :value="item.value" :label="item.label") .x-friend-item template(v-if="item.ref") .detail span.name(v-text="item.ref.displayName" :class="item.ref.$trustClass") location.extra(:location="item.ref.location" :link="false") img.avatar(v-if="item.ref.userIcon" v-lazy="item.ref.userIcon") img.avatar(v-else v-lazy="item.ref.currentAvatarThumbnailImageUrl") span(v-else) Search More: #[span(v-text="item.label" style="font-weight:bold")] .x-friend-list(style="padding-bottom:10px") .x-friend-group i.el-icon-arrow-right(:class="{ rotate: isFriendsGroupMe }") span.x-link(@click="isFriendsGroupMe = !isFriendsGroupMe" style="margin-left:5px") ME div(v-show="isFriendsGroupMe") .x-friend-item(:key="API.currentUser.id" @click="showUserDialog(API.currentUser.id)") .avatar(:class="userStatusClass(API.currentUser)") img(v-if="API.currentUser.userIcon" v-lazy="API.currentUser.userIcon") img(v-else v-lazy="API.currentUser.currentAvatarThumbnailImageUrl") .detail span.name(v-text="API.currentUser.displayName" :class="API.currentUser.$trustClass") location.extra(v-if="isGameRunning === true" :location="lastLocation" :link="false") span.extra(v-else v-text="API.currentUser.statusDescription" :link="false") .x-friend-group(v-show="friendsGroup0.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup0 }") span.x-link(@click="isFriendsGroup0 = !isFriendsGroup0" style="margin-left:5px") VIP―{{ friendsGroup0.length }} div(v-show="isFriendsGroup0") .x-friend-item(v-for="friend in friendsGroup0" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") .avatar(:class="userStatusClass(friend.ref)") img(v-if="friend.ref.userIcon" v-lazy="friend.ref.userIcon") img(v-else v-lazy="friend.ref.currentAvatarThumbnailImageUrl") .detail span.name(v-if="friend.memo" :class="friend.ref.$trustClass") {{ friend.ref.displayName }} ({{ friend.memo }}) span.name(v-else v-text="friend.ref.displayName" :class="friend.ref.$trustClass") location.extra(:location="friend.ref.location" :link="false") template(v-else) span(v-text="friend.name || friend.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(friend.id)" style="margin-left:5px") .x-friend-group(v-show="friendsGroup1.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup1 }") span.x-link(@click="isFriendsGroup1 = !isFriendsGroup1" style="margin-left:5px") ONLINE―{{ friendsGroup1.length }} div(v-show="isFriendsGroup1") .x-friend-item(v-for="friend in friendsGroup1" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") .avatar(:class="userStatusClass(friend.ref)") img(v-if="friend.ref.userIcon" v-lazy="friend.ref.userIcon") img(v-else v-lazy="friend.ref.currentAvatarThumbnailImageUrl") .detail span.name(v-if="friend.memo" :class="friend.ref.$trustClass") {{ friend.ref.displayName }} ({{ friend.memo }}) span.name(v-else v-text="friend.ref.displayName" :class="friend.ref.$trustClass") location.extra(:location="friend.ref.location" :link="false") template(v-else) span(v-text="friend.name || friend.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(friend.id)" style="margin-left:5px") .x-friend-group(v-show="friendsGroup2.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup2 }") span.x-link(@click="isFriendsGroup2 = !isFriendsGroup2" style="margin-left:5px") ACTIVE―{{ friendsGroup2.length }} div(v-show="isFriendsGroup2") .x-friend-item(v-for="friend in friendsGroup2" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") .avatar img(v-if="friend.ref.userIcon" v-lazy="friend.ref.userIcon") img(v-else v-lazy="friend.ref.currentAvatarThumbnailImageUrl") .detail span.name(v-if="friend.memo" :class="friend.ref.$trustClass") {{ friend.ref.displayName }} ({{ friend.memo }}) span.name(v-else v-text="friend.ref.displayName" :class="friend.ref.$trustClass") span.extra(v-text="friend.ref.statusDescription" :link="false") template(v-else) span(v-text="friend.name || friend.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(friend.id)" style="margin-left:5px") .x-friend-group(v-show="friendsGroup3.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup3 }") span.x-link(@click="isFriendsGroup3 = !isFriendsGroup3" style="margin-left:5px") OFFLINE―{{ friendsGroup3.length }} div(v-show="isFriendsGroup3") .x-friend-item(v-for="friend in friendsGroup3" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") .avatar img(v-if="friend.ref.userIcon" v-lazy="friend.ref.userIcon") img(v-else v-lazy="friend.ref.currentAvatarThumbnailImageUrl") .detail span.name(v-if="friend.memo" :class="friend.ref.$trustClass") {{ friend.ref.displayName }} ({{ friend.memo }}) span.name(v-else v-text="friend.ref.displayName" :class="friend.ref.$trustClass") span.extra(v-text="friend.ref.statusDescription") template(v-else) span(v-text="friend.name || friend.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(friend.id)" style="margin-left:5px") //- dialog: user el-dialog.x-dialog.x-user-dialog(ref="userDialog" :visible.sync="userDialog.visible" :show-close="false" width="600px") div(v-loading="userDialog.loading") div(style="display:flex") el-popover(placement="right" width="500px" trigger="click") img.x-link(slot="reference" v-lazy="userDialog.ref.currentAvatarThumbnailImageUrl" style="flex:none;width:160px;height:120px;border-radius:4px") img(v-lazy="userDialog.ref.currentAvatarImageUrl" style="width:500px;height:375px") div(style="flex:1;display:flex;align-items:center;margin-left:15px") div(style="flex:1") div el-tooltip(v-if="userDialog.ref.status" placement="top") template(#content) span(v-if="userDialog.ref.location === 'offline'") Offline span(v-else-if="userDialog.ref.status === 'active'") Online span(v-else-if="userDialog.ref.status === 'join me'") Join Me span(v-else-if="userDialog.ref.status === 'ask me'") Ask Me span(v-else-if="userDialog.ref.status === 'busy'") Do Not Disturb span(v-else) Offline i.x-user-status(:class="userStatusClass(userDialog.ref)") span(v-text="userDialog.ref.displayName" style="margin-left:5px;font-weight:bold") el-popover(placement="top" trigger="click") span(slot="reference" v-text="userDialog.ref.username" style="margin-left:5px;color:#909399;font-family:monospace;font-size:12px;cursor:pointer") span(style="display:block;text-align:center;font-family:monospace") {{ userDialog.ref.username | textToHex }} el-tooltip(v-for="item in userDialog.ref.$languages" :key="item.key" placement="top") template(#content) span {{ item.value }} ({{ item.key }}) span.famfamfam-flags(:class="languageClass(item.key)" style="display:inline-block;margin-left:5px") div(style="margin-top:5px") el-tag.name(type="info" effect="plain" size="mini" :class="userDialog.ref.$trustClass" v-text="userDialog.ref.$trustLevel") el-tag.x-tag-friend(v-if="userDialog.isFriend && userDialog.friend" type="info" effect="plain" size="mini" style="margin-left:5px") Friend No.{{userDialog.friend.no}} el-tag.x-tag-vrcplus(type="info" effect="plain" size="mini" v-if="userDialog.ref.$isVRCPlus" style="margin-left:5px") VRC+ div(style="margin-top:5px") span(v-text="userDialog.ref.statusDescription" style="font-size:12px") div(v-if="userDialog.ref.userIcon" style="flex:none") el-popover(placement="right" width="500px" trigger="click") img.x-link(slot="reference" v-lazy="userDialog.ref.userIcon" style="flex:none;width:120px;height:120px;border-radius:4px") img(v-lazy="userDialog.ref.userIcon" style="width:500px;height:500px;") div(style="flex:none") el-button(v-if="userDialog.isFavorite" @click="userDialogCommand('Delete Favorite')" type="warning" icon="el-icon-star-on" circle) el-button(v-else type="default" @click="userDialogCommand('Add Favorite')" icon="el-icon-star-off" circle) el-dropdown(trigger="click" @command="userDialogCommand" size="small") el-button(:type="(userDialog.incomingRequest || userDialog.outgoingRequest) ? 'success' : (userDialog.isBlock || userDialog.isMute || userDialog.isHideAvatar) ? 'danger' : 'default'" icon="el-icon-more" circle style="margin-left:5px") el-dropdown-menu(#default="dropdown") template(v-if="userDialog.ref.id === API.currentUser.id") el-dropdown-item(icon="el-icon-s-custom" command="Show Avatar Details") Show Avatar Details el-dropdown-item(icon="el-icon-edit" command="Edit Social Status" divided) Social Status el-dropdown-item(icon="el-icon-edit" command="Edit Language") Language el-dropdown-item(icon="el-icon-edit" command="Edit Bio") Bio el-dropdown-item(icon="el-icon-switch-button" command="Logout" divided) Logout template(v-else) template(v-if="userDialog.isFriend") el-dropdown-item(icon="el-icon-postcard" command="Request Invite") Request Invite //- el-dropdown-item(icon="el-icon-message" command="Message") Message template(v-else-if="userDialog.incomingRequest") el-dropdown-item(icon="el-icon-check" command="Accept Friend Request") Accept Friend Request el-dropdown-item(icon="el-icon-close" command="Decline Friend Request") Decline Friend Request el-dropdown-item(v-else-if="userDialog.outgoingRequest" icon="el-icon-close" command="Cancel Friend Request") Cancel Friend Request el-dropdown-item(v-else icon="el-icon-plus" command="Send Friend Request") Send Friend Request el-dropdown-item(icon="el-icon-s-custom" command="Show Avatar Details" divided) Show Avatar Details el-dropdown-item(v-if="userDialog.isBlock" icon="el-icon-circle-check" command="Unblock" divided style="color:#F56C6C") Unblock el-dropdown-item(v-else icon="el-icon-circle-close" command="Block" divided) Block el-dropdown-item(v-if="userDialog.isMute" icon="el-icon-microphone" command="Unmute" style="color:#F56C6C") Unmute el-dropdown-item(v-else icon="el-icon-turn-off-microphone" command="Mute") Mute el-dropdown-item(v-if="userDialog.isHideAvatar" icon="el-icon-user-solid" command="Show Avatar" style="color:#F56C6C") Show Avatar el-dropdown-item(v-else icon="el-icon-user" command="Hide Avatar") Hide Avatar template(v-if="userDialog.isFriend") el-dropdown-item(icon="el-icon-delete" command="Unfriend" divided) Unfriend el-tabs el-tab-pane(label="Info") div(v-if="userDialog.ref.location" style="display:flex;flex-direction:column;margin-bottom:10px;padding-bottom:10px;border-bottom:1px solid #eee") div(style="flex:none") location(:location="userDialog.ref.location") template(#default v-if="userDialog.instance.occupants") ({{ userDialog.instance.occupants }}) launch(:location="userDialog.ref.location" style="margin-left:5px") invite-yourself(:location="userDialog.ref.location" style="margin-left:5px") .x-friend-list(style="flex:1;margin-top:10px") .x-friend-item(v-if="userDialog.$location.userId" @click="showUserDialog(userDialog.$location.userId)") template(v-if="userDialog.$location.user") .avatar(:class="userStatusClass(userDialog.$location.user)") img(v-if="userDialog.$location.user.userIcon" v-lazy="userDialog.$location.user.userIcon") img(v-else v-lazy="userDialog.$location.user.currentAvatarThumbnailImageUrl") .detail span.name(v-text="userDialog.$location.user.displayName" :class="userDialog.$location.user.$trustClass") span.extra Instance Creator span(v-else v-text="userDialog.$location.userId") .x-friend-item(v-for="user in userDialog.users" :key="user.id" @click="showUserDialog(user.id)") .avatar(:class="userStatusClass(user)") img(v-if="user.userIcon" v-lazy="user.userIcon") img(v-else v-lazy="user.currentAvatarThumbnailImageUrl") .detail span.name(v-text="user.displayName" :class="user.$trustClass") span.extra timer(:epoch="user.$location_at") .x-friend-list(style="max-height:none") .x-friend-item(style="width:100%") .detail span.name Note el-input.extra(v-model="userDialog.memo" type="textarea" :rows="2" placeholder="Click to add a note" size="mini" resize="none") .x-friend-item(style="width:100%") .detail span.name Bio pre.extra(style="font-family:inherit;font-size:12px;white-space:pre-wrap;margin:0 0.5em 0 0") {{ userDialog.ref.bio || '-' }} div(style="margin-top:5px") el-tooltip(v-for="(link, index) in userDialog.ref.bioLinks" :key="index") template(#content) span(v-text="link") img(:src="getFaviconUrl(link)" style="width:16px;height:16px;vertical-align:middle;margin-right:5px" @click.stop="openExternalLink(link)") .x-friend-item .detail span.name Avatar Copying span.extra(v-if="userDialog.ref.allowAvatarCopying" style="color:#67C23A") Allow span.extra(v-else style="color:#F56C6C") Deny .x-friend-item .detail span.name Last Login span.extra {{ userDialog.ref.last_login | formatDate('YYYY-MM-DD HH24:MI:SS') || '-' }} .x-friend-item .detail span.name Last Platform span.extra(v-text="userDialog.ref.last_platform") .x-friend-item(v-if="userDialog.ref.id === API.currentUser.id && API.currentUser.homeLocation" @click="showWorldDialog(API.currentUser.homeLocation)" style="width:100%") .detail span.name Home Location span.extra location(:location="API.currentUser.homeLocation" :link="false") el-button(@click.stop="resetHome()" size="mini" icon="el-icon-delete" circle style="margin-left:5px") el-tab-pane(label="Worlds") el-button(type="default" :loading="userDialog.isWorldsLoading" @click="refreshUserDialogWorlds()" size="mini" icon="el-icon-refresh" circle) span(style="margin-left:5px") Total {{ userDialog.worlds.length }} el-radio-group(v-model="userDialog.worldSorting" size="mini" style="margin-left:30px" @change="changeUserDialogWorldSorting") el-radio(label="name") by name el-radio(label="update") by update .x-friend-list(v-loading="userDialog.isWorldsLoading" style="margin-top:10px;min-height:60px") .x-friend-item(v-for="world in userDialog.worlds" :key="world.id" @click="showWorldDialog(world.id)") .avatar img(v-lazy="world.thumbnailImageUrl") .detail span.name(v-text="world.name") span.extra(v-if="world.occupants") ({{ world.occupants }}) el-tab-pane(label="Avatars") el-button(type="default" :loading="userDialog.isAvatarsLoading" @click="refreshUserDialogAvatars()" size="mini" icon="el-icon-refresh" circle) span(style="margin-left:5px") Total {{ userDialog.avatars.length }} el-radio-group(v-model="userDialog.avatarSorting" size="mini" style="margin-left:30px" @change="changeUserDialogAvatarSorting") el-radio(label="name") by name el-radio(label="update") by update .x-friend-list(v-loading="userDialog.isAvatarsLoading" style="margin-top:10px;min-height:60px") .x-friend-item(v-for="avatar in userDialog.avatars" :key="avatar.id" @click="showAvatarDialog(avatar.id)") .avatar img(v-lazy="avatar.thumbnailImageUrl") .detail span.name(v-text="avatar.name") el-tab-pane(label="JSON") el-button(type="default" @click="refreshUserDialogTreeData()" size="mini" icon="el-icon-refresh" circle) el-tree(:data="userDialog.treeData" style="margin-top:5px;font-size:12px") template(#default="scope") span span(v-text="scope.data.key" style="font-weight:bold;margin-right:5px") span(v-if="!scope.data.children" v-text="scope.data.value") //- dialog: world el-dialog.x-dialog.x-world-dialog(ref="worldDialog" :visible.sync="worldDialog.visible" :show-close="false" width="600px") div(v-loading="worldDialog.loading") div(style="display:flex") el-popover(placement="right" width="500px" trigger="click") img.x-link(slot="reference" v-lazy="worldDialog.ref.thumbnailImageUrl" style="flex:none;width:160px;height:120px;border-radius:4px") img(v-lazy="worldDialog.ref.imageUrl" style="width:500px;height:375px") div(style="flex:1;display:flex;align-items:center;margin-left:15px") div(style="flex:1") div i.el-icon-s-home(v-show="API.currentUser.$homeLocation && API.currentUser.$homeLocation.worldId === worldDialog.id") span(v-text="worldDialog.ref.name" style="font-weight:bold") div(style="margin-top:5px") span.x-link(v-text="worldDialog.ref.authorName" @click="showUserDialog(worldDialog.ref.authorId)" style="color:#909399;font-family:monospace") div(style="margin-top:5px") el-tag(v-if="worldDialog.ref.$isLabs" type="primary" effect="plain" size="mini") Labs el-tag(v-else-if="worldDialog.ref.releaseStatus === 'public'" type="success" effect="plain" size="mini") Public el-tag(v-else type="danger" effect="plain" size="mini") Private el-tag(type="info" effect="plain" size="mini" v-text="worldDialog.fileSize" style="margin-left:5px") div(style="margin-top:5px") span(v-show="worldDialog.ref.name !== worldDialog.ref.description" v-text="worldDialog.ref.description" style="font-size:12px") div(style="flex:none;margin-left:10px") el-button(v-if="worldDialog.isFavorite" type="warning" icon="el-icon-star-on" circle @click="worldDialogCommand('Delete Favorite')") el-button(v-else type="default" icon="el-icon-star-off" circle @click="worldDialogCommand('Add Favorite')") el-dropdown(trigger="click" @command="worldDialogCommand" size="small" style="margin-left:5px") el-button(type="default" icon="el-icon-more" circle) el-dropdown-menu(#default="dropdown") el-dropdown-item(icon="el-icon-refresh" command="Refresh") Refresh el-dropdown-item(icon="el-icon-s-flag" command="New Instance" divided) New Instance el-dropdown-item(v-if="API.currentUser.$homeLocation && API.currentUser.$homeLocation.worldId === worldDialog.id" icon="el-icon-magic-stick" command="Reset Home" divided) Reset Home el-dropdown-item(v-else icon="el-icon-s-home" command="Make Home" divided) Make Home el-tabs el-tab-pane(label="Instances") div. #[i.el-icon-user] Public {{ worldDialog.ref.publicOccupants | commaNumber }} #[i.el-icon-user-solid(style="margin-left:10px")] Private {{ worldDialog.ref.privateOccupants | commaNumber }} #[i.el-icon-check(style="margin-left:10px")] Capacity {{ worldDialog.ref.capacity | commaNumber }} div(v-for="room in worldDialog.rooms" :key="room.id") div(style="margin:5px 0") span.x-link(@click="showLaunchDialog(room.$location.tag)"). \#{{ room.$location.instanceName }} {{ room.$location.accessType }} #[template(v-if="room.occupants") ({{ room.occupants }})] invite-yourself(:location="room.$location.tag" style="margin-left:5px") .x-friend-list(style="margin:10px 0" v-if="room.$location.userId || room.users.length") .x-friend-item(v-if="room.$location.userId" @click="showUserDialog(room.$location.userId)") template(v-if="room.$location.user") .avatar(:class="userStatusClass(room.$location.user)") img(v-if="room.$location.user.userIcon" v-lazy="room.$location.user.userIcon") img(v-else v-lazy="room.$location.user.currentAvatarThumbnailImageUrl") .detail span.name(v-text="room.$location.user.displayName" :class="room.$location.user.$trustClass") span.extra Instance Creator span(v-else v-text="room.$location.userId") .x-friend-item(v-for="user in room.users" :key="user.id" @click="showUserDialog(user.id)") .avatar(:class="userStatusClass(user)") img(v-if="user.userIcon" v-lazy="user.userIcon") img(v-else v-lazy="user.currentAvatarThumbnailImageUrl") .detail span.name(v-text="user.displayName" :class="user.$trustClass") span.extra timer(:epoch="user.$location_at") el-tab-pane(label="Info") .x-friend-list(style="max-height:none") .x-friend-item .detail span.name Players span.extra {{ worldDialog.ref.occupants | commaNumber }} .x-friend-item .detail span.name Favorites span.extra {{ worldDialog.ref.favorites | commaNumber }} .x-friend-item .detail span.name Visits span.extra {{ worldDialog.ref.visits | commaNumber }} .x-friend-item .detail span.name Capacity span.extra(v-text="worldDialog.ref.capacity") .x-friend-item .detail span.name Heat span.extra {{ worldDialog.ref.heat | commaNumber }} {{ 'πŸ”₯'.repeat(worldDialog.ref.heat) }} .x-friend-item .detail span.name Popularity span.extra {{ worldDialog.ref.popularity | commaNumber }} {{ 'πŸ’–'.repeat(worldDialog.ref.popularity) }} .x-friend-item .detail span.name Created span.extra {{ worldDialog.ref.created_at | formatDate('YYYY-MM-DD HH24:MI:SS') || '-' }} .x-friend-item .detail span.name Last Updated span.extra {{ worldDialog.fileCreatedAt | formatDate('YYYY-MM-DD HH24:MI:SS') || '-' }} .x-friend-item .detail span.name Version span.extra(v-text="worldDialog.ref.version") .x-friend-item(style="width:100%") .detail span.name Platform span.extra(v-text="worldDialogPlatform") el-tab-pane(label="JSON") el-button(type="default" @click="refreshWorldDialogTreeData()" size="mini" icon="el-icon-refresh" circle) el-tree(:data="worldDialog.treeData" style="margin-top:5px;font-size:12px") template(#default="scope") span span(v-text="scope.data.key" style="font-weight:bold;margin-right:5px") span(v-if="!scope.data.children" v-text="scope.data.value") //- dialog: avatar el-dialog.x-dialog.x-avatar-dialog(ref="avatarDialog" :visible.sync="avatarDialog.visible" :show-close="false" width="600px") div(v-loading="avatarDialog.loading") div(style="display:flex") el-popover(placement="right" width="500px" trigger="click") img.x-link(slot="reference" v-lazy="avatarDialog.ref.thumbnailImageUrl" style="flex:none;width:160px;height:120px;border-radius:4px") img(v-lazy="avatarDialog.ref.imageUrl" style="width:500px;height:375px") div(style="flex:1;display:flex;align-items:center;margin-left:15px") div(style="flex:1") div span(v-text="avatarDialog.ref.name" style="font-weight:bold") div(style="margin-top:5px") span.x-link(v-text="avatarDialog.ref.authorName" @click="showUserDialog(avatarDialog.ref.authorId)" style="color:#909399;font-family:monospace") div(style="margin-top:5px") el-tag(v-if="avatarDialog.ref.releaseStatus === 'public'" type="success" effect="plain" size="mini") Public el-tag(v-else type="danger" effect="plain" size="mini") Private el-tag(type="info" effect="plain" size="mini" v-text="avatarDialog.fileSize" style="margin-left:5px") div(style="margin-top:5px") span(v-show="avatarDialog.ref.name !== avatarDialog.ref.description" v-text="avatarDialog.ref.description" style="font-size:12px") div(style="flex:none;margin-left:10px") el-button(v-if="avatarDialog.isFavorite" type="warning" icon="el-icon-star-on" circle @click="avatarDialogCommand('Delete Favorite')") el-button(v-else type="default" icon="el-icon-star-off" circle @click="avatarDialogCommand('Add Favorite')") el-dropdown(trigger="click" @command="avatarDialogCommand" size="small") el-button(type="default" icon="el-icon-more" circle) el-dropdown-menu(#default="dropdown") el-dropdown-item(icon="el-icon-check" command="Select Avatar") Select Avatar template(v-if="avatarDialog.ref.authorId === API.currentUser.id") el-dropdown-item(v-if="avatarDialog.ref.releaseStatus === 'public'" icon="el-icon-user-solid" command="Make Private" divided) Make Private el-dropdown-item(v-else icon="el-icon-user" command="Make Public" divided) Make Public el-tabs el-tab-pane(label="Info") .x-friend-list .x-friend-item .detail span.name Created span.extra {{ avatarDialog.ref.created_at | formatDate('YYYY-MM-DD HH24:MI:SS') || '-' }} .x-friend-item .detail span.name Last Updated span.extra {{ avatarDialog.fileCreatedAt | formatDate('YYYY-MM-DD HH24:MI:SS') || '-' }} .x-friend-item .detail span.name Version span.extra(v-text="avatarDialog.ref.version") .x-friend-item(style="width:100%") .detail span.name Platform span.extra(v-text="avatarDialogPlatform") el-tab-pane(label="JSON") el-button(type="default" @click="refreshAvatarDialogTreeData()" size="mini" icon="el-icon-refresh" circle) el-tree(:data="avatarDialog.treeData" style="margin-top:5px;font-size:12px") template(#default="scope") span span(v-text="scope.data.key" style="font-weight:bold;margin-right:5px") span(v-if="!scope.data.children" v-text="scope.data.value") //- dialog: favorite el-dialog.x-dialog(ref="favoriteDialog" :visible.sync="favoriteDialog.visible" title="Choose Group" width="250px") div(v-loading="favoriteDialog.loading") el-button(v-for="group in favoriteDialog.groups" :key="group.name" style="display:block;width:100%;margin:10px 0" @click="addFavorite(group)" :disabled="group.count >= group.capacity") {{ group.displayName }} ({{ group.count }} / {{ group.capacity }}) //- dialog: invite el-dialog.x-dialog(ref="inviteDialog" :visible.sync="inviteDialog.visible" title="Invite" width="450px") div(v-loading="inviteDialog.loading") location(:location="inviteDialog.worldId" :link="false") el-select(v-model="inviteDialog.userIds" multiple clearable placeholder="Choose Friends" filterable :disabled="inviteDialog.loading" style="width:100%;margin-top:15px") el-option-group(v-if="API.currentUser" label="ME") el-option.x-friend-item(:label="API.currentUser.displayName" :value="API.currentUser.id" style="height:auto") .avatar(:class="userStatusClass(API.currentUser)") img(v-if="API.currentUser.userIcon" v-lazy="API.currentUser.userIcon") img(v-else v-lazy="API.currentUser.currentAvatarThumbnailImageUrl") .detail span.name(v-text="API.currentUser.displayName") el-option-group(v-if="friendsGroup0.length" label="VIP") el-option.x-friend-item(v-for="friend in friendsGroup0" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar(:class="userStatusClass(friend.ref)") img(v-if="friend.ref.userIcon" v-lazy="friend.ref.userIcon") img(v-else v-lazy="friend.ref.currentAvatarThumbnailImageUrl") .detail span.name(v-text="friend.ref.displayName" :class="friend.ref.$trustClass") span(v-else v-text="friend.id") el-option-group(v-if="friendsGroup1.length" label="ONLINE") el-option.x-friend-item(v-for="friend in friendsGroup1" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar(:class="userStatusClass(friend.ref)") img(v-if="friend.ref.userIcon" v-lazy="friend.ref.userIcon") img(v-else v-lazy="friend.ref.currentAvatarThumbnailImageUrl") .detail span.name(v-text="friend.ref.displayName" :class="friend.ref.$trustClass") span(v-else v-text="friend.id") el-option-group(v-if="friendsGroup2.length" label="ACTIVE") el-option.x-friend-item(v-for="friend in friendsGroup2" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar img(v-if="friend.ref.userIcon" v-lazy="friend.ref.userIcon") img(v-else v-lazy="friend.ref.currentAvatarThumbnailImageUrl") .detail span.name(v-text="friend.ref.displayName" :class="friend.ref.$trustClass") span(v-else v-text="friend.id") template(#footer) el-button(type="primary" size="small" :disabled="inviteDialog.loading || !inviteDialog.userIds.length" @click="sendInvite()") Invite //- dialog: social status el-dialog.x-dialog(ref="socialStatusDialog" :visible.sync="socialStatusDialog.visible" title="Social Status" width="400px") div(v-loading="socialStatusDialog.loading") el-select(v-model="socialStatusDialog.status" style="dispaly:block") el-option(label="Online" value="active"). #[i.x-user-status.active] Online el-option(label="Join Me" value="join me"). #[i.x-user-status.joinme] Join Me el-option(label="Ask Me" value="ask me"). #[i.x-user-status.askme] Ask Me el-option(label="Do Not Disturb" value="busy"). #[i.x-user-status.busy] Do Not Disturb el-option(label="Offline" value="offline"). #[i.x-user-status.offline] Offline el-input(v-model="socialStatusDialog.statusDescription" placeholder="Status" style="dispaly:block;margin-top:10px") template(#footer) el-button(type="primary" size="small" :disabled="socialStatusDialog.loading" @click="saveSocialStatus") Update //- dialog: language el-dialog.x-dialog(ref="languageDialog" :visible.sync="languageDialog.visible" title="Language" width="400px") div(v-loading="languageDialog.loading") div(style="margin:5px 0") el-tag(v-for="item in API.currentUser.$languages" :key="item.key" size="small" type="info" effect="plain" closable @close="removeUserLanguage(item.key)" style="margin-right:5px") span.famfamfam-flags(:class="languageClass(item.key)" style="display:inline-block;margin-right:5px") | {{ item.value }} ({{ item.key }}) div(v-if="languageDialog.languageChoice === true") el-select(v-model="languageDialog.languageValue" size="mini") el-option(v-for="item in languageDialog.languages" :key="item.key" :value="item.key" :label="item.value") span.famfamfam-flags(:class="languageClass(item.key)" style="display:inline-block;margin-right:5px") | {{ item.value }} ({{ item.key }}) el-button(@click="languageDialog.languageChoice=false; addUserLanguage(languageDialog.languageValue)" size="mini") Ok el-button(@click="languageDialog.languageChoice=false" size="mini" style="margin-left:0") Cancel div(v-else) el-button(@click="languageDialog.languageValue='';languageDialog.languageChoice=true" size="mini") Add Language //- dialog: bio el-dialog.x-dialog(ref="bioDialog" :visible.sync="bioDialog.visible" title="Bio" width="400px") div(v-loading="bioDialog.loading") el-input(type="textarea" v-model="bioDialog.bio" size="mini" maxlength="512" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="Please input a bio") el-input(v-for="(link, index) in bioDialog.bioLinks" :key="index" :value="link" v-model="bioDialog.bioLinks[index]" size="small" style="margin-top:5px") img(slot="prepend" :src="getFaviconUrl(link)" style="width:16px;height:16px") el-button(slot="append" icon="el-icon-delete" @click="bioDialog.bioLinks.splice(index, 1)") el-button(@click="bioDialog.bioLinks.push('')" size="mini" style="margin-top:5px") Add Link template(#footer) el-button(type="primary" size="small" :disabled="bioDialog.loading" @click="saveBio") Update //- dialog: new instance el-dialog.x-dialog(ref="newInstanceDialog" :visible.sync="newInstanceDialog.visible" title="New Instance" width="600px") el-form(:model="newInstanceDialog" label-width="100px") el-form-item(label="Access Type") el-radio-group(v-model="newInstanceDialog.accessType" size="mini" @change="buildInstance") el-radio-button(label="public") el-radio-button(label="friends+") el-radio-button(label="friends") el-radio-button(label="invite+") el-radio-button(label="invite") el-form-item(label="World ID") el-input(v-model="newInstanceDialog.worldId" size="mini" @click.native="$event.target.tagName === 'INPUT' && $event.target.select()") el-form-item(label="Instance ID") el-input(v-model="newInstanceDialog.instanceId" size="mini" @click.native="$event.target.tagName === 'INPUT' && $event.target.select()") el-form-item(label="Location") el-input(v-model="newInstanceDialog.location" size="mini" readonly @click.native="$event.target.tagName === 'INPUT' && $event.target.select()") el-form-item(label="URL") el-input(ref="wtf" v-model="newInstanceDialog.url" size="mini" readonly @click.native="$event.target.tagName === 'INPUT' && $event.target.select()") template(#footer) el-button(size="small" @click="makeHome(newInstanceDialog.location)") Make Home el-button(size="small" @click="showInviteDialog(newInstanceDialog.location)") Invite el-button(type="primary" size="small" @click="showLaunchDialog(newInstanceDialog.location)") Launch //- dialog: launch options el-dialog.x-dialog(ref="launchOptionsDialog" :visible.sync="launchOptionsDialog.visible" title="Launch Options" width="400px") div(style='font-size:12px;') | These options are for advanced users only. #[br] | to change fps: --fps=<N> ex) #[el-tag(size="mini") --fps=144] el-input(type="textarea" v-model="launchOptionsDialog.arguments" size="mini" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="" style="margin-top:10px") template(#footer) div(style="display:flex") el-button(size="small" @click="openExternalLink('https://docs.vrchat.com/docs/launch-options')") VRChat Docs el-button(size="small" @click="openExternalLink('https://docs.unity3d.com/Manual/CommandLineArguments.html')") Unity Manual el-button(type="primary" size="small" :disabled="launchOptionsDialog.loading" @click="updateLaunchOptions" style="margin-left:auto") OK //- dialog: launch el-dialog.x-dialog(ref="launchDialog" :visible.sync="launchDialog.visible" title="Launch" width="400px") div #[span(v-text="launchDialog.url" style="word-break:break-all;font-size:12px")] template(#footer) el-checkbox(v-model="launchDialog.desktop" style="float:left;margin-top:5px") Start as Desktop (No VR) el-button(size="small" @click="showInviteDialog(launchDialog.location)") Invite el-button(type="primary" size="small" @click="launchGame(locationToLaunchArg(launchDialog.location))") Launch //- dialog: export friends list el-dialog.x-dialog(:visible.sync="exportFriendsListDialog" title="Export Friends List" width="650px") el-input(type="textarea" v-model="exportFriendsListContent" size="mini" rows="15" resize="none" readonly style="margin-top:15px" @click.native="$event.target.tagName === 'TEXTAREA' && $event.target.select()") //- dialog: Notification position el-dialog.x-dialog(ref="notificationPositionDialog" :visible.sync="notificationPositionDialog.visible" title="Notification Position" width="400px") div(style='font-size:12px;') | Choose a notification position. svg(version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 300 200" style="margin-top:15px;" xml:space="preserve") path(style="fill:black;" d="M291.89,5A3.11,3.11,0,0,1,295,8.11V160.64a3.11,3.11,0,0,1-3.11,3.11H8.11A3.11,3.11,0,0,1,5,160.64V8.11A3.11,3.11,0,0,1,8.11,5H291.89m0-5H8.11A8.11,8.11,0,0,0,0,8.11V160.64a8.11,8.11,0,0,0,8.11,8.11H291.89a8.11,8.11,0,0,0,8.11-8.11V8.11A8.11,8.11,0,0,0,291.89,0Z") rect(style="fill:#c4c4c4;" x="5" y="5" width="290" height="158.75" rx="2.5") el-radio-group(v-model="notificationPosition" size="mini" @change="changeNotificationPosition") el-radio(label="topLeft" v-model="notificationPosition" style="margin:0;position:absolute;left:35px;top:120px;") β€Ž el-radio(label="top" v-model="notificationPosition" style="margin:0;position:absolute;left:195px;top:120px;") β€Ž el-radio(label="topRight" v-model="notificationPosition" style="margin:0;position:absolute;right:25px;top:120px;") β€Ž el-radio(label="centerLeft" v-model="notificationPosition" style="margin:0;position:absolute;left:35px;top:200px;") β€Ž el-radio(label="topCenter" v-model="notificationPosition" style="margin:0;position:absolute;left:195px;top:200px;") β€Ž el-radio(label="centerRight" v-model="notificationPosition" style="margin:0;position:absolute;right:25px;top:200px;") β€Ž el-radio(label="bottomLeft" v-model="notificationPosition" style="margin:0;position:absolute;left:35px;top:280px;") β€Ž el-radio(label="bottom" v-model="notificationPosition" style="margin:0;position:absolute;left:195px;top:280px;") β€Ž el-radio(label="bottomRight" v-model="notificationPosition" style="margin:0;position:absolute;right:25px;top:280px;") β€Ž template(#footer) div(style="display:flex") el-button(type="primary" size="small" style="margin-left:auto" @click="notificationPositionDialog.visible = false") OK //- dialog: open source software notice el-dialog.x-dialog(:visible.sync="ossDialog" title="Open Source Software Notice" width="650px") div(style="height:350px;overflow:hidden scroll;word-break:break-all") div span VRCX is based on open source software. It was possible because of their contribution. div(style="margin-top:15px") p(style="font-weight:bold") animate.css pre(style="font-size:12px;white-space:pre-line"). The MIT License (MIT) Copyright (c) 2019 Daniel Eden Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. div(style="margin-top:15px") p(style="font-weight:bold") CefSharp pre(style="font-size:12px;white-space:pre-line"). // Copyright Β© The CefSharp Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // // * Neither the name of Google Inc. nor the name Chromium Embedded // Framework nor the name CefSharp nor the names of its contributors // may be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. div(style="margin-top:15px") p(style="font-weight:bold") DiscordRichPresence pre(style="font-size:12px;white-space:pre-line"). MIT License Copyright (c) 2018 Lachee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. div(style="margin-top:15px") p(style="font-weight:bold") element pre(style="font-size:12px;white-space:pre-line"). The MIT License (MIT) Copyright (c) 2016-present ElemeFE Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. div(style="margin-top:15px") p(style="font-weight:bold") Newtonsoft.Json pre(style="font-size:12px;white-space:pre-line"). The MIT License (MIT) Copyright (c) 2007 James Newton-King Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. div(style="margin-top:15px") p(style="font-weight:bold") normalize pre(style="font-size:12px;white-space:pre-line"). The MIT License (MIT) Copyright Β© Nicolas Gallagher and Jonathan Neal Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. div(style="margin-top:15px") p(style="font-weight:bold") noty pre(style="font-size:12px;white-space:pre-line"). Copyright (c) 2012 Nedim ArabacΔ± Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. div(style="margin-top:15px") p(style="font-weight:bold") OpenVR SDK pre(style="font-size:12px;white-space:pre-line"). Copyright (c) 2015, Valve Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. div(style="margin-top:15px") p(style="font-weight:bold") SharpDX pre(style="font-size:12px;white-space:pre-line"). Copyright (c) 2010-2014 SharpDX - Alexandre Mutel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. div(style="margin-top:15px") p(style="font-weight:bold") vue pre(style="font-size:12px;white-space:pre-line"). The MIT License (MIT) Copyright (c) 2013-present, Yuxi (Evan) You Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. div(style="margin-top:15px") p(style="font-weight:bold") vue-data-tables pre(style="font-size:12px;white-space:pre-line"). The MIT License (MIT) Copyright (c) 2018 Leon Zhang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. div(style="margin-top:15px") p(style="font-weight:bold") vue-lazyload pre(style="font-size:12px;white-space:pre-line"). The MIT License (MIT) Copyright (c) 2016 Awe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. script(src="app.js")