-
+
}
{ markNotificationRead }
{(promo_posts && promo_posts.size) ?
select {
border: none;
border-bottom: 1px solid $medium-gray;
@@ -68,17 +72,9 @@
color: gray;
}
-/* Small only */
-@media screen and (max-width: 39.9375em) {
- .PostsIndex__left {
- padding: 0;
- }
- .PostsIndex__topics_compact {
- padding: 0 0.5rem;
- float: none;
- width: auto;
- margin-top: 1.5rem;
- }
+/* hideOrders */
+.PostsIndex__left.ho {
+ padding: 0;
}
/* Medium and up */
diff --git a/app/components/pages/Search.jsx b/app/components/pages/Search.jsx
index 6826a754a..8bf6b1bc6 100644
--- a/app/components/pages/Search.jsx
+++ b/app/components/pages/Search.jsx
@@ -3,11 +3,7 @@ import golos from 'golos-lib-js';
import { Link } from 'react-router';
import { browserHistory } from 'react-router';
import tt from 'counterpart';
-import Icon from 'app/components/elements/Icon';
-import TimeAgoWrapper from 'app/components/elements/TimeAgoWrapper';
-import remarkableStripper from 'app/utils/RemarkableStripper';
import sanitize from 'sanitize-html';
-import { detransliterate } from 'app/utils/ParsersAndFormatters';
import truncate from 'lodash/truncate';
import Pagination from 'rc-pagination';
import localeEn from 'rc-pagination/lib/locale/en_US';
@@ -16,6 +12,13 @@ if (typeof(document) !== 'undefined') require('rc-pagination/assets/index.css');
let Multiselect;
if (typeof(document) !== 'undefined') Multiselect = require('multiselect-react-dropdown').Multiselect;
+import Icon from 'app/components/elements/Icon';
+import TimeAgoWrapper from 'app/components/elements/TimeAgoWrapper';
+import remarkableStripper from 'app/utils/RemarkableStripper';
+import { detransliterate } from 'app/utils/ParsersAndFormatters';
+import { hrefClick } from 'app/utils/app/RoutingUtils'
+import { withScreenSize } from 'app/utils/ScreenSize'
+
class Search extends React.Component {
constructor(props) {
super(props);
@@ -273,7 +276,95 @@ class Search extends React.Component {
});
};
+ _renderWhereButton = () => {
+ const { isS } = this.props
+
+ let button =
+
+
+
+
+
+ if (isS) {
+ return
+ {button}
+
+ }
+
+ return button
+ }
+
+ _renderSettings = () => {
+ const { isS } = this.props
+
+ const dateFrom =
+ const dateSep = —
+ const dateTo =
+ const sep =
+ const dateAll = (this.state.dateFrom || this.state.dateTo) &&
+
+
+
+ const selAuthor = Multiselect &&
+ const selTags = Multiselect &&
+ let sel =
+ {selAuthor}
+ {sep}
+ {isS ? sep : null}
+ {selTags}
+
+ if (isS) {
+ sel =
+ {sel}
+
+ }
+
+ return
+ {dateFrom}
+ {dateSep}
+ {dateTo}
+ {isS ? null : sep}
+ {dateAll}
+ {isS ? null : sep}
+ {sel}
+
+ }
+
render() {
+ const { isS } = this.props
+ let wordWrap
+ if (isS) {
+ wordWrap = 'break-word'
+ }
let results = [];
let totalPosts = 0;
let display = null;
@@ -307,13 +398,13 @@ class Search extends React.Component {
body = sanitize(body, {allowedTags: ['em', 'img']});
return (
-
+
— @
{hit.fields.author[0]}
-
+
);
});
@@ -343,56 +434,14 @@ class Search extends React.Component {
/>
);
}
+
return (
-
+ {isS ? null :
}
-
-
-
-
-
-
- —
-
-
- {(this.state.dateFrom || this.state.dateTo) ?
-
- : null}
-
- {Multiselect ? : null}
-
- {Multiselect ? : null}
+ {this._renderWhereButton()}
+ {this._renderSettings()}
{display}
@@ -410,5 +459,5 @@ class Search extends React.Component {
module.exports = {
path: '/search(/:query)',
- component: Search
+ component: withScreenSize(Search)
};
diff --git a/app/components/pages/Search.scss b/app/components/pages/Search.scss
index b42b95662..2be46fbc1 100644
--- a/app/components/pages/Search.scss
+++ b/app/components/pages/Search.scss
@@ -72,6 +72,9 @@
.esearch-settings input {
width: 150px;
}
+ .esearch-settings input.searchBox {
+ width: 140px;
+ }
.another-search {
font-size: 1.3em;
}
diff --git a/app/components/pages/UserProfile.jsx b/app/components/pages/UserProfile.jsx
index 2140d8562..0e0191218 100644
--- a/app/components/pages/UserProfile.jsx
+++ b/app/components/pages/UserProfile.jsx
@@ -38,6 +38,7 @@ import TimeAgoWrapper from 'app/components/elements/TimeAgoWrapper';
import Userpic from 'app/components/elements/Userpic';
import Callout from 'app/components/elements/Callout';
import normalizeProfile, { getLastSeen } from 'app/utils/NormalizeProfile';
+import { withScreenSize } from 'app/utils/ScreenSize'
export default class UserProfile extends React.Component {
constructor(props) {
@@ -79,7 +80,11 @@ export default class UserProfile extends React.Component {
np.location.pathname !== this.props.location.pathname ||
np.routeParams.accountname !== this.props.routeParams.accountname ||
np.follow_count !== this.props.follow_count ||
- ns.repLoading !== this.state.repLoading
+ ns.repLoading !== this.state.repLoading ||
+ np.hideMainMe !== this.props.hideMainMe ||
+ np.hideMainFor !== this.props.hideMainFor ||
+ np.hideRewardsMe !== this.props.hideRewardsMe ||
+ np.hideRewardsFor !== this.props.hideRewardsFor
)
}
@@ -153,8 +158,9 @@ export default class UserProfile extends React.Component {
render() {
const {
- props: {current_user, current_account, wifShown, global_status, follow},
- onPrint
+ props: {current_user, current_account, wifShown, global_status, follow,
+ hideMainMe, hideRewardsMe, hideMainFor, hideRewardsFor,},
+ onPrint,
} = this;
let { accountname, section, id, action } = this.props.routeParams;
// normalize account from cased params
@@ -428,6 +434,56 @@ export default class UserProfile extends React.Component {
accountjoin = transferFromSteemToGolosDate;
}
+ const hideMain = isMyAccount ? hideMainMe : hideMainFor
+ const hideRewards = isMyAccount ? hideRewardsMe : hideRewardsFor
+ let mentionCounter = isMyAccount &&
+ let disCounter = isMyAccount &&
+ let walletCounter = isMyAccount &&
+
+ let kebab
+ let kebabNotify = ''
+ if (hideMain) {
+ let kebabMenu = [
+ { link: `/@${accountname}/mentions`, label: tt('g.mentions'), value: tt('g.mentions'), addon: mentionCounter }
+ ]
+ if (isMyAccount) {
+ kebabMenu.unshift({ link: `/@${accountname}/discussions`, label: tt('g.discussions'), value: tt('g.discussions'), addon: disCounter })
+ kebabMenu.push({ value: '-' })
+ kebabMenu.push({ link: `/@${accountname}/settings`, label: tt('g.settings'), value: tt('g.settings') })
+ kebabNotify += ',mention,subscriptions'
+ }
+ if (hideRewards) {
+ kebabMenu = [
+ ...rewardsMenu,
+ { value: '-' },
+ ...kebabMenu,
+ ]
+ kebabNotify += ',donate,donate_msgs'
+ }
+ kebabMenu = [
+ { link: walletUrl(`/@${accountname}/transfers`), target: walletTarget(), label: tt('g.wallet'), value: tt('g.wallet'), addon: walletCounter },
+ { value: '-' },
+ ...kebabMenu,
+ ]
+ kebabNotify += ',send,receive,fill_order,nft_receive,nft_token_sold,nft_buy_offer'
+
+ if (kebabMenu.length) {
+ if (kebabMenu[kebabMenu.length - 1].value === '-') kebabMenu.pop()
+ }
+ if (kebabNotify[0] === ',') kebabNotify = kebabNotify.slice(1)
+ kebab = kebabMenu.length ?
}
+ >
+
+
+ {(isMyAccount && kebabNotify) ? : null}
+
+ : null
+ }
+
const top_menu =
@@ -440,18 +496,18 @@ export default class UserProfile extends React.Component {
{tt('g.replies')} {isMyAccount &&
}
- {isMyAccount ?
- {tt('g.discussions')}
+ {(!hideMain && isMyAccount) ?
+ {tt('g.discussions')} {disCounter}
: null}
-
- {tt('g.mentions')} {isMyAccount &&
}
-
+ {!hideMain &&
+ {tt('g.mentions')} {mentionCounter}
+ }
-
- {tt('g.wallet')} {isMyAccount && }
-
-
+ {tt('g.wallet')} {walletCounter}
+ }
+ {!hideRewards && }
-
+ }
{isMyAccount && msgsHost() ?
: null}
- {isMyAccount ?
+ {(isMyAccount && !hideMain) ?
: null}
+ {kebab}
@@ -641,5 +698,5 @@ module.exports = {
},
requestData: (args) => dispatch({type: 'REQUEST_DATA', payload: args}),
})
- )(UserProfile)
+ )(withScreenSize(UserProfile))
};
diff --git a/app/components/pages/UserProfile.scss b/app/components/pages/UserProfile.scss
index 380b90232..3277e27d5 100644
--- a/app/components/pages/UserProfile.scss
+++ b/app/components/pages/UserProfile.scss
@@ -306,7 +306,7 @@
}
}
-@media screen and (max-width: 400px) {
+@media screen and (max-width: 330px) {
.UserProfile {
&__filler {
display: none;
diff --git a/app/components/pages/app/AppSettings.jsx b/app/components/pages/app/AppSettings.jsx
index cb6bd2f25..a41bf3e83 100644
--- a/app/components/pages/app/AppSettings.jsx
+++ b/app/components/pages/app/AppSettings.jsx
@@ -2,6 +2,8 @@ import React from 'react'
import tt from 'counterpart'
import { Formik, Field } from 'formik'
+import Icon from 'app/components/elements/Icon'
+
class AppSettings extends React.Component {
_onSubmit = (data) => {
let cfg = { ...$STM_Config }
@@ -22,12 +24,25 @@ class AppSettings extends React.Component {
cfg.images.use_img_proxy = data.use_img_proxy
cfg.auth_service.host = data.auth_service
cfg.notify_service.host = data.notify_service
+ cfg.notify_service.host_ws = data.notify_service_ws
cfg.elastic_search.url = data.elastic_search
- cfg.main_app = data.main_app
+ if (process.env.MOBILE_APP) {
+ cfg = JSON.stringify(cfg)
+ localStorage.setItem('app_settings', cfg)
+ window.location.href = '/'
+ return
+ } else {
+ cfg.main_app = data.main_app
+ }
window.appSettings.save(cfg)
}
- _onClose = () => {
+ _onClose = (e) => {
+ e.preventDefault()
+ if (process.env.MOBILE_APP) {
+ window.location.href = '/'
+ return
+ }
window.close()
}
@@ -38,6 +53,7 @@ class AppSettings extends React.Component {
use_img_proxy: $STM_Config.images.use_img_proxy,
auth_service: $STM_Config.auth_service.host,
notify_service: $STM_Config.notify_service.host,
+ notify_service_ws: $STM_Config.notify_service.host_ws || '',
elastic_search: $STM_Config.elastic_search.url,
main_app: $STM_Config.main_app,
}
@@ -49,6 +65,17 @@ class AppSettings extends React.Component {
this.makeInitialValues()
}
+ showLogs = (e) => {
+ e.preventDefault()
+ NativeLogs.getLog(
+ 200,
+ false,
+ logs => {
+ alert(logs)
+ }
+ )
+ }
+
_renderNodes(ws_connection_client) {
let fields = []
for (let i in $STM_Config.ws_connection_app) {
@@ -85,8 +112,14 @@ class AppSettings extends React.Component {
}
render() {
+ const { MOBILE_APP } = process.env
return
-
{tt('g.settings')}
+
+ {MOBILE_APP ?
+
+ : null}
+ {MOBILE_APP ? tt('app_settings.mobile_title') : tt('g.settings')}
+
{tt('app_settings.to_save_click_button')}
@@ -150,6 +183,17 @@ class AppSettings extends React.Component {
+
+
+ {tt('app_settings.notify_service_ws')}
+
+
+
+
+
{tt('app_settings.elastic_search')}
@@ -161,7 +205,7 @@ class AppSettings extends React.Component {
-
+ {MOBILE_APP ? null :
{tt('app_settings.main_app')}
@@ -174,16 +218,19 @@ class AppSettings extends React.Component {
-
+
}
-
}
+ {MOBILE_APP ?
+ {tt('app_settings.logs')}
+ : null}
@@ -197,3 +244,15 @@ module.exports = {
path: '/__app_settings',
component: AppSettings,
}
+
+module.exports.openAppSettings = function() {
+ if (!process.env.MOBILE_APP) {
+ window.location.href = '/__app_settings'
+ return
+ }
+ const { pathname } = window.location
+ window.location.href = '/#app-settings'
+ if (pathname === '/' && window.appMounted) {
+ window.location.reload()
+ }
+}
diff --git a/app/locales/en.json b/app/locales/en.json
index 3dd088df0..68b6dbca7 100644
--- a/app/locales/en.json
+++ b/app/locales/en.json
@@ -69,6 +69,7 @@
"age": "age",
"approximately": "approximately",
"all_langs": "All languages",
+ "all_posts": "All posts",
"amount": "Amount",
"and": "and",
"at_least": "at least",
@@ -214,7 +215,7 @@
"tag": "Tag",
"team": "Team",
"to": " to ",
- "topics": "Topics",
+ "topics": "Categories",
"transaction_history": "Transaction History",
"transfer": "Transfer ",
"transfer2": "Transfer",
@@ -306,7 +307,7 @@
"show_more_low_value_posts": "Show more low value posts",
"select_topic": "Select Topic",
"tags_filter": "Filter",
- "no_tags_selected": "No tags selected",
+ "no_tags_selected": "no categories selected",
"filter": "Filter",
"show_more_topics": "Go to tag rating",
"personal_info_will_be_private": "Your personal information will be kept",
@@ -466,6 +467,7 @@
"tag_your_story": "Tag (up to 5 tags), the first tag is your main category.",
"select_a_tag": "Select tag",
"select_a_category": "Select category",
+ "select_a_category2": "Category",
"maximum_tag_length_is_24_characters": "Maximum tag length is 24 characters",
"use_only_lowercase_letters": "Use only lowercase letters",
"use_one_dash": "Use only one dash",
@@ -859,12 +861,18 @@
"choose_preset_tips": "Choose the amounts for the reward buttons",
"emission_donate_pct": "Donation percent of your daily token emission",
"notifications_settings": "Notification settings",
+ "notifications_settings2": "Notification settings",
"notifications_transfer": "Transfer notifications",
"notifications_donate": "Donate notifications",
"notifications_reply": "Reply notifications",
"notifications_mention": "Mention notifications",
"notifications_message": "Private message notifications",
"notifications_order": "Market order filled",
+ "notifications_bg": "Show notifications in background",
+ "notifications_bg_title": "Show notification when app hidden, screen is off",
+ "app_settings": "App Settings",
+ "advanced_settings": "Select the blockchain node, and another advanced settings...",
+ "open": "Open",
"invalid_url": "Invalid URL",
"name_is_too_long": "Name is too long",
"name_must_not_begin_with": "Name must not begin with @",
@@ -1156,21 +1164,30 @@
"mention_comment": " mentioned you in their comment",
"message": " sent you a private message"
},
+ "login_app_reminder": {
+ "or_download_for": "...or download for ",
+ "title": "Click to download for "
+ },
"app_download": {
- "title": "Download Golos Desktop"
+ "title": "Download Golos Desktop",
+ "download_for": "Download for",
+ "mobile": "Download Golos Blogs for"
},
"app_reminder": {
- "text": "Install desktop application for Windows or Linux to receive data directly from blockchain"
+ "text": "Install desktop application for Windows, Linux, Android",
+ "text2": "to receive data directly from blockchain"
},
"app_goto_url": {
"goto": "Goto",
"wrong_domain_DOMAINS": "This address is not belong to GOLOS Blogs.\nGOLOS Blogs domains are: %(DOMAINS)s\nThis address will be opened in external browser."
},
"app_settings": {
+ "mobile_title": "Settings of Blogs",
"ws_connection_client": "GOLOS node URL",
"img_proxy_prefix": "Use Proxy For Images",
"auth_service": "Golos Auth & Registration Service (for notifications)",
"notify_service": "Golos Notify Service (for notifications)",
+ "notify_service_ws": "Golos Notify Service WebSocket (for notifications)",
"messenger_service": "Messenger",
"elastic_search": "Search",
"main_app": "When start app, open:",
@@ -1179,7 +1196,10 @@
"save_and_restart": "Save and restart",
"cancel": "Cancel",
"node_error_NODE": "Не удалось подключиться к ноде %(NODE)s. Возможно, это проблемы с интернетом. Или попробуйте задать другую ноду GOLOS в меню Настройки.",
- "to_save_click_button": "To save settings, click \"Save and restart\" button at bottom of the window."
+ "node_error_new_NODE": "Не удалось подключиться к ноде %(NODE)s. Возможно, это проблемы с интернетом (или с нодой).",
+ "node_error_new_NODE2": "Выбрать другую ноду",
+ "to_save_click_button": "To save settings, click \"Save and restart\" button at bottom of the window.",
+ "logs": "Logs"
},
"app_update": {
"notify_VERSION": "Доступна новая версия GOLOS Блогов - %(VERSION)s",
diff --git a/app/locales/ru-RU.json b/app/locales/ru-RU.json
index 6acf3262e..5198765c6 100644
--- a/app/locales/ru-RU.json
+++ b/app/locales/ru-RU.json
@@ -15,6 +15,7 @@
"tag_your_story": "Добавьте тэги, первый станет категорией.",
"select_a_tag": "Выбрать тэг",
"select_a_category": "Выберите категорию",
+ "select_a_category2": "Категория",
"maximum_tag_length_is_24_characters": "Максимальная длина категории 24 знака",
"use_only_lowercase_letters": "Используйте только символы нижнего регистра",
"use_one_dash": "Используйте только одно тире",
@@ -129,6 +130,7 @@
"active": "Активный ключ",
"advanced": "Расширенные опции",
"all_langs": "Показать всё",
+ "all_posts": "Все посты",
"amount": "Количество",
"and": "и",
"are_you_sure": "Вы уверены?",
@@ -277,7 +279,7 @@
"tag": "Тэг",
"team": "Команда",
"to": " к ",
- "topics": "Темы",
+ "topics": "Категории",
"transaction_history": "История транзакций",
"transfer": "Передать ",
"transfer2": "Перевод",
@@ -721,12 +723,18 @@
"choose_preset_tips": "Выберите суммы для кнопок вознаграждений",
"emission_donate_pct": "Процент от вашей суточной эмиссии токенов для вознаграждения",
"notifications_settings": "Настройки уведомлений на сайте",
+ "notifications_settings2": "Настройки уведомлений",
"notifications_transfer": "Перевод средств",
"notifications_donate": "Вознаграждения (донаты)",
"notifications_reply": "Ответ на комментарий или пост",
"notifications_mention": "Упоминание @ника в посте или комментарии",
"notifications_message": "Новое сообщение",
"notifications_order": "Сработал ордер на бирже",
+ "notifications_bg": "Показывать уведомления в фоне",
+ "notifications_bg_title": "Показывать ли уведомления при свернутом приложении, выключенном экране",
+ "app_settings": "Настройки приложения",
+ "advanced_settings": "Выбор ноды и другие расширенные настройки...",
+ "open": "Открыть",
"invalid_url": "Недопустимый URL-адрес",
"invalid_ws": "wss://api-full.golos.id/ws",
"invalid_ip_port": "Пример: 120.16.10.18:2001",
@@ -1222,22 +1230,30 @@
"mention_comment": " упомянул вас в комментарии",
"message": " написал вам сообщение"
},
+ "login_app_reminder": {
+ "or_download_for": "...или скачайте для ",
+ "title": "Нажмите, чтобы скачать для "
+ },
"app_download": {
"title": "Скачать Golos Desktop",
- "download_for": "Скачать для"
+ "download_for": "Скачать для",
+ "mobile": "Скачать Golos Блоги для"
},
"app_reminder": {
- "text": "Установите десктоп-приложение для Windows или Linux и получайте информацию напрямую с блокчейна"
+ "text": "Установите приложение для Windows, Linux, Android",
+ "text2": "и получайте информацию напрямую с блокчейна"
},
"app_goto_url": {
"goto": "Перейти",
"wrong_domain_DOMAINS": "Похоже, эта ссылка не с GOLOS Блогов.\nДомены GOLOS Блогов: %(DOMAINS)s\nЭта ссылка будет открыта во внешнем браузере."
},
"app_settings": {
+ "mobile_title": "Настройки Блогов",
"ws_connection_client": "Адрес ноды GOLOS",
"img_proxy_prefix": "Использовать прокси для изображений",
"auth_service": "Golos Auth & Registration Service (для уведомлений)",
"notify_service": "Golos Notify Service (для уведомлений)",
+ "notify_service_ws": "Golos Notify Service WebSocket (для уведомлений)",
"messenger_service": "Мессенджер",
"elastic_search": "Поиск",
"main_app": "При запуске открывать:",
@@ -1246,7 +1262,10 @@
"save_and_restart": "Сохранить и перезапустить",
"cancel": "Отмена",
"node_error_NODE": "Не удалось подключиться к ноде %(NODE)s. Возможно, это проблемы с интернетом. Или попробуйте задать другую ноду GOLOS в меню Настройки.",
- "to_save_click_button": "Чтобы сохранить настройки, нажмите кнопку \"Сохранить и перезапустить\" внизу окна."
+ "node_error_new_NODE": "Не удалось подключиться к ноде %(NODE)s. Возможно, это проблемы с интернетом (или с нодой).",
+ "node_error_new_NODE2": "Выбрать другую ноду",
+ "to_save_click_button": "Чтобы сохранить настройки, нажмите кнопку \"Сохранить и перезапустить\" внизу окна.",
+ "logs": "Логи"
},
"app_update": {
"notify_VERSION": "Доступна новая версия GOLOS Блогов - %(VERSION)s",
diff --git a/app/redux/User.js b/app/redux/User.js
index d39cb1f09..a25e92497 100644
--- a/app/redux/User.js
+++ b/app/redux/User.js
@@ -133,7 +133,8 @@ export default createModule({
},
{
action: 'LOGIN_ERROR',
- reducer: (state, {payload: {error}}) => state.merge({ login_error: error, logged_out: undefined })
+ reducer: (state, {payload: {error, ...rest}}) => state.merge({ login_error: { error, ...rest },
+ logged_out: undefined })
},
{
action: 'LOGOUT',
diff --git a/app/redux/UserSaga.js b/app/redux/UserSaga.js
index 870c10b7c..ab7ab6e38 100644
--- a/app/redux/UserSaga.js
+++ b/app/redux/UserSaga.js
@@ -12,7 +12,7 @@ import { fetchState } from 'app/redux/FetchDataSaga'
import {loadFollows} from 'app/redux/FollowSaga'
import { signData } from 'golos-lib-js/lib/auth'
import {PrivateKey, Signature, hash} from 'golos-lib-js/lib/auth/ecc'
-import {api} from 'golos-lib-js'
+import {api, config} from 'golos-lib-js'
import g from 'app/redux/GlobalReducer'
import React from 'react';
import PushNotificationSaga from 'app/redux/services/PushNotificationSaga';
@@ -170,7 +170,14 @@ function* usernamePasswordLogin2({payload: {username, password, saveLogin,
const isRole = (role, fn) => (!userProvidedRole || role === userProvidedRole ? fn() : undefined)
- let account = yield call(getAccount, username)
+ let account
+ try {
+ account = yield call(getAccount, username)
+ } catch (err) {
+ console.error(err)
+ yield put(user.actions.loginError({ error: 'Node failure', node: config.get('websocket') }))
+ return
+ }
if (!account) {
yield put(user.actions.loginError({ error: 'Username does not exist' }))
return
diff --git a/app/redux/UserSaga_UploadImage.js b/app/redux/UserSaga_UploadImage.js
index 5e38af67d..654ba7ee0 100644
--- a/app/redux/UserSaga_UploadImage.js
+++ b/app/redux/UserSaga_UploadImage.js
@@ -55,7 +55,7 @@ function* uploadImage(action) {
let data, dataBase64;
if (file) {
- const reader = new FileReader();
+ const reader = new (window.FileReader0 || FileReader)();
data = yield new Promise(resolve => {
reader.addEventListener('load', () => {
@@ -148,12 +148,33 @@ function* uploadImage(action) {
const xhr = new XMLHttpRequest();
+ let tm
+ let connected
+ const clearTm = () => {
+ if (tm) clearTimeout(tm)
+ }
+ const resetTm = () => {
+ clearTm()
+ tm = setTimeout(() => {
+ onError(tt('user_saga_js.image_upload.error.upload_failed'))
+ xhr.abort()
+ }, connected ? 10000 : 5000)
+ }
+ resetTm()
+
xhr.open('POST', postUrl);
if (!golosImages) {
xhr.setRequestHeader('Authorization', 'Client-ID ' + $STM_Config.images.client_id)
}
+ xhr.onloadstart = function () {
+ connected = true
+ resetTm()
+ }
+
xhr.onload = async function() {
+ clearTm()
+
let data;
try {
@@ -230,11 +251,13 @@ function* uploadImage(action) {
};
xhr.onerror = function(error) {
+ clearTm()
onError(tt('user_saga_js.image_upload.error.server_unavailable'));
console.error(error);
};
xhr.upload.onprogress = function(event) {
+ resetTm()
if (event.lengthComputable) {
const percent = Math.round((event.loaded / event.total) * 100);
diff --git a/app/redux/services/PushNotificationSaga.js b/app/redux/services/PushNotificationSaga.js
index aa4db98da..ae164fc73 100644
--- a/app/redux/services/PushNotificationSaga.js
+++ b/app/redux/services/PushNotificationSaga.js
@@ -27,11 +27,26 @@ function getScopePresets(username) {
if (presets.donate) {
presets.donate_msgs = true
}
- return Object.keys(presets).filter(k => presets[k]);
+
+ let bgPresets = []
+ if (process.env.MOBILE_APP) {
+ const forApp = ['comment_reply', 'mention']
+ for (const p of forApp) {
+ if (presets[p]) bgPresets.push(p)
+ }
+ if (presets.in_background === undefined) {
+ presets.in_background = true
+ }
+ }
+ const inBackground = presets.in_background
+ delete presets.in_background
+ return { presets: Object.keys(presets).filter(k => presets[k]),
+ bgPresets,
+ inBackground }
}
export function* onUserLogin(action) {
- let presets = getScopePresets(action.username).join(',');
+ let presets = getScopePresets(action.username).presets.join(',');
if (!presets) {
console.log('GNS: all scopes disabled, so will not subscribe');
@@ -72,7 +87,7 @@ export function* onUserLogin(action) {
removeTaskIds = yield notificationTake(action.username, removeTaskIds,
(type, op, timestamp, id, scope) => {
if (op._offchain) return;
- if (!getScopePresets(action.username).includes(scope)) {
+ if (!getScopePresets(action.username).presets.includes(scope)) {
return;
}
if (scope === 'message') {
@@ -130,4 +145,5 @@ export function* pushNotificationWatches() {
export default {
onUserLogin,
pushNotificationWatches,
+ getScopePresets,
}
diff --git a/app/renderApp.js b/app/renderApp.js
index 43adae76d..e05e5e9ae 100644
--- a/app/renderApp.js
+++ b/app/renderApp.js
@@ -34,6 +34,9 @@ export default async function renderApp(initialState) {
clientRender(initialState)
} catch (error) {
console.error(error)
+ if (process.env.MOBILE_APP) {
+ alert('renderApp ' + error.toString() + '\n' + JSON.stringify(error.stack))
+ }
serverApiRecordEvent('client_error', error)
}
}
\ No newline at end of file
diff --git a/app/utils/ScreenSize.jsx b/app/utils/ScreenSize.jsx
new file mode 100644
index 000000000..926743958
--- /dev/null
+++ b/app/utils/ScreenSize.jsx
@@ -0,0 +1,75 @@
+import React from 'react'
+
+const isScreenS = () => {
+ const res = window.matchMedia('screen and (max-width: 39.9375em)').matches
+ return res
+}
+
+const shortQuestion = '63.9375em'
+const hideOrders = '710px'
+const hideOrdersMe = '768px'
+
+const hideMainMe = '800px'
+const hideRewardsMe = '440px'
+
+const hideMainFor = '560px'
+const hideRewardsFor = '440px'
+
+const isSmaller = (val) => {
+ const res = window.matchMedia('screen and (max-width: ' + val + ')').matches
+ return res
+}
+
+export const withScreenSize = (WrappedComponent) => {
+ class ScreenSize extends React.Component {
+ state = {}
+
+ componentDidMount() {
+ if (!process.env.BROWSER) return
+ this.updateSize()
+ window.addEventListener('resize', this.onResize)
+ }
+
+ componentWillUnmount() {
+ if (!process.env.BROWSER) return
+ window.removeEventListener('resize', this.onResize)
+ }
+
+ onResize = () => {
+ this.updateSize()
+ }
+
+ updateSize = () => {
+ this.setState({
+ _isSmall: isScreenS(),
+ _shortQuestion: isSmaller(shortQuestion),
+ _hideOrders: isSmaller(hideOrders),
+ _hideOrdersMe: isSmaller(hideOrdersMe),
+ _hideMainMe: isSmaller(hideMainMe),
+ _hideRewardsMe: isSmaller(hideRewardsMe),
+ _hideMainFor: isSmaller(hideMainFor),
+ _hideRewardsFor: isSmaller(hideRewardsFor),
+ })
+ }
+
+ render() {
+ const { _shortQuestion, _hideOrders, _hideOrdersMe,
+ _hideMainMe, _hideRewardsMe, _hideMainFor, _hideRewardsFor, } = this.state
+ return (
+
+ )
+ }
+ }
+
+ return ScreenSize
+}
diff --git a/app/utils/app/RoutingUtils.js b/app/utils/app/RoutingUtils.js
new file mode 100644
index 000000000..dfd93da2f
--- /dev/null
+++ b/app/utils/app/RoutingUtils.js
@@ -0,0 +1,65 @@
+import { browserHistory, } from 'react-router'
+
+export function reloadLocation(href) {
+ if (href && href[0] === '#') {
+ throw new Error('reloadLocation cannot reload with href starts with #')
+ }
+ const { MOBILE_APP } = process.env
+ if (MOBILE_APP) {
+ let { pathname, hash, host } = window.location
+ if (href) {
+ if (href.startsWith('http:') || href.startsWith('https:')) {
+ const url = new URL(href)
+ if (url.host !== host) {
+ window.open(href, '_blank')
+ // And just opening in same tab - not working, somewhy opens with app's hostname...
+ return
+ }
+ href = url.pathname + url.search + url.hash
+ }
+ if (href[0] !== '/') {
+ href = '/' + href
+ }
+ } else {
+ href = pathname || '/'
+ }
+ window.location.href = '/#' + href
+ if (!pathname || pathname === '/') {
+ window.location.reload()
+ }
+ return
+ }
+ window.location.href = href
+}
+
+export function hrefClick(e) {
+ if (process.env.MOBILE_APP) {
+ let node, href, target
+ do {
+ node = node ? node.parentNode : e.target
+ if (!node) break
+ href = node.href
+ target = node.target
+ } while (!href)
+ if (!href) return
+ e.preventDefault()
+ reloadLocation(href)
+ }
+}
+
+//... and this processes such reloads:
+
+export function fixRouteIfApp() {
+ const { MOBILE_APP } = process.env
+ if (!MOBILE_APP) {
+ return true
+ }
+ let hash = window.location.hash
+ if (hash && hash[1] === '/') {
+ hash = hash.slice(1)
+ if (!hash) hash = '/'
+ browserHistory.push(hash)
+ return false
+ }
+ return true
+}
diff --git a/app/utils/app/ShortcutUtils.js b/app/utils/app/ShortcutUtils.js
new file mode 100644
index 000000000..35c3b524a
--- /dev/null
+++ b/app/utils/app/ShortcutUtils.js
@@ -0,0 +1,84 @@
+
+async function getShorcuts() {
+ let i = 0
+ for (let i = 0; i < 5; ++i) {
+ if (!window.plugins || !window.plugins.Shortcuts) {
+ await new Promise(resolve => setTimeout(resolve, 50))
+ continue
+ }
+ const { Shortcuts } = window.plugins
+ return Shortcuts
+ }
+ return null
+}
+
+async function dynShortcutsSupported() {
+ const Shortcuts = await getShorcuts()
+ return await new Promise(async (resolve, reject) => {
+ Shortcuts.supportsDynamic((supported) => {
+ resolve(supported)
+ }, (err) => {
+ reject(err)
+ })
+ })
+}
+
+async function setDynShortcut(shortcut) {
+ const Shortcuts = await getShorcuts()
+ await new Promise(async (resolve, reject) => {
+ Shortcuts.setDynamic([shortcut], () => {
+ resolve()
+ }, (err) => {
+ reject(err)
+ })
+ })
+}
+
+export async function addShortcut({ id, shortLabel, longLabel, hash }) {
+ try {
+ let shortcutSupport = await dynShortcutsSupported()
+ if (!shortcutSupport) {
+ console.error('Cannot add shortcut - not supported')
+ return
+ }
+ let shortcut = {
+ id,
+ shortLabel,
+ longLabel,
+ iconFromResource: 'blg_setting',
+ intent: {
+ action: 'android.intent.action.RUN',
+ flags: 67108864, // FLAG_ACTIVITY_CLEAR_TOP
+ extras: {
+ id: Math.random().toString(),
+ hash
+ }
+ }
+ }
+ await setDynShortcut(shortcut)
+ console.log('Shortcut successfully created')
+ } catch (err) {
+ console.error('Adding shortcut failed with', err)
+ }
+}
+
+export async function getShortcutIntent() {
+ const Shortcuts = await getShorcuts()
+ return await new Promise((resolve, reject) => {
+ try {
+ Shortcuts.getIntent(intent => {
+ resolve(intent)
+ })
+ } catch (err) {
+ reject(err)
+ }
+ })
+}
+
+export async function onShortcutIntent(handler) {
+ const Shortcuts = await getShorcuts()
+ Shortcuts.onNewIntent()
+ Shortcuts.onNewIntent((intent) => {
+ handler(intent)
+ })
+}
diff --git a/app/utils/app/UpdateUtils.js b/app/utils/app/UpdateUtils.js
new file mode 100644
index 000000000..6af0dbf70
--- /dev/null
+++ b/app/utils/app/UpdateUtils.js
@@ -0,0 +1,110 @@
+import tt from 'counterpart'
+import { fetchEx } from 'golos-lib-js/lib/utils'
+
+function updaterHost() {
+ return $STM_Config.app_updater.host
+}
+
+async function httpGet(url, timeout = fetchEx.COMMON_TIMEOUT, responseType = 'text') {
+ if (process.env.MOBILE_APP) {
+ return await new Promise((resolve, reject) => {
+ try {
+ cordova.plugin.http.sendRequest(url.toString(), {
+ responseType,
+ timeout: Math.ceil(timeout / 1000)
+ }, (resp) => {
+ resolve(resp.data)
+ }, (resp) => {
+ reject(resp.error)
+ })
+ } catch (err) {
+ reject(err)
+ }
+ })
+ } else {
+ let res = await fetchEx(url, {
+ timeout
+ })
+ if (responseType === 'arraybuffer') {
+ res = await res.arrayBuffer()
+ } else {
+ res = await res.text()
+ }
+ return res
+ }
+}
+
+export async function checkUpdates(timeout = 2000) {
+ let url = ''
+ try {
+ let path
+ const isDesktop = !process.env.MOBILE_APP
+ if (isDesktop) {
+ path = 'desktop/' + ($STM_Config.platform === 'linux' ? 'linux' : 'windows')
+ } else {
+ path = 'messenger/android'
+ }
+ url = new URL(
+ '/api/' + path, updaterHost()
+ )
+ url.searchParams.append('latest', '1')
+ url.searchParams.append('after', $STM_Config.app_version)
+ let res = await httpGet(url, timeout)
+ res = JSON.parse(res)
+ if (res.status === 'ok' && res.data) {
+ const versions = Object.entries(res.data)
+ if (versions[0]) {
+ const [ v, obj ] = versions[0]
+ if (obj.exe) {
+ let link = '/__app_update?v=' + v + '&exe=' + obj.exe + '&txt=' + obj.txt
+ if (!isDesktop) {
+ link = new URL('/api/html/' + path + '/' + v, updaterHost())
+ link = link.toString()
+ }
+ return {
+ show: true,
+ id: v,
+ link,
+ title: tt('app_update.notify_VERSION', { VERSION: v }),
+ new_tab: true,
+ }
+ } else {
+ console.error(versions[0])
+ }
+ }
+ } else {
+ if (res.error) {
+ if (process.env.MOBILE_APP) {
+ throw new Error(res.error)
+ }
+ }
+ console.error(res)
+ }
+ } catch (err) {
+ if (process.env.MOBILE_APP) {
+ throw new Error((err || 'checkUpdates') + ' (' + url + ')',
+ { cause : err })
+ } else {
+ console.error('checkUpdates', err)
+ }
+ }
+ return {}
+}
+
+export async function getChangelog(txtLink) {
+ try {
+ const decoder = new TextDecoder('windows-1251')
+ let res
+ if (process.env.MOBILE_APP) {
+ res = await httpGet(txtLink, 1000, 'arraybuffer')
+ res = decoder.decode(res)
+ } else {
+ res = await fetch(txtLink)
+ res = decoder.decode(await res.arrayBuffer())
+ }
+ return res
+ } catch (err) {
+ console.error('getChangelog', err)
+ throw err
+ }
+}
diff --git a/build_app_entry.js b/build_app_entry.js
index c2af0a1a7..9ce77d71f 100644
--- a/build_app_entry.js
+++ b/build_app_entry.js
@@ -29,6 +29,10 @@ if (destDir !== 'null') {
fse.copySync('app/assets/images', destDir + '/images', { overwrite: true }) // for some direct links
}
+if (cfgFile === '_mobile') {
+ process.exit(0)
+}
+
let cfg = {}
const copyKey = (key) => {
cfg[key] = config.get('desktop.' + key)
diff --git a/config.xml b/config.xml
new file mode 100644
index 000000000..151ded74a
--- /dev/null
+++ b/config.xml
@@ -0,0 +1,37 @@
+
+
+ GOLOS Блоги
+ Мобильное приложение Блогов на блокчейне Golos.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/mobile.json b/config/mobile.json
new file mode 100644
index 000000000..d173bd35c
--- /dev/null
+++ b/config/mobile.json
@@ -0,0 +1,62 @@
+{
+ "mobile": {
+ "ws_connection_app": [
+ { "address": "wss://apibeta.golos.today/ws" },
+ { "address": "wss://api.golos.id/ws" },
+ { "address": "wss://api.aleksw.space/ws" },
+ { "address": "wss://api-golos.blckchnd.com/ws" }
+ ],
+ "ws_connection_exchange": "wss://apibeta.golos.today/ws",
+ "site_domain": "beta.golos.today",
+ "logo": {
+ "icon": "https://i.imgur.com/Q7GCdPf.png",
+ "title": "https://i.imgur.com/36zv8We.png"
+ },
+ "images": {
+ "img_proxy_prefix": "https://devimages.golos.today",
+ "img_proxy_backup_prefix": "https://steemitimages.com",
+ "upload_image": "https://api.imgur.com/3/image",
+ "client_id": "6c09ebf8c548126"
+ },
+ "wallet_service": {
+ "host": "https://devwallet.golos.today"
+ },
+ "messenger_service": {
+ "host": "https://devchat.golos.app"
+ },
+ "auth_service": {
+ "host": "https://dev.golos.app",
+ "custom_client": "blogs"
+ },
+ "notify_service": {
+ "host": "https://devnotify.golos.app",
+ "host_ws": "wss://devnotify.golos.app/ws"
+ },
+ "elastic_search": {
+ "url": "https://search.golos.today",
+ "login": "golosclient",
+ "password": "golosclient"
+ },
+ "apidex_service": {
+ "host": "https://devapi-dex.golos.app",
+ "host_local": "https://devapi-dex.golos.app"
+ },
+ "app_updater": {
+ "host": "https://files.golos.app"
+ },
+ "forums": {
+ "white_list": ["fm-golostalk", "fm-prizmtalk", "fm-graphenetalks"],
+ "fm-golostalk": {"domain": "golostalk.com"},
+ "fm-prizmtalk": {"domain": "prizmtalk.com"},
+ "fm-graphenetalks": {"domain": "forum.gph.ai"}
+ },
+ "hidden_assets": {
+ "RUDEX": true,
+ "PRIZM": true,
+ "DOGECOIN": true,
+ "YMZEC": true,
+ "YMWMZ": true,
+ "YMBTC": true
+ }
+ }
+}
diff --git a/native_core/package.json b/native_core/package.json
new file mode 100644
index 000000000..3f854d9de
--- /dev/null
+++ b/native_core/package.json
@@ -0,0 +1,4 @@
+{
+ "name": "gls-blogs-native-core",
+ "version": "1.0.0"
+}
diff --git a/native_core/plugin.xml b/native_core/plugin.xml
new file mode 100644
index 000000000..b6e9a8cb3
--- /dev/null
+++ b/native_core/plugin.xml
@@ -0,0 +1,46 @@
+
+
+ Golos Blogs Native Core
+ Provides notification service when activity is paused, as well as on boot received
+ Apache 2.0
+ cordova
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/native_core/res/ic_empty.xml b/native_core/res/ic_empty.xml
new file mode 100644
index 000000000..16f82337d
--- /dev/null
+++ b/native_core/res/ic_empty.xml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/native_core/res/notify.png b/native_core/res/notify.png
new file mode 100644
index 000000000..4ad196057
Binary files /dev/null and b/native_core/res/notify.png differ
diff --git a/native_core/src/android/ApiClient.kt b/native_core/src/android/ApiClient.kt
new file mode 100644
index 000000000..70a7cd928
--- /dev/null
+++ b/native_core/src/android/ApiClient.kt
@@ -0,0 +1,50 @@
+package gls.blogs.core
+
+import okhttp3.HttpUrl
+import okhttp3.HttpUrl.Companion.toHttpUrl
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.Response
+import org.json.JSONObject
+import java.util.concurrent.TimeUnit
+
+open class ApiClient(val host: String) {
+ private var client: OkHttpClient = OkHttpClient()
+
+ fun urlBuilder(): HttpUrl.Builder {
+ return host.toHttpUrl().newBuilder()
+ }
+
+ open fun reqBuilder(url: HttpUrl): Request.Builder {
+ return Request.Builder()
+ .url(url)
+ }
+
+ private fun call(req: Request, err: String, timeoutMsec : Long? = null) : Response {
+ try {
+ var clientBuilder = client.newBuilder()
+ if (timeoutMsec != null) {
+ clientBuilder = clientBuilder.readTimeout(timeoutMsec, TimeUnit.MILLISECONDS)
+ }
+ return clientBuilder.build().newCall(req).execute()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ throw Exception(err)
+ }
+ }
+
+ private fun getJSON(str: String, err: String) : JSONObject {
+ try {
+ return JSONObject(str)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ throw Exception(err)
+ }
+ }
+
+ fun callForJSON(req: Request, err: String, timeoutMsec : Long? = null) : JSONObject {
+ val res = call(req, err, timeoutMsec)
+ val str = res.body?.string()
+ return getJSON(str!!, err)
+ }
+}
\ No newline at end of file
diff --git a/native_core/src/android/AppPrefs.kt b/native_core/src/android/AppPrefs.kt
new file mode 100644
index 000000000..ab2a37361
--- /dev/null
+++ b/native_core/src/android/AppPrefs.kt
@@ -0,0 +1,9 @@
+package gls.blogs.core
+
+data class AppPrefs(
+ var account: String = "",
+ var session: String = "",
+ var scopes: String = "",
+ var lastTake: Long = 0,
+ var notifyHost: String = ""
+ )
\ No newline at end of file
diff --git a/native_core/src/android/BootReceiver.kt b/native_core/src/android/BootReceiver.kt
new file mode 100644
index 000000000..8dce2e8d8
--- /dev/null
+++ b/native_core/src/android/BootReceiver.kt
@@ -0,0 +1,31 @@
+package gls.blogs.core
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.util.Log
+
+const val TAG = "GLS/BootReceiver"
+
+class BootReceiver: BroadcastReceiver() {
+ override fun onReceive(ctx: Context?, intent: Intent?) {
+ if (intent == null) {
+ Log.e(TAG, "Boot received, but no Intent")
+ return
+ }
+ if (intent.action != Intent.ACTION_BOOT_COMPLETED) {
+ Log.e(TAG, "Boot received, but Intent has wrong action: ${intent.action}")
+ return
+ }
+ if (ctx != null) {
+ if (ServiceHelper.loadPrefs(ctx).account != "") {
+ Log.i(TAG, "Boot received, starting service")
+ ServiceHelper.startNotifyService(ctx.applicationContext)
+ } else {
+ Log.w(TAG, "Boot received, but account in prefs is null, so we should not start service")
+ }
+ } else {
+ Log.e(TAG, "Boot received, but no Context, so cannot start service")
+ }
+ }
+}
\ No newline at end of file
diff --git a/native_core/src/android/CorePlugin.kt b/native_core/src/android/CorePlugin.kt
new file mode 100644
index 000000000..6991c187b
--- /dev/null
+++ b/native_core/src/android/CorePlugin.kt
@@ -0,0 +1,34 @@
+package gls.blogs.core
+
+import android.content.Context
+import org.apache.cordova.CordovaPlugin
+import org.apache.cordova.CallbackContext
+
+import org.json.JSONArray
+import org.json.JSONException
+import org.json.JSONObject
+import android.widget.Toast
+
+class CorePlugin : CordovaPlugin() {
+ override fun execute(action: String, args: JSONArray, callbackContext: CallbackContext) : Boolean {
+ val ctx = this.cordova.getContext()
+ if (action.equals("startService")) {
+ var prefs = AppPrefs()
+ prefs.account = args.getString(0)
+ prefs.session = args.getString(1)
+ prefs.scopes = args.getString(2)
+ prefs.lastTake = args.getLong(3)
+ prefs.notifyHost = args.getString(4)
+ // And not passing subscriber id because service should subscribe again
+ ServiceHelper.savePrefs(ctx, prefs)
+ ServiceHelper.startNotifyService(ctx)
+ callbackContext.success()
+ } else if (action.equals("stopService")) {
+ ServiceHelper.stopNotifyService(ctx)
+ callbackContext.success()
+ } else if (action.equals("logout")) {
+ ServiceHelper.clearPrefs(ctx)
+ }
+ return false
+ }
+}
\ No newline at end of file
diff --git a/native_core/src/android/NotificationHelper.kt b/native_core/src/android/NotificationHelper.kt
new file mode 100644
index 000000000..0d8b46797
--- /dev/null
+++ b/native_core/src/android/NotificationHelper.kt
@@ -0,0 +1,97 @@
+package gls.blogs.core
+
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.media.RingtoneManager
+import android.net.Uri
+import android.os.Build
+import android.widget.Toast
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import gls.blogs.MainActivity
+import gls.blogs.R
+
+private const val MESSAGES_CHANNEL = "MESSAGES"
+private const val MESSAGE_NOTIFICATION_ID = 2
+
+private const val FOREGROUND_CHANNEL = "FOREGROUND"
+const val FOREGROUND_NOTIFICATION_ID = 1
+
+class NotificationHelper(val ctx: Context) {
+ private val soundUri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
+ private val notificationManager: NotificationManager =
+ ctx.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ private var notifId = MESSAGE_NOTIFICATION_ID
+
+ private fun createChannel(id: String, name: String, description: String, importance: Int, silent: Boolean = false) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val channel = NotificationChannel(id, name, importance).apply {
+ description
+ }
+ if (!silent) {
+ channel.enableVibration(true)
+ channel.setSound(soundUri, null)
+ }
+ notificationManager.createNotificationChannel(channel)
+ }
+ }
+
+ private fun createMessagesChannel() {
+ createChannel(MESSAGES_CHANNEL, "Messages", "New messages notifications",
+ NotificationManager.IMPORTANCE_HIGH)
+ }
+
+ private fun createForegroundChannel() {
+ createChannel(
+ FOREGROUND_CHANNEL, "Others", "Others channel",
+ NotificationManager.IMPORTANCE_LOW, true)
+ }
+
+ private fun pendingIntent() : PendingIntent {
+ val intent = Intent(ctx, MainActivity::class.java).apply {
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+ }
+ return PendingIntent.getActivity(ctx, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+ }
+
+ private fun makeMessage(title: String, description: String, icon: Int): Notification {
+ createMessagesChannel()
+
+ return NotificationCompat.Builder(ctx, MESSAGES_CHANNEL)
+ .setSmallIcon(icon)
+ .setContentTitle(title)
+ .setContentText(description)
+ .setContentIntent(pendingIntent())
+ .setAutoCancel(true)
+ .setPriority(NotificationCompat.PRIORITY_HIGH)
+ .setSound(soundUri)
+ .build()
+ }
+
+ fun notifyMessage(title: String, description: String) {
+ val notification = makeMessage(title, description, R.drawable.notify)
+
+ with(NotificationManagerCompat.from(ctx)) {
+ if (notifId >= MESSAGE_NOTIFICATION_ID+2) {
+ notifId = MESSAGE_NOTIFICATION_ID
+ }
+ notificationManager.notify(notifId++, notification)
+ }
+ }
+
+ fun makeForeground(title: String, description: String, icon: Int): Notification {
+ createForegroundChannel()
+
+ return NotificationCompat.Builder(ctx, FOREGROUND_CHANNEL)
+ .setSmallIcon(icon)
+ .setContentTitle(title)
+ .setContentText(description)
+ .setContentIntent(pendingIntent())
+ .setPriority(NotificationCompat.PRIORITY_LOW)
+ .build()
+ }
+}
\ No newline at end of file
diff --git a/native_core/src/android/NotifyApiClient.kt b/native_core/src/android/NotifyApiClient.kt
new file mode 100644
index 000000000..cb45b4925
--- /dev/null
+++ b/native_core/src/android/NotifyApiClient.kt
@@ -0,0 +1,88 @@
+package gls.blogs.core
+
+import android.util.Log
+import okhttp3.HttpUrl
+import okhttp3.Request
+import org.json.JSONObject
+
+class NotifyApiClient(notifyHost: String) : ApiClient(notifyHost) {
+ var session = ""
+
+ override fun reqBuilder(url: HttpUrl): Request.Builder {
+ val builder = super.reqBuilder(url)
+ return builder.header("X-Session", session)
+ }
+
+ public fun subscribe(acc: String, scopes: String) : Int {
+ val url = urlBuilder().addPathSegments("subscribe/@$acc/$scopes").build()
+ val request = reqBuilder(url).build()
+
+ val json = callForJSON(request, "Cannot subscribe")
+ try {
+ return json.getInt("subscriber_id")
+ } catch (e: Exception) {
+ throw Exception("Cannot subscribe, error: " + json.optString("error"))
+ }
+ }
+
+ data class TakeResult(
+ var removeTaskIds: ArrayList
= ArrayList(),
+ var lastTake: Long = 0
+ ) {}
+
+ public fun take(acc: String, subId: String, callback: (String, JSONObject) -> Unit, removeTaskIds: String?): TakeResult {
+ var builder = urlBuilder().addPathSegments("take/@$acc/$subId")
+ if (removeTaskIds != null) {
+ builder = builder.addPathSegment(removeTaskIds)
+ }
+
+ val request = reqBuilder(builder.build()).build()
+
+ val json = callForJSON(request, "Cannot take", 61000)
+ try {
+ val lastTake = json.getLong("__")
+ val tasks = json.getJSONArray("tasks")
+ var removeTaskIds = ArrayList()
+ (0 until tasks.length()).forEach {
+ val task = tasks.getJSONObject(it)
+
+ val data = task.getJSONArray("data")
+ val type = data.getString(0)
+ val op = data.getJSONObject(1)
+
+ callback(type, op)
+
+ val taskId = task.getString("id")
+ removeTaskIds.add(taskId)
+ }
+ return TakeResult(removeTaskIds, lastTake)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ throw Exception(json.getString("error"))
+ }
+ }
+
+ public fun getInbox(acc: String, lastTake: Long, callback: (JSONObject) -> Unit) {
+ var builder = urlBuilder().addPathSegments("msgs/get_inbox/@$acc")
+ .addQueryParameter("unread_only", "true")
+ val request = reqBuilder(builder.build()).build()
+ val json = callForJSON(request, "Cannot getInbox")
+ try {
+ val results = json.getJSONArray("result")
+ for (index in 0 until results.length()) {
+ val result = results.getJSONObject(index)
+
+ val time = result.getLong("__time")
+
+ if (time >= lastTake) {
+ callback(result)
+ } else {
+ break
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ throw Exception(json.getString("error"))
+ }
+ }
+}
\ No newline at end of file
diff --git a/native_core/src/android/NotifyService.kt b/native_core/src/android/NotifyService.kt
new file mode 100644
index 000000000..5155cb33c
--- /dev/null
+++ b/native_core/src/android/NotifyService.kt
@@ -0,0 +1,132 @@
+package gls.blogs.core
+
+import android.app.Service
+import android.content.Intent
+import android.os.Handler
+import android.os.IBinder
+import android.os.Looper
+import android.widget.Toast
+import android.util.Log
+import org.json.JSONObject
+import kotlin.concurrent.thread
+import gls.blogs.R
+
+class NotifyService() : Service() {
+ companion object {
+ private const val TAG = "GLS/NotifyService"
+
+ const val ACTION_STOP = "ACTION_STOP"
+ }
+
+ private lateinit var nac: NotifyApiClient
+ private lateinit var nh: NotificationHelper
+ private lateinit var prefs: AppPrefs
+ private var workThread: Thread? = null
+
+ private var subId = ""
+
+ private fun showNotification(descr: String) {
+ Handler(Looper.getMainLooper()).post {
+ nh.notifyMessage("GOLOS Блоги", descr)
+ }
+ }
+
+ private fun doLoop(removeTaskIds: ArrayList) {
+ if (Thread.interrupted()) return
+
+ if (subId.isEmpty()) {
+ try {
+ subId = nac?.subscribe(prefs.account, prefs.scopes).toString()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ Thread.sleep(5000)
+ doLoop(removeTaskIds)
+ return
+ }
+ Log.i(TAG, "NotifyService subscribed $subId")
+
+ if (Thread.interrupted()) return
+ }
+
+ if (Thread.interrupted()) return
+
+ var entries = ArrayList()
+ val rti = removeTaskIds.joinToString(",")
+ var newRTI = ArrayList()
+ try {
+ val takeRes = nac?.take(prefs.account, subId, { typ: String, op: JSONObject ->
+ var entry = typ + ":" + op.toString()
+ val author = op.optString("author", "")
+ val parent_author = op.optString("parent_author", "")
+ if (typ == "comment_reply") {
+ val _depth = op.optInt("_depth", 0)
+ if (_depth > 1) {
+ entry = "@" + author + " ответил на ваш комментарий."
+ } else {
+ entry = "@" + author + " прокомментировал ваш пост."
+ }
+ } else if (typ == "comment_mention") {
+ if (parent_author != "") {
+ entry = "@" + author + " упомянул вас в комментарии."
+ } else {
+ entry = "@" + author + " упомянул вас в своем посте."
+ }
+ }
+ entries.add(entry)
+ }, rti)
+ newRTI = takeRes.removeTaskIds
+
+ if (Thread.interrupted()) return
+
+ prefs.lastTake = takeRes.lastTake
+ ServiceHelper.savePrefs(applicationContext, prefs)
+
+ for (i in 0..entries.size) {
+ showNotification(entries[i])
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ if (e.message != null && e.message!!.contains("No such queue")) {
+ Log.e(TAG, "No such queue - resubscribing")
+ subId = ""
+ }
+ }
+ Thread.sleep(2500)
+ doLoop(newRTI)
+ }
+
+ override fun onBind(intent: Intent?): IBinder? {
+ return null
+ }
+
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ if (intent != null && intent.action == ACTION_STOP) {
+ if (workThread != null) {
+ workThread!!.interrupt()
+ stopForeground(true)
+ stopSelfResult(startId)
+ }
+ return START_STICKY
+ }
+
+ nh = NotificationHelper(this)
+ val n = nh.makeForeground(" ", "GOLOS Блоги работают.", R.drawable.ic_empty)
+ startForeground(FOREGROUND_NOTIFICATION_ID, n)
+
+ Log.i(TAG, "Started")
+
+ prefs = ServiceHelper.loadPrefs(applicationContext)
+ nac = NotifyApiClient(prefs.notifyHost)
+ nac.session = prefs.session
+
+ workThread = thread {
+ try {
+ doLoop(ArrayList())
+ } catch (e: InterruptedException) {
+ Log.i(TAG, "Service stopped - InterruptedException", e)
+ }
+ }
+
+ return START_STICKY
+ }
+}
diff --git a/native_core/src/android/ServiceHelper.kt b/native_core/src/android/ServiceHelper.kt
new file mode 100644
index 000000000..6c4c59e1a
--- /dev/null
+++ b/native_core/src/android/ServiceHelper.kt
@@ -0,0 +1,70 @@
+package gls.blogs.core
+
+import android.app.Application
+import android.content.Context
+import android.content.Context.MODE_PRIVATE
+import android.content.Intent
+import android.content.SharedPreferences
+
+const val PREF_ACCOUNT = "pref_account"
+const val PREF_SESSION = "pref_session"
+const val PREF_SCOPES = "pref_scopes"
+const val PREF_LAST_TAKE = "pref_last_take"
+const val PREF_NOTIFYHOST = "pref_notify_host"
+
+class ServiceHelper {
+ companion object {
+ private fun getSharedPrefs(ctx: Context): SharedPreferences {
+ return ctx.getSharedPreferences("prefs", MODE_PRIVATE)
+ }
+
+ fun savePrefs(ctx: Context, prefs: AppPrefs) {
+ val sharedPrefs = getSharedPrefs(ctx)
+ with (sharedPrefs.edit()) {
+ putString(PREF_ACCOUNT, prefs.account)
+ putString(PREF_SESSION, prefs.session)
+ putString(PREF_SCOPES, prefs.scopes)
+ putLong(PREF_LAST_TAKE, prefs.lastTake)
+ putString(PREF_NOTIFYHOST, prefs.notifyHost)
+ apply()
+ }
+ }
+
+ fun loadPrefs(ctx: Context): AppPrefs {
+ val sharedPrefs = getSharedPrefs(ctx)
+ return AppPrefs(
+ sharedPrefs.getString(PREF_ACCOUNT, "")!!,
+ sharedPrefs.getString(PREF_SESSION, "")!!,
+ sharedPrefs.getString(PREF_SCOPES, "")!!,
+ sharedPrefs.getLong(PREF_LAST_TAKE, 0),
+ sharedPrefs.getString(PREF_NOTIFYHOST, "")!!
+ )
+ }
+
+ fun clearPrefs(ctx: Context) {
+ val sharedPrefs = getSharedPrefs(ctx)
+ with (sharedPrefs.edit()) {
+ remove(PREF_ACCOUNT)
+ remove(PREF_SESSION)
+ remove(PREF_SCOPES)
+ remove(PREF_LAST_TAKE)
+ remove(PREF_NOTIFYHOST)
+ apply()
+ }
+ }
+
+ fun startNotifyService(ctx: Context?) {
+ if (ctx != null) {
+ ctx.startForegroundService(Intent(ctx, NotifyService::class.java))
+ }
+ }
+
+ fun stopNotifyService(ctx: Context?) {
+ if (ctx != null) {
+ val intent = Intent(ctx, NotifyService::class.java)
+ intent.action = NotifyService.ACTION_STOP
+ ctx.startService(intent)
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
index 12cc35dff..cf7d10f6b 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,7 @@
"description": "Golos Blogs — децентрализованная платформа блогов, работающая на блокчейне Golos.",
"main": "dist/electron/electron.js",
"scripts": {
+ "cordova": "cordova",
"build-version": "./server/build-version.sh",
"build-hash": "node check_integrity --save",
"build": "npm run build-hash && NODE_ENV=production NODE_CONFIG_ENV=production,blacklist ./node_modules/.bin/webpack --config ./webpack/prod.config.js",
@@ -22,7 +23,10 @@
"build-storybook": "build-storybook",
"dev:app": "npm run build-hash && cross-env NODE_CONFIG_ENV=blacklist IS_APP=1 ./node_modules/@babel/node/bin/babel-node.js ./webpack/dev-server.js",
"build:app": "npm run build-hash && cross-env NODE_ENV=production NODE_CONFIG_ENV=production,desktop ./node_modules/.bin/webpack --config ./webpack/prod-app.config.js",
- "build:app-entry": "cross-env NODE_ENV=production NODE_CONFIG_ENV=production,desktop ./node_modules/@babel/node/bin/babel-node.js build_app_entry.js"
+ "build:app-entry": "cross-env NODE_ENV=production NODE_CONFIG_ENV=production,desktop ./node_modules/@babel/node/bin/babel-node.js build_app_entry.js",
+ "prebuild:mobile": "cross-env NODE_CONFIG_ENV=production,mobile node ./prebuild_mobile.js",
+ "build:mobile": "npm run build-hash && cross-env NODE_ENV=production NODE_CONFIG_ENV=production,mobile ./node_modules/.bin/webpack --config ./webpack/prod-mobile.config.js",
+ "postbuild:mobile": "npm run build:app-entry dist _mobile && cross-env NODE_CONFIG_ENV=production,mobile node ./postbuild_mobile.js && cd cordova && cordova prepare && cordova run android"
},
"author": "Golos ",
"license": "MIT",
@@ -138,11 +142,23 @@
"@babel/plugin-transform-runtime": "^7.16.0",
"@babel/preset-env": "^7.16.0",
"@babel/preset-react": "^7.16.0",
+ "@red-mobile/cordova-plugin-shortcuts-android": "^1.0.1",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.3",
"babel-plugin-styled-components": "^1.5.1",
"chai": "^4.1.2",
+ "cheerio": "1.0.0-rc.10",
"co-mocha": "^1.2.2",
+ "cordova-android": "^10.1.2",
+ "cordova-config": "^0.7.0",
+ "cordova-plugin-advanced-http": "^3.3.1",
+ "cordova-plugin-androidx-adapter": "^1.1.3",
+ "cordova-plugin-backbutton": "^0.3.0",
+ "cordova-plugin-badge": "^0.8.9",
+ "cordova-plugin-device": "^3.0.0",
+ "cordova-plugin-file": "^7.0.0",
+ "cordova-plugin-native-logs": "^1.0.5",
+ "cordova-plugin-splashscreen": "^6.0.2",
"core-js": "^3.19.1",
"cross-env": "^7.0.3",
"eslint": "^4.9.0",
@@ -151,6 +167,7 @@
"eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-react": "^7.4.0",
"folder-hash": "^4.0.4",
+ "gls-blogs-native-core": "file:native_core",
"jsdom": "^21.0.0",
"mini-css-extract-plugin": "^0.4.0",
"mocha": "^5.2.0",
@@ -162,7 +179,7 @@
"svg-sprite-loader": "^4.3.0",
"uglifyjs-webpack-plugin": "^1.2.5",
"webpack-command": "^0.2.1",
- "webpack-merge": "^4.1.2",
+ "webpack-merge": "5.2.0",
"webpack-serve": "^1.0.4"
},
"optionalDependencies": {
@@ -177,5 +194,23 @@
"tabWidth": 4,
"semi": true,
"trailingComma": "es5"
+ },
+ "cordova": {
+ "platforms": [
+ "android"
+ ],
+ "plugins": {
+ "cordova-plugin-advanced-http": {
+ "ANDROIDBLACKLISTSECURESOCKETPROTOCOLS": "SSLv3,TLSv1"
+ },
+ "cordova-plugin-androidx-adapter": {},
+ "cordova-plugin-backbutton": {},
+ "cordova-plugin-native-logs": {},
+ "cordova-plugin-splashscreen": {},
+ "@red-mobile/cordova-plugin-shortcuts-android": {
+ "ANDROIDX_CORE_VERSION": "1.3.2"
+ },
+ "gls-blogs-native-core": {}
+ }
}
}
diff --git a/postbuild_mobile.js b/postbuild_mobile.js
new file mode 100644
index 000000000..d8f44e398
--- /dev/null
+++ b/postbuild_mobile.js
@@ -0,0 +1,89 @@
+const fs = require('fs')
+const fse = require('fs-extra')
+const cheerio = require('cheerio')
+const CordovaConfig = require('cordova-config')
+const config = require('config')
+
+function dirExists(path) {
+ try {
+ return fs.statSync(path).isDirectory();
+ } catch (e) {
+ return false
+ }
+}
+
+function copyDir(dir) {
+ fse.copySync(dir, distPath + '/' + dir)
+}
+
+function patchLocalPluginVersion(moduleName, dir) { // Patch plugin version to do not broke on cordova prepare
+ const coreVersion = JSON.parse(fs.readFileSync(dir + '/package.json')).version
+ console.log(' ' + moduleName, 'version:', coreVersion)
+
+ let json = JSON.parse(fs.readFileSync(distPath + '/package.json'))
+ if (!json.devDependencies[moduleName]) {
+ throw new Error(moduleName + ' dependency is not found in package.json/devDependencies')
+ }
+ json.devDependencies[moduleName] = coreVersion
+ json = JSON.stringify(json, null, 2)
+ fs.writeFileSync(distPath + '/package.json', json)
+}
+
+
+const distPath = 'cordova'
+const configFile = distPath + '/config.xml'
+const indexHtml = distPath + '/www/index.html'
+
+console.log('--- Copying files to "' + distPath + '" folder...')
+
+if (!fs.existsSync(distPath)) {
+ fs.mkdirSync(distPath)
+}
+fs.copyFileSync('config.xml', configFile)
+fs.copyFileSync('package.json', distPath + '/package.json') // for "cordova prepare"
+fs.copyFileSync('yarn.lock', distPath + '/yarn.lock')
+
+console.log('--- Adding hostname to "' + configFile + '" file...')
+
+let cc = new CordovaConfig(configFile)
+cc.setPreference('hostname', config.get('mobile.site_domain'))
+cc.writeSync()
+
+console.log('--- Moving react "build" folder to "' + distPath + '/www"')
+
+if (dirExists('dist')) {
+ fs.rmSync(distPath + '/www', { recursive: true, force: true });
+ fs.renameSync('dist', distPath + '/www')
+}
+
+console.log('--- Copying "native_core" folder to "' + distPath + '/native_core"')
+
+copyDir('native_core')
+
+console.log('--- Patching "native_core" version for correct installation')
+
+patchLocalPluginVersion('gls-blogs-native-core', 'native_core')
+
+console.log('--- Clearing cordova in order to update in on "cordova prepare"')
+
+fs.rmSync(distPath + '/platforms', { recursive: true, force: true })
+fs.rmSync(distPath + '/plugins', { recursive: true, force: true })
+
+console.log('--- Copying "res" folder to "' + distPath + '/res"')
+
+copyDir('res')
+
+console.log('--- Including cordova.js script into "' + indexHtml + '" file...')
+
+let idx = fs.readFileSync(indexHtml, 'utf8')
+idx = cheerio.load(idx)
+if (idx('script[src="cordova.js"]').length === 0) {
+ idx('').insertBefore('script:first-of-type')
+ idx('').insertBefore('script:first-of-type')
+ console.log('Included.')
+} else {
+ console.log('Already exists.')
+}
+fs.writeFileSync(indexHtml, idx.html())
+
+console.log('--- Copied. Installing Cordova plugins and platforms ("cordova prepare"), and building+running android')
diff --git a/prebuild_mobile.js b/prebuild_mobile.js
new file mode 100644
index 000000000..149890c0f
--- /dev/null
+++ b/prebuild_mobile.js
@@ -0,0 +1,27 @@
+const config = require('config')
+const fs = require('fs')
+const app_version = require('./package.json').version
+
+console.log('--- Making default config for react build...')
+
+let cfg = {}
+const copyKey = (key) => {
+ cfg[key] = config.get('mobile.' + key)
+}
+cfg.app_version = app_version
+copyKey('ws_connection_app')
+copyKey('ws_connection_exchange')
+copyKey('logo')
+copyKey('images')
+copyKey('wallet_service')
+copyKey('messenger_service')
+copyKey('auth_service')
+copyKey('notify_service')
+copyKey('elastic_search')
+copyKey('apidex_service')
+copyKey('app_updater')
+copyKey('forums')
+copyKey('hidden_assets')
+fs.writeFileSync('app/app_cfg.js', '/* Only Mobile. Generated automatically. Do not edit. */\r\nmodule.exports = ' + JSON.stringify(cfg, null, 4))
+
+console.log('--- Config done. Next stage is running react build.')
diff --git a/res/blg_setting.png b/res/blg_setting.png
new file mode 100644
index 000000000..acaff94a8
Binary files /dev/null and b/res/blg_setting.png differ
diff --git a/res/blog0.png b/res/blog0.png
new file mode 100644
index 000000000..d465a76eb
Binary files /dev/null and b/res/blog0.png differ
diff --git a/res/blog1.png b/res/blog1.png
new file mode 100644
index 000000000..3ded20e91
Binary files /dev/null and b/res/blog1.png differ
diff --git a/res/icon-hdpi.png b/res/icon-hdpi.png
new file mode 100644
index 000000000..474425e46
Binary files /dev/null and b/res/icon-hdpi.png differ
diff --git a/res/icon-ldpi.png b/res/icon-ldpi.png
new file mode 100644
index 000000000..8434d3381
Binary files /dev/null and b/res/icon-ldpi.png differ
diff --git a/res/icon-mdpi.png b/res/icon-mdpi.png
new file mode 100644
index 000000000..478cda1c6
Binary files /dev/null and b/res/icon-mdpi.png differ
diff --git a/res/icon-xhdpi.png b/res/icon-xhdpi.png
new file mode 100644
index 000000000..252b7307d
Binary files /dev/null and b/res/icon-xhdpi.png differ
diff --git a/res/icon-xxhdpi.png b/res/icon-xxhdpi.png
new file mode 100644
index 000000000..5fdcff6d2
Binary files /dev/null and b/res/icon-xxhdpi.png differ
diff --git a/res/icon-xxxhdpi.png b/res/icon-xxxhdpi.png
new file mode 100644
index 000000000..b0e49b6d0
Binary files /dev/null and b/res/icon-xxxhdpi.png differ
diff --git a/res/logo.png b/res/logo.png
new file mode 100644
index 000000000..c1579ea6f
Binary files /dev/null and b/res/logo.png differ
diff --git a/res/logo_x.png b/res/logo_x.png
new file mode 100644
index 000000000..78e852dd5
Binary files /dev/null and b/res/logo_x.png differ
diff --git a/res/screen/android/land/splash-land-hdpi.png b/res/screen/android/land/splash-land-hdpi.png
new file mode 100644
index 000000000..b5893cff3
Binary files /dev/null and b/res/screen/android/land/splash-land-hdpi.png differ
diff --git a/res/screen/android/land/splash-land-ldpi.png b/res/screen/android/land/splash-land-ldpi.png
new file mode 100644
index 000000000..05c53b4f2
Binary files /dev/null and b/res/screen/android/land/splash-land-ldpi.png differ
diff --git a/res/screen/android/land/splash-land-mdpi.png b/res/screen/android/land/splash-land-mdpi.png
new file mode 100644
index 000000000..604ba2a6f
Binary files /dev/null and b/res/screen/android/land/splash-land-mdpi.png differ
diff --git a/res/screen/android/land/splash-land-xhdpi.png b/res/screen/android/land/splash-land-xhdpi.png
new file mode 100644
index 000000000..db95d626a
Binary files /dev/null and b/res/screen/android/land/splash-land-xhdpi.png differ
diff --git a/res/screen/android/land/splash-land-xxhdpi.png b/res/screen/android/land/splash-land-xxhdpi.png
new file mode 100644
index 000000000..46146a12b
Binary files /dev/null and b/res/screen/android/land/splash-land-xxhdpi.png differ
diff --git a/res/screen/android/land/splash-land-xxxhdpi.png b/res/screen/android/land/splash-land-xxxhdpi.png
new file mode 100644
index 000000000..9e4f263ad
Binary files /dev/null and b/res/screen/android/land/splash-land-xxxhdpi.png differ
diff --git a/res/screen/android/splash-hdpi.png b/res/screen/android/splash-hdpi.png
new file mode 100644
index 000000000..e4593654f
Binary files /dev/null and b/res/screen/android/splash-hdpi.png differ
diff --git a/res/screen/android/splash-ldpi.png b/res/screen/android/splash-ldpi.png
new file mode 100644
index 000000000..46d1e4f5b
Binary files /dev/null and b/res/screen/android/splash-ldpi.png differ
diff --git a/res/screen/android/splash-mdpi.png b/res/screen/android/splash-mdpi.png
new file mode 100644
index 000000000..487b5560a
Binary files /dev/null and b/res/screen/android/splash-mdpi.png differ
diff --git a/res/screen/android/splash-xhdpi.png b/res/screen/android/splash-xhdpi.png
new file mode 100644
index 000000000..41bcb64d2
Binary files /dev/null and b/res/screen/android/splash-xhdpi.png differ
diff --git a/res/screen/android/splash-xxhdpi.png b/res/screen/android/splash-xxhdpi.png
new file mode 100644
index 000000000..454380548
Binary files /dev/null and b/res/screen/android/splash-xxhdpi.png differ
diff --git a/res/screen/android/splash-xxxhdpi.png b/res/screen/android/splash-xxxhdpi.png
new file mode 100644
index 000000000..10e592473
Binary files /dev/null and b/res/screen/android/splash-xxxhdpi.png differ
diff --git a/webpack/dev-app.config.js b/webpack/dev-app.config.js
index e3e2e7d12..5828b4d2f 100644
--- a/webpack/dev-app.config.js
+++ b/webpack/dev-app.config.js
@@ -1,5 +1,5 @@
const webpack = require('webpack');
-const merge = require('webpack-merge');
+const { merge } = require('webpack-merge');
const git = require('git-rev-sync');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const baseConfig = require('./base.config');
diff --git a/webpack/dev.config.js b/webpack/dev.config.js
index 2606bb4aa..ef0d1c48a 100644
--- a/webpack/dev.config.js
+++ b/webpack/dev.config.js
@@ -1,5 +1,5 @@
const webpack = require('webpack');
-const merge = require('webpack-merge');
+const { merge } = require('webpack-merge')
const git = require('git-rev-sync');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const baseConfig = require('./base.config');
diff --git a/webpack/prod-app.config.js b/webpack/prod-app.config.js
index 9bce3b673..8c585d945 100644
--- a/webpack/prod-app.config.js
+++ b/webpack/prod-app.config.js
@@ -1,5 +1,5 @@
const webpack = require('webpack');
-const merge = require('webpack-merge');
+const { merge } = require('webpack-merge')
const path = require('path');
let prodConfig = require('./prod.config');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
diff --git a/webpack/prod-mobile.config.js b/webpack/prod-mobile.config.js
new file mode 100644
index 000000000..1e7cdbd5d
--- /dev/null
+++ b/webpack/prod-mobile.config.js
@@ -0,0 +1,45 @@
+const webpack = require('webpack');
+const { mergeWithCustomize, unique } = require('webpack-merge')
+const path = require('path');
+let prodConfig = require('./prod.config');
+const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
+
+delete prodConfig.optimization.minimizer
+
+module.exports = mergeWithCustomize({
+ customizeArray: unique(
+ 'plugins',
+ ['DefinePlugin'],
+ (plugin) => plugin.constructor && plugin.constructor.name,
+ ),
+})(prodConfig, {
+ plugins: [
+ new webpack.DefinePlugin({
+ 'process.env': {
+ BROWSER: JSON.stringify(true),
+ NODE_ENV: JSON.stringify('production'),
+ IS_APP: JSON.stringify(true),
+ MOBILE_APP: JSON.stringify(true),
+ },
+ global: {
+ TYPED_ARRAY_SUPPORT: JSON.stringify(false),
+ },
+ }),
+ ],
+ entry: {
+ app: [ './app/MainApp.js' ],
+ // vendor: ['react', 'react-dom', 'react-router']
+ },
+ output: {
+ path: path.resolve(__dirname, '../dist/assets'),
+ },
+ optimization: {
+ minimizer: [
+ new OptimizeCSSAssetsPlugin({
+ cssProcessorOptions: {
+ safe: true,
+ }
+ }),
+ ],
+ },
+});
diff --git a/webpack/prod.config.js b/webpack/prod.config.js
index b757e9a71..3226861f5 100644
--- a/webpack/prod.config.js
+++ b/webpack/prod.config.js
@@ -1,5 +1,5 @@
const webpack = require('webpack');
-const merge = require('webpack-merge');
+const { merge } = require('webpack-merge')
const baseConfig = require('./base.config');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
diff --git a/yarn.lock b/yarn.lock
index c55f11db1..b22e6a257 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1287,11 +1287,41 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"
+"@netflix/nerror@^1.1.3":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@netflix/nerror/-/nerror-1.1.3.tgz#9d88eccca442f1d544f2761d15ea557dc0a44ed2"
+ integrity sha512-b+MGNyP9/LXkapreJzNUzcvuzZslj/RGgdVVJ16P2wSlYatfLycPObImqVJSmNAdyeShvNeM/pl3sVZsObFueg==
+ dependencies:
+ assert-plus "^1.0.0"
+ extsprintf "^1.4.0"
+ lodash "^4.17.15"
+
"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3":
version "2.1.8-no-fsevents.3"
resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b"
integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.5"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3":
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.5"
+ fastq "^1.6.0"
+
"@npmcli/fs@^1.0.0":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257"
@@ -1329,6 +1359,11 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.2.tgz#adea7b6953cbb34651766b0548468e743c6a2353"
integrity sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q==
+"@red-mobile/cordova-plugin-shortcuts-android@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@red-mobile/cordova-plugin-shortcuts-android/-/cordova-plugin-shortcuts-android-1.0.1.tgz#5ac176fe47d9be979a313f53692db6a56d28dc1a"
+ integrity sha512-WlmgkCyp6WCTV/Y/AW9xg8gQrnxwGD8CxH90uWglHops8Uf0vsSnWpvxrlGQTjpOSavnqosgrnge58kkhd7ccw==
+
"@shellscape/koa-send@^4.1.0":
version "4.1.3"
resolved "https://registry.yarnpkg.com/@shellscape/koa-send/-/koa-send-4.1.3.tgz#1a7c8df21f63487e060b7bfd8ed82e1d3c4ae0b0"
@@ -1614,6 +1649,11 @@
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.6.tgz#8a1524eb5bd5e965c1e3735476f0262469f71440"
integrity sha512-uRjjusqpoqfmRkTaNuLJ2VohVr67Q5YwDATW3VU7PfzTj6IRaihGrYI7zckGZjxQPBIp63nfvJbM+Yu5ICh0Bg==
+"@xmldom/xmldom@^0.8.8":
+ version "0.8.10"
+ resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99"
+ integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==
+
"@xtuc/ieee754@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
@@ -1775,6 +1815,13 @@ alphanum-sort@^1.0.0:
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=
+android-versions@^1.7.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/android-versions/-/android-versions-1.9.0.tgz#433d53fc6ed5ba2b8d3c2801cb5da3964013274d"
+ integrity sha512-13O2B6PQMEM4ej9n13ePRQeckrCoKbZrvuzlLvK+9s2QmncpHDbYzZxhgapN32sJNoifN6VAHexLnd/6CYrs7Q==
+ dependencies:
+ semver "^7.5.2"
+
ansi-align@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
@@ -1815,6 +1862,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
dependencies:
color-convert "^2.0.1"
+ansi@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/ansi/-/ansi-0.3.1.tgz#0c42d4fb17160d5a9af1e484bace1c66922c1b21"
+ integrity sha512-iFY7JCgHbepc0b82yLaw4IMortylNb6wG4kL+4R0C3iv6i+RHGHux/yUX5BTiRvSX/shMnngjR1YyNMnXEFh5A==
+
any-promise@^1.0.0, any-promise@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
@@ -1998,6 +2050,11 @@ asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+at-least-node@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
+ integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
+
atob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a"
@@ -2155,7 +2212,7 @@ base-x@^3.0.2:
dependencies:
safe-buffer "^5.0.1"
-base64-js@^1.0.2, base64-js@^1.3.1:
+base64-js@^1.0.2, base64-js@^1.3.1, base64-js@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
@@ -2178,6 +2235,11 @@ bcrypt-pbkdf@^1.0.0:
dependencies:
tweetnacl "^0.14.3"
+big-integer@^1.6.44:
+ version "1.6.52"
+ resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85"
+ integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==
+
big.js@^3.1.3:
version "3.2.0"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
@@ -2237,6 +2299,13 @@ boxen@^1.2.1:
term-size "^1.2.0"
widest-line "^2.0.0"
+bplist-parser@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e"
+ integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==
+ dependencies:
+ big-integer "^1.6.44"
+
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -2266,6 +2335,13 @@ braces@^2.2.2, braces@^2.3.1, braces@^2.3.2:
split-string "^3.0.2"
to-regex "^3.0.1"
+braces@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
+ integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
+ dependencies:
+ fill-range "^7.1.1"
+
braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
@@ -2707,6 +2783,30 @@ check-error@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
+cheerio-select@^1.5.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-1.6.0.tgz#489f36604112c722afa147dedd0d4609c09e1696"
+ integrity sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g==
+ dependencies:
+ css-select "^4.3.0"
+ css-what "^6.0.1"
+ domelementtype "^2.2.0"
+ domhandler "^4.3.1"
+ domutils "^2.8.0"
+
+cheerio@1.0.0-rc.10:
+ version "1.0.0-rc.10"
+ resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.10.tgz#2ba3dcdfcc26e7956fc1f440e61d51c643379f3e"
+ integrity sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==
+ dependencies:
+ cheerio-select "^1.5.0"
+ dom-serializer "^1.3.2"
+ domhandler "^4.2.0"
+ htmlparser2 "^6.1.0"
+ parse5 "^6.0.1"
+ parse5-htmlparser2-tree-adapter "^6.0.1"
+ tslib "^2.2.0"
+
chokidar@^2.1.8:
version "2.1.8"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
@@ -3175,6 +3275,95 @@ copy-to-clipboard@^3.3.1:
dependencies:
toggle-selection "^1.0.6"
+cordova-android@^10.1.2:
+ version "10.1.2"
+ resolved "https://registry.yarnpkg.com/cordova-android/-/cordova-android-10.1.2.tgz#3abfabb5fbc77dc3b90d7173c64cb2f8ad3d80df"
+ integrity sha512-F28+NvgKO4ZhKFkqctCOh62mhVoNyUuRQh/F/nqp+Sti4ODv2rUa6UeW18khhdYTjlDeihHQsPqxvB7mI6fVYA==
+ dependencies:
+ android-versions "^1.7.0"
+ cordova-common "^4.0.2"
+ execa "^5.1.1"
+ fast-glob "^3.2.7"
+ fs-extra "^10.0.0"
+ is-path-inside "^3.0.3"
+ nopt "^5.0.0"
+ properties-parser "^0.3.1"
+ semver "^7.3.5"
+ untildify "^4.0.0"
+ which "^2.0.2"
+
+cordova-common@^4.0.2:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/cordova-common/-/cordova-common-4.1.0.tgz#06058ea00e9dd0c635b6884617a0df81b3d89359"
+ integrity sha512-sYfOSfpYGQOmUDlsARUbpT/EvVKT/E+GI3zwTXt+C6DjZ7xs6ZQVHs3umHKSidjf9yVM2LLmvGFpGrGX7aGxug==
+ dependencies:
+ "@netflix/nerror" "^1.1.3"
+ ansi "^0.3.1"
+ bplist-parser "^0.2.0"
+ cross-spawn "^7.0.1"
+ elementtree "^0.1.7"
+ endent "^1.4.1"
+ fast-glob "^3.2.2"
+ fs-extra "^9.0.0"
+ glob "^7.1.6"
+ plist "^3.0.1"
+ q "^1.5.1"
+ read-chunk "^3.2.0"
+ strip-bom "^4.0.0"
+ underscore "^1.9.2"
+
+cordova-config@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/cordova-config/-/cordova-config-0.7.0.tgz#a1e6d2cacaa4c3c5e821840932832fe44e5448fb"
+ integrity sha512-3ZIXl0qAZypaQevZ2BUUDqrSF9I+mnikuO5e641s29KEKDhDIQMq4v/iPNoV0/fxOYgeCqPNnjwJFx4w+oGSQA==
+ dependencies:
+ elementtree "^0.1.6"
+ pify "^2.3.0"
+ pinkie-promise "^1.0.0"
+
+cordova-plugin-advanced-http@^3.3.1:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/cordova-plugin-advanced-http/-/cordova-plugin-advanced-http-3.3.1.tgz#903143a9aae3577cdbb6953fbe482902983b9237"
+ integrity sha512-hESuB3mxIHCUrzb5lm7juda6PSNcC5N8Invizj5wGV2rSldCapiNxMTEpzKR1UVPDDP2XOtBzO0SAYS+3+g/ig==
+
+cordova-plugin-androidx-adapter@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/cordova-plugin-androidx-adapter/-/cordova-plugin-androidx-adapter-1.1.3.tgz#aa7e673ee342de208a6a34a50986ee2ac4b5ba60"
+ integrity sha512-W1SImn0cCCvOSTSfWWp5TnanIQrSuh2Bch+dcZXIzEn0km3Qb7VryeAqHhgBQYwwzC5Ollk1DtUAk/AJSojuZA==
+ dependencies:
+ q "^1.5.1"
+ recursive-readdir "^2.2.2"
+
+cordova-plugin-backbutton@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/cordova-plugin-backbutton/-/cordova-plugin-backbutton-0.3.0.tgz#752fd68fff83d3917ae1eff6de2cd50fcce024e3"
+ integrity sha512-vPQQ8SZk2LcNP89sFVnZkFN3GChERSaxO1UlS2O+a86qUJZpzBgA+21C978wo/w43tk1+JDbzEw+PTIbYcex5w==
+
+cordova-plugin-badge@^0.8.9:
+ version "0.8.9"
+ resolved "https://registry.yarnpkg.com/cordova-plugin-badge/-/cordova-plugin-badge-0.8.9.tgz#c3b91e12ce18a51e42ede46763978583ed6c6d55"
+ integrity sha512-oVv+z3B7Jgi7/gnE/jvSnjBsBNwZVoLmJYwTUw3nLmp50fnY22H7NWthTachEdle2EljDk8AzvhuDpdf0triIw==
+
+cordova-plugin-device@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cordova-plugin-device/-/cordova-plugin-device-3.0.0.tgz#e70d6def715629f62b96c1e0ee5a1299e96b1341"
+ integrity sha512-g8fFYOvleeYpklWvHwZ/T8/IzJe/3O0MGVDIUoqBru4v8SNDAbNVD3oOqoOQANBWGFQMg7GIkAAl8errCHZ7zQ==
+
+cordova-plugin-file@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/cordova-plugin-file/-/cordova-plugin-file-7.0.0.tgz#40e72468e09439c402c81ff063d6ee74fffd763a"
+ integrity sha512-mSwy9GE5pHq2ZHhu/wYk/VhrwR5VLk+XQsk3+IiiFmDgcPsrVIyELkM2FZKX09cC6i+bJVTFVKUlwteSStj3ow==
+
+cordova-plugin-native-logs@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/cordova-plugin-native-logs/-/cordova-plugin-native-logs-1.0.5.tgz#43665b44de2f613d381bdc9352d53e4edd0890cb"
+ integrity sha512-X+l78oqw1U+eZoBF1nikRSa1vUlWw8QzNRPQWQ4VHFfjPUsfC0uvoDr2Spgn0tuUe+0kJ0ovRNeVpgWWb5LN2A==
+
+cordova-plugin-splashscreen@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/cordova-plugin-splashscreen/-/cordova-plugin-splashscreen-6.0.2.tgz#2151ee7256fbd64f07a84951854687855c56856f"
+ integrity sha512-7JiUfnInir+SCOEgTJ+5/cHF3UFl69jp6cAQfHtJaaQt9Pli8D8yTJjU0HGlJCvryvsVs4Xlc7/sEJM7vLJgvg==
+
core-js-compat@^3.18.0, core-js-compat@^3.19.0:
version "3.19.1"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.19.1.tgz#fe598f1a9bf37310d77c3813968e9f7c7bb99476"
@@ -3440,6 +3629,17 @@ css-select@^4.1.3:
domutils "^2.6.0"
nth-check "^2.0.0"
+css-select@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"
+ integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==
+ dependencies:
+ boolbase "^1.0.0"
+ css-what "^6.0.1"
+ domhandler "^4.3.1"
+ domutils "^2.8.0"
+ nth-check "^2.0.1"
+
css-selector-tokenizer@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86"
@@ -3483,6 +3683,11 @@ css-what@^5.0.0:
resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad"
integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==
+css-what@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
+ integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
+
cssesc@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
@@ -3730,6 +3935,11 @@ decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
+dedent@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
+ integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==
+
deep-eql@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
@@ -3947,6 +4157,15 @@ dom-serializer@^1.0.1:
domhandler "^4.2.0"
entities "^2.0.0"
+dom-serializer@^1.3.2:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
+ integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==
+ dependencies:
+ domelementtype "^2.0.1"
+ domhandler "^4.2.0"
+ entities "^2.0.0"
+
domain-browser@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
@@ -3988,6 +4207,13 @@ domhandler@^4.0.0, domhandler@^4.2.0:
dependencies:
domelementtype "^2.2.0"
+domhandler@^4.3.1:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
+ integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
+ dependencies:
+ domelementtype "^2.2.0"
+
domready@1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/domready/-/domready-1.0.8.tgz#91f252e597b65af77e745ae24dd0185d5e26d58c"
@@ -4010,6 +4236,15 @@ domutils@^2.5.2, domutils@^2.6.0:
domelementtype "^2.2.0"
domhandler "^4.2.0"
+domutils@^2.8.0:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
+ integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
+ dependencies:
+ dom-serializer "^1.0.1"
+ domelementtype "^2.2.0"
+ domhandler "^4.2.0"
+
dont-sniff-mimetype@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58"
@@ -4129,6 +4364,13 @@ electron-to-chromium@^1.3.896:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.898.tgz#0bd4090bf7c7003cb9bd31c4223a9f6aa1aab9dc"
integrity sha512-dxEsaHy9Ter268LO7P8uWomuChbyML4zZk5F9+UZSozFRS7ggC5cQ8fPIM8Pec+6uWGdujuDagQhIbqjohUK2w==
+elementtree@^0.1.6, elementtree@^0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/elementtree/-/elementtree-0.1.7.tgz#9ac91be6e52fb6e6244c4e54a4ac3ed8ae8e29c0"
+ integrity sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==
+ dependencies:
+ sax "1.1.4"
+
elliptic@^6.0.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
@@ -4177,6 +4419,15 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"
+endent@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/endent/-/endent-1.4.1.tgz#c58cc13dfc432d0b2c7faf74c13ffdca60b2d1c8"
+ integrity sha512-buHTb5c8AC9NshtP6dgmNLYkiT+olskbq1z6cEGvfGCF3Qphbu/1zz5Xu+yjTDln8RbxNhPoUyJ5H8MSrp1olQ==
+ dependencies:
+ dedent "^0.7.0"
+ fast-json-parse "^1.0.3"
+ objectorarray "^1.0.4"
+
enhanced-resolve@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz#e34a6eaa790f62fccd71d93959f56b2b432db10a"
@@ -4581,6 +4832,21 @@ execa@^0.8.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
+execa@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
+ integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
+ dependencies:
+ cross-spawn "^7.0.3"
+ get-stream "^6.0.0"
+ human-signals "^2.1.0"
+ is-stream "^2.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^4.0.1"
+ onetime "^5.1.2"
+ signal-exit "^3.0.3"
+ strip-final-newline "^2.0.0"
+
exenv@^1.2.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
@@ -4648,6 +4914,11 @@ extsprintf@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
+extsprintf@^1.4.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07"
+ integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==
+
fast-deep-equal@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
@@ -4661,6 +4932,22 @@ fast-deep-equal@^3.1.1:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+fast-glob@^3.2.2, fast-glob@^3.2.7:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
+ integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.2"
+ merge2 "^1.3.0"
+ micromatch "^4.0.4"
+
+fast-json-parse@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/fast-json-parse/-/fast-json-parse-1.0.3.tgz#43e5c61ee4efa9265633046b770fb682a7577c4d"
+ integrity sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==
+
fast-json-stable-stringify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
@@ -4673,6 +4960,13 @@ fastparse@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
+fastq@^1.6.0:
+ version "1.17.1"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47"
+ integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==
+ dependencies:
+ reusify "^1.0.4"
+
fbjs-css-vars@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8"
@@ -4750,6 +5044,13 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
+fill-range@^7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
+ integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
+ dependencies:
+ to-regex-range "^5.0.1"
+
find-cache-dir@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f"
@@ -4949,6 +5250,15 @@ fs-extra@^0.30.0:
path-is-absolute "^1.0.0"
rimraf "^2.2.8"
+fs-extra@^10.0.0:
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
+ integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
+ dependencies:
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
+
fs-extra@^10.0.1:
version "10.0.1"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.1.tgz#27de43b4320e833f6867cc044bfce29fdf0ef3b8"
@@ -4958,6 +5268,16 @@ fs-extra@^10.0.1:
jsonfile "^6.0.1"
universalify "^2.0.0"
+fs-extra@^9.0.0:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
+ integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
+ dependencies:
+ at-least-node "^1.0.0"
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
+
fs-minipass@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
@@ -5106,6 +5426,11 @@ get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
+get-stream@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
+ integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
+
get-symbol-description@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6"
@@ -5140,7 +5465,7 @@ glob-parent@^3.1.0:
is-glob "^3.1.0"
path-dirname "^1.0.0"
-glob-parent@~5.1.0, glob-parent@~5.1.2:
+glob-parent@^5.1.2, glob-parent@~5.1.0, glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
@@ -5170,6 +5495,18 @@ glob@^7.1.3, glob@^7.1.4, glob@~7.1.1:
once "^1.3.0"
path-is-absolute "^1.0.0"
+glob@^7.1.6:
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+ integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.1.1"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
glob@^8.0.1:
version "8.1.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e"
@@ -5211,6 +5548,9 @@ globule@^1.0.0:
lodash "^4.17.21"
minimatch "~3.0.2"
+"gls-blogs-native-core@file:native_core":
+ version "1.0.0"
+
golos-dex-lib-js@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/golos-dex-lib-js/-/golos-dex-lib-js-1.0.2.tgz#e0fe5d29781da8d0830ccb6bcfa5386bc73a2c5d"
@@ -5706,6 +6046,11 @@ https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1:
agent-base "6"
debug "4"
+human-signals@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
+ integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
+
humanize-ms@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
@@ -6222,6 +6567,11 @@ is-path-inside@^1.0.0:
dependencies:
path-is-inside "^1.0.1"
+is-path-inside@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+ integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
is-plain-obj@^1.1, is-plain-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
@@ -6289,6 +6639,11 @@ is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+is-stream@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
+ integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
+
is-string@^1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f"
@@ -7295,6 +7650,16 @@ merge-options@1.0.1, merge-options@^1.0.0, merge-options@^1.0.1:
dependencies:
is-plain-obj "^1.1"
+merge-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+ integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
+
+merge2@^1.3.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
methods@^1.0.1, methods@~1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
@@ -7336,6 +7701,14 @@ micromatch@^3.1.10, micromatch@^3.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.2"
+micromatch@^4.0.4:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
+ integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
+ dependencies:
+ braces "^3.0.3"
+ picomatch "^2.3.1"
+
miller-rabin@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
@@ -7365,6 +7738,11 @@ mimic-fn@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
+mimic-fn@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+ integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+
min-indent@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
@@ -7391,6 +7769,13 @@ minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
dependencies:
brace-expansion "^1.1.7"
+minimatch@^3.0.5, minimatch@^3.1.1:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+ dependencies:
+ brace-expansion "^1.1.7"
+
minimatch@^5.0.1, minimatch@~5.1.2:
version "5.1.6"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
@@ -8004,6 +8389,13 @@ npm-run-path@^2.0.0:
dependencies:
path-key "^2.0.0"
+npm-run-path@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
+ integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
+ dependencies:
+ path-key "^3.0.0"
+
npmlog@^4.0.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
@@ -8037,6 +8429,13 @@ nth-check@^2.0.0:
dependencies:
boolbase "^1.0.0"
+nth-check@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
+ integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
+ dependencies:
+ boolbase "^1.0.0"
+
num2fraction@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
@@ -8171,6 +8570,11 @@ object.values@^1.1.0:
define-properties "^1.1.3"
es-abstract "^1.19.1"
+objectorarray@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/objectorarray/-/objectorarray-1.0.5.tgz#2c05248bbefabd8f43ad13b41085951aac5e68a5"
+ integrity sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==
+
on-finished@^2.1.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
@@ -8189,6 +8593,13 @@ onetime@^2.0.0:
dependencies:
mimic-fn "^1.0.0"
+onetime@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
+ integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
+ dependencies:
+ mimic-fn "^2.1.0"
+
only@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4"
@@ -8296,7 +8707,7 @@ p-try@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
-p-try@^2.0.0:
+p-try@^2.0.0, p-try@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
@@ -8371,10 +8782,22 @@ parse-srcset@^1.0.2:
resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1"
integrity sha1-8r0iH2zJcKk42IVWq8WJyqqiveE=
+parse5-htmlparser2-tree-adapter@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6"
+ integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==
+ dependencies:
+ parse5 "^6.0.1"
+
parse5@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
+parse5@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
+ integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
+
parse5@^7.1.1:
version "7.1.2"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32"
@@ -8431,7 +8854,7 @@ path-key@^2.0.0, path-key@^2.0.1:
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
-path-key@^3.1.0:
+path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
@@ -8496,12 +8919,12 @@ picomatch@^2.0.4, picomatch@^2.2.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
-picomatch@^2.3.0:
+picomatch@^2.3.0, picomatch@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
-pify@^2.0.0:
+pify@^2.0.0, pify@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@@ -8514,12 +8937,24 @@ pify@^4.0.1:
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
+pinkie-promise@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-1.0.0.tgz#d1da67f5482563bb7cf57f286ae2822ecfbf3670"
+ integrity sha512-5mvtVNse2Ml9zpFKkWBpGsTPwm3DKhs+c95prO/F6E7d6DN0FPqxs6LONpLNpyD7Iheb7QN4BbUoKJgo+DnkQA==
+ dependencies:
+ pinkie "^1.0.0"
+
pinkie-promise@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
dependencies:
pinkie "^2.0.0"
+pinkie@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-1.0.0.tgz#5a47f28ba1015d0201bda7bf0f358e47bec8c7e4"
+ integrity sha512-VFVaU1ysKakao68ktZm76PIdOhvEfoNNRaGkyLln9Os7r0/MCxqHjHyBM7dT3pgTiBybqiPtpqKfpENwdBp50Q==
+
pinkie@^2.0.0:
version "2.0.4"
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
@@ -8561,6 +8996,15 @@ platform@1.3.5:
version "1.3.5"
resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.5.tgz#fb6958c696e07e2918d2eeda0f0bc9448d733444"
+plist@^3.0.1:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/plist/-/plist-3.1.0.tgz#797a516a93e62f5bde55e0b9cc9c967f860893c9"
+ integrity sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==
+ dependencies:
+ "@xmldom/xmldom" "^0.8.8"
+ base64-js "^1.5.1"
+ xmlbuilder "^15.1.1"
+
plur@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/plur/-/plur-3.0.1.tgz#268652d605f816699b42b86248de73c9acd06a7c"
@@ -9107,6 +9551,13 @@ prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
object-assign "^4.1.1"
react-is "^16.8.1"
+properties-parser@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/properties-parser/-/properties-parser-0.3.1.tgz#1316e9539ffbfd93845e369b211022abd478771a"
+ integrity sha512-AkSQxQAviJ89x4FIxOyHGfO3uund0gvYo7lfD0E+Gp7gFQKrTNgtoYQklu8EhrfHVZUzTwKGZx2r/KDSfnljcA==
+ dependencies:
+ string.prototype.codepointat "^0.2.0"
+
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@@ -9169,7 +9620,7 @@ punycode@^2.1.0, punycode@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
-q@^1.1.2:
+q@^1.1.2, q@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
@@ -9208,6 +9659,11 @@ querystringify@^2.1.1:
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==
+queue-microtask@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
quick-lru@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8"
@@ -9520,6 +9976,14 @@ react@^18.2.0:
dependencies:
loose-envify "^1.1.0"
+read-chunk@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-3.2.0.tgz#2984afe78ca9bfbbdb74b19387bf9e86289c16ca"
+ integrity sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ==
+ dependencies:
+ pify "^4.0.1"
+ with-open-file "^0.1.6"
+
read-pkg-up@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
@@ -9629,6 +10093,13 @@ rechoir@^0.6.2:
dependencies:
resolve "^1.1.6"
+recursive-readdir@^2.2.2:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.3.tgz#e726f328c0d69153bcabd5c322d3195252379372"
+ integrity sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==
+ dependencies:
+ minimatch "^3.0.5"
+
redent@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa"
@@ -9968,6 +10439,11 @@ retry@^0.12.0:
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==
+reusify@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
rgb-regex@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1"
@@ -10022,6 +10498,13 @@ run-async@^2.2.0:
dependencies:
is-promise "^2.1.0"
+run-parallel@^1.1.9:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+ dependencies:
+ queue-microtask "^1.2.2"
+
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"
@@ -10098,6 +10581,11 @@ sass-loader@6.0.6:
lodash.tail "^4.1.1"
pify "^3.0.0"
+sax@1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.4.tgz#74b6d33c9ae1e001510f179a91168588f1aedaa9"
+ integrity sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==
+
sax@^1.2.4, sax@~1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
@@ -10211,6 +10699,11 @@ semver@^7.3.4, semver@^7.3.5:
dependencies:
lru-cache "^6.0.0"
+semver@^7.5.2:
+ version "7.6.3"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
+ integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
+
sentence-case@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-1.1.3.tgz#8034aafc2145772d3abe1509aa42c9e1042dc139"
@@ -10339,7 +10832,7 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
-signal-exit@^3.0.7:
+signal-exit@^3.0.3, signal-exit@^3.0.7:
version "3.0.7"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
@@ -10680,6 +11173,11 @@ string-width@^1.0.1:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
+string.prototype.codepointat@^0.2.0:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz#004ad44c8afc727527b108cd462b4d971cd469bc"
+ integrity sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==
+
string.prototype.trimend@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80"
@@ -10732,10 +11230,20 @@ strip-bom@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+strip-bom@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878"
+ integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==
+
strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
+strip-final-newline@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+ integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+
strip-indent@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
@@ -11185,6 +11693,11 @@ tslib@^1.10.0, tslib@^1.9.3:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+tslib@^2.2.0:
+ version "2.8.1"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
+ integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
+
tslib@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e"
@@ -11337,6 +11850,11 @@ underscore.string@^3.3.5:
sprintf-js "^1.0.3"
util-deprecate "^1.0.2"
+underscore@^1.9.2:
+ version "1.13.7"
+ resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.7.tgz#970e33963af9a7dda228f17ebe8399e5fbe63a10"
+ integrity sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==
+
unicode-canonical-property-names-ecmascript@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc"
@@ -11449,6 +11967,11 @@ unset-value@^1.0.0:
has-value "^0.3.1"
isobject "^3.0.0"
+untildify@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
+ integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
+
unzip-response@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
@@ -11789,11 +12312,13 @@ webpack-log@^1.0.1, webpack-log@^1.1.1, webpack-log@^1.1.2:
loglevelnext "^1.0.1"
uuid "^3.1.0"
-webpack-merge@^4.1.2:
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.3.tgz#8aaff2108a19c29849bc9ad2a7fd7fce68e87c4a"
+webpack-merge@5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.2.0.tgz#31cbcc954f8f89cd4b06ca8d97a38549f7f3f0c9"
+ integrity sha512-QBglJBg5+lItm3/Lopv8KDDK01+hjdg2azEwi/4vKJ8ZmGPdtJsTpjtNNOW3a4WiqzXdCATtTudOZJngE7RKkA==
dependencies:
- lodash "^4.17.5"
+ clone-deep "^4.0.1"
+ wildcard "^2.0.0"
webpack-serve@^1.0.4:
version "1.0.4"
@@ -11986,10 +12511,24 @@ widest-line@^2.0.0:
dependencies:
string-width "^2.1.1"
+wildcard@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67"
+ integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==
+
window-size@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+with-open-file@^0.1.6:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/with-open-file/-/with-open-file-0.1.7.tgz#e2de8d974e8a8ae6e58886be4fe8e7465b58a729"
+ integrity sha512-ecJS2/oHtESJ1t3ZfMI3B7KIDKyfN0O16miWxdn30zdh66Yd3LsRFebXZXq6GU4xfxLf6nVxp9kIqElb5fqczA==
+ dependencies:
+ p-finally "^1.0.0"
+ p-try "^2.1.0"
+ pify "^4.0.1"
+
wordwrap@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
@@ -12072,6 +12611,11 @@ xml-name-validator@^4.0.0:
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835"
integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==
+xmlbuilder@^15.1.1:
+ version "15.1.1"
+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5"
+ integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==
+
xmlchars@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"