diff --git a/.flake8 b/.flake8
deleted file mode 100644
index f443307f3..000000000
--- a/.flake8
+++ /dev/null
@@ -1,18 +0,0 @@
-[flake8]
-select =
- E772,
- F401,
- F811,
- E901,
- E999,
- F821,
- F822,
- F823,
- C901, # complexity
- E501, # line length
- E225 # whitespace around operators
-max_complexity = 70
-max_line_length = 200
-show_source = True
-statistics = True
-count = True
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 000000000..3a7361388
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,5 @@
+# These are supported funding model platforms
+
+github: 'jarrodnorwell'
+ko_fi: 'antiquecodes'
+custom: ['buymeacoffee.com/jarrodnorwell', 'paypal.me/officialantique']
\ No newline at end of file
diff --git a/.github/issue_template.md b/.github/issue_template.md
deleted file mode 100644
index d751a6f4b..000000000
--- a/.github/issue_template.md
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-## Expected Behavior
-
-## Current Behavior
-
-## Possible Solution (optional)
-
-## InstaPy configuration
-
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
deleted file mode 100644
index f16b91b00..000000000
--- a/.github/pull_request_template.md
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-# Pull Request Template
-
-## Description
-
-Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
-
-Do not include any personal data.
-
-Fixes # (issue)
-
-## How Has This Been Tested?
-
-Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.
-
-- [ ] Test
-
-## Checklist:
-
-- [ ] I have commented my code, particularly in hard-to-understand areas
-- [ ] I have made corresponding changes to the documentation
-- [ ] I have checked my code and corrected any misspellings
-- [ ] I have performed a self-review of my own code
-- [ ] My code follows the style guidelines of this project, `black -t py34`
-- [ ] My changes generate no new warnings
diff --git a/.github/stale.yml b/.github/stale.yml
deleted file mode 100644
index 56ca70eda..000000000
--- a/.github/stale.yml
+++ /dev/null
@@ -1,58 +0,0 @@
-# Configuration for probot-stale - https://github.com/probot/stale
-
- # Number of days of inactivity before an Issue or Pull Request becomes stale
- daysUntilStale: 30
-
- # Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
- # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
- daysUntilClose: 7
-
- # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
- exemptLabels:
- - pinned
- - security
- - bounty
- - feature request
-
- # Set to true to ignore issues in a project (defaults to false)
- exemptProjects: false
-
- # Set to true to ignore issues in a milestone (defaults to false)
- exemptMilestones: false
-
- # Label to use when marking as stale
- staleLabel: wontfix
-
- # Comment to post when marking as stale. Set to `false` to disable
- markComment: >
- This issue has been automatically marked as stale because it has not had
- recent activity. It will be closed if no further activity occurs. Thank you
- for your contributions.
-
- > If this problem still occurs, please open a new issue
-
- # Comment to post when removing the stale label.
- # unmarkComment: >
- # Your comment here.
-
- # Comment to post when closing a stale Issue or Pull Request.
- # closeComment: >
- # Your comment here.
-
- # Limit the number of actions per hour, from 1-30. Default is 30
- limitPerRun: 30
-
- # Limit to only `issues` or `pulls`
- only: issues
-
- # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
- # pulls:
- # daysUntilStale: 30
- # markComment: >
- # This pull request has been automatically marked as stale because it has not had
- # recent activity. It will be closed if no further activity occurs. Thank you
- # for your contributions.
-
- # issues:
- # exemptLabels:
- # - confirmed
diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
deleted file mode 100644
index c767c60b3..000000000
--- a/.github/workflows/docs.yaml
+++ /dev/null
@@ -1,27 +0,0 @@
-name: GitHub Pages
-
-on:
- push:
- branches: [master]
-
-jobs:
- build-and-deploy:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v2
- - uses: actions/setup-node@v2
- with:
- node-version: 14.x
- - name: Install and Build
- run: |
- cd docusaurus
- yarn install
- yarn build
-
- - name: Deploy
- uses: JamesIves/github-pages-deploy-action@4.1.4
- with:
- branch: gh-pages
- folder: docusaurus/build
- clean: true
diff --git a/.github/workflows/pypi.yaml b/.github/workflows/pypi.yaml
deleted file mode 100644
index 5d9d73579..000000000
--- a/.github/workflows/pypi.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-name: PyPi
-
-on:
- push:
- tags: ["*"]
-
-jobs:
- build:
- runs-on: ubuntu-latest
- name: Deploy to PyPi
- steps:
- - uses: actions/checkout@v2
- - name: Setup python
- uses: actions/setup-python@v2
- with:
- python-version: 3.x
- - name: Install requirements
- run: |
- pip install --upgrade pip sdist wheel
- pip install -r requirements.txt
- - name: Build the package
- run: python setup.py sdist bdist_wheel
- - name: Publish package
- if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
- uses: pypa/gh-action-pypi-publish@release/v1
- with:
- user: __token__
- password: ${{ secrets.PYPI_TOKEN }}
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
deleted file mode 100644
index 14d7a10ca..000000000
--- a/.github/workflows/tests.yaml
+++ /dev/null
@@ -1,40 +0,0 @@
-name: Tests
-
-on: [push, pull_request]
-
-jobs:
- pytest:
- runs-on: ${{ matrix.os }}
- strategy:
- matrix:
- os: [ubuntu-latest, macos-latest]
- python-version: [3.6, 3.7, 3.8, 3.9, 3.x]
- name: ${{ matrix.os }} Python ${{ matrix.python-version }} Test
- steps:
- - uses: actions/checkout@v2
- - name: Setup python
- uses: actions/setup-python@v2
- with:
- python-version: ${{ matrix.python-version }}
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip pytest
- pip install -r requirements.txt
- - run: python -m pytest
-
- lint:
- runs-on: ${{ matrix.os }}
- strategy:
- matrix:
- os: [ubuntu-latest]
- name: ${{ matrix.os }} Python ${{ matrix.python-version }} Linting
- steps:
- - uses: actions/checkout@v2
- - name: Setup python
- uses: actions/setup-python@v2
- with:
- python-version: 3.x
- - name: Install dependencies
- run: python -m pip install --upgrade pip black flake8
- - run: flake8 .
- - run: black -t py34 --check .
diff --git a/.gitignore b/.gitignore
index 14d9fb282..6575fd442 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,121 +1,6 @@
-# pylint file
-googlecl-pylint.rc.txt
-assets/chromedriver
-
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-quickstart.py
-docker_quickstart.py
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-env/
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-*.egg-info/
-.installed.cfg
-*.egg
-
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*,cover
-.hypothesis/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
-
-# IPython Notebook
-.ipynb_checkpoints
-
-# pyenv
-.python-version
-
-# celery beat schedule file
-celerybeat-schedule
-
-# dotenv
-.env
-
-# virtualenv
-venv/
-.venv/
-ENV/
-
-# Spyder project settings
-.spyderproject
-
-# Rope project settings
-.ropeproject
-
-# Mac files
-.DS_Store
-
-# Storage
-*.db
-logs/
-
-# Editors
-.idea
.vscode
-*.code-workspace
-.bak
-
-# pytest
-.pytest_cache/
-tests/logs
-
-# Pipfile
-Pipfile
-Pipfile.lock
-# Instances
-z_*
+build
+dist
+InstaPy2/src/instapy2.egg-info
+test
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index 0fed184e2..000000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,789 +0,0 @@
-# Changelog
-
-The **goal** of this file is explaining to the users of our project the notable changes _relevant to them_ that occurred _between_ commits.
-
-_The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)_
-
-## [0.6.17] - 2022-01-19 - [Unreleased]
-
-### Fixed
-
-- Fixed project homepage to [InstaPy](https://github.com/InstaPy/InstaPy)
-
-## [0.6.16] - 2021-12-11
-
-### Added
-
-- Added filter in `extract_text_from_element()` for non-username elements.
-
-### Fixed
-
-- Fixed `is_private_profile()` when 'NoneType' object is not subscriptable
-- Fixed `find_element*()` to `find_element()`
-
-## [0.6.16] - 2021-12-11
-
-### Added
-
-- Added filter in `extract_text_from_element()` for non-username elements.
-
-### Fixed
-
-- Fixed `is_private_profile()` when 'NoneType' object is not subscriptable
-- Fixed `find_element*()` to `find_element()`
-
-## [0.6.15] - 2021-12-02
-
-### Fixed
-
-- Fixed `relationship_tools` to check if not `username == self_username`
-
-## [0.6.14] - 2021-10-18
-
-### Added
-
-- Added delays after load cookie in login.util.py
-- Added `apidisplaypurposes about` in `smart_hashtags` and new api token; Python3.5
-- Added `interact_user_likers` interacting with the likers from a given user's posts
-- Added second `accept_igcookie_dialogue` to handled the second "cookie accept screen" that is not automatically accepted
-- Added delays after `update_activity()` in `follow_util.py` and `util.py`
-- Added extra trace in `get_followers()`
-- Added `verified_only` argument to `get_followers` to return only verified users
-- `mandatory_bio_keywords` control before evaluating for mandatory
-- Fix user following and verification of follow
-- Skipping of public account with (optional) percentage
-
-### Fixed
-
-- Move call to `get_following_status` above `web_address_navigator` inside `get_links_for_username` function
-- Fixed the correct URL `displaypurposes.com`, the old `displaypurposes.com` API is deprecated
-- Fixed `additional-information.md`, removed extra info for `cron` configuration
-- Fixed `actions.md` and `settings.md` for identation
-- Fixed getting additional data from page source
-- Fixed xpath for when images cannot be detected
-- Fixed empty shared data
-- Cannot detect post media type
-- Updated xpath Image "Like" and "Unlike"
-
-### Changed
-
-- Change the ip data supplier to from
-
-## [0.6.13] - 2020-12-30
-
-### Added
-
-- Handle situation if stale elements detected when cookie cannot be loaded
-- Convert Documentation to Docusaurus
-- Check if user's account is private
-- Added informational message when videos found instead of images in `likers_from_photo`
-- Two Factor Authentication check when acct is protected
-- Added Pull Request Template
-- Added function `accept_igcookie_dialogue` that clicks accept at IG cookie dialogue
-- Added `comment_liked_photo` to `set_do_comment` to be able to comment twice a photo that is already liked; deactivated by default
-
-### Fixed
-
-- Fixed typo in message when a video is tried to like.
-- Fixed the problem where `followers_list` could be used without being initialized.
-- Fixed incorrect xpath used by `interact_by_comments`
-- Fixed typo in `dissmiss_save_information` to `dismiss_save_information`
-- Fixed `get_followers` return for empty list
-- Fixed xpath for `likers_from_photo`
-- Changed windows size to `iPhone XS Max: 414, 896`
-- Fixed `process_comments` where some comments used the InstaPy user
-- Updated `user_agent` profile to be the same for the bot session
-- Fixed required `sameSite:Strict` parameter in browser cookie session
-- Fixed `login_session` for issues when cookie cannot be loaded
-- Fixed `likes_dialog_close_xpath` to generic format
-- Fixed `validate_username` to navigate user profile to read their Bio
-- Fixed `Liked button now found, might be a video` that could be floodig general log
-- Fixed `logger.warn` to `logger.warning` as default warning in Python
-- Fixed xpath for `watch_story`
-
-## [0.6.12] - 2020-10-26
-
-### Added
-
-- Defined local variables ( ie: 'unfollow_state') to fix message for referenced before assignment
-- *.code-workspace in .gitignore for vscode project (macOS)
-- `like_by_locations()` with randomize flag
-- Added firefox_options.log.level = geckodriver_log_level for debugging
-- `dissmiss_save_information` in `login_user()`
-- new path used in login_util.py
-- information for geckodriver_log_level, development only
-
-### Changed
-
-- check if liking activity was blocked after every like
-- Call scroll_down() after follower accepted, with this new def the window is scrolled down after accepting a follower.
-- Sorted imports, to make code readable
-- Modified followed.txt log to append information
-- `like_image` now needs to handle images and videos
-- Imports were ordered
-- `like_by_feed` limits from 100 to 50
-
-### Fixed
-
-- fixed some comments were double quotes were not necessary
-- issue where `getTitle` was timing out
-- `get_users_through_dialog_with_graphql` with a new try/except
-
-## [0.6.11] - 2020-09-25
-
-### Added
-
-- Use random tag list for `session.like_by_tags`
-
-### Changed
-
-- General log rotation, gecko driver log in user directory, comments in 80 chars
-
-### Fixed
-
-- Unfollowing of users that haven't posted anything
-- `get_links` xpath for yet another change
-- Path for Obtaining user id
-- `like_util.py` list index out of range error
-- `like_by_feed()` method
-- `follow_user_following
-- processing unexpected alert error on resize
-
-## [0.6.10] - 2020-07-30
-
-### Added
-
-- Generallize mandatory words and add mandatory_bio_keywords
-
-### Changed
-
-- Update xpath for like/unlike and comment
-- Fix `like_by_feed()` xpath
-- `get_like_on_feed()` improve function readability
-
-### Fixed
-
-- "UnboundLocalError: local variable 'commenting_approved' referenced before assignment" error when bot tries to comment
-- Typo updating configuration object. Changed nofity into notify
-- Add specific firefox preference agent data to prevent error
-- Smart location url
-- Error "Hide Selenium Extension: Error" mentioned in #5304
-- XPATH for like svg
-
-## [0.6.9] - 2020-06-12
-
-### Added
-
-- Additional parameter `browser_executable_path` now available when initializing InstaPy. Use it to run a specific installation of Firefox.
-- A new feature - `target_list()` to parse text files containing target lists of users, hashtags etc.
-
-### Changed
-
-- Remove `view-source` which stops bot from proceeding
-- Remove instagram status check
-
-## [0.6.8] - 2020-01-28
-
-### Fixed
-
-- xPath for breaking LIKE and COMMENT
-
-## [0.6.7] - 2020-01-05
-
-### Fixed
-
-- Adjusted follow xPath
-
-## [0.6.6] - 2019-11-11
-
-### Changed
-
-- Additional web checks default `False` to avoid erros on runtime
-
-## [0.6.5] - 2019-10-20
-
-### Added
-
-- Additional CLI-Argument for connection checks
-
-### Changed
-
-- Post types now as Enum in separate file
-
-### Fixed
-
-- Internet connection checks
-- Small typos in documentation
-- Firefox Proxy error
-
-## [0.6.4] - 2019-09-15
-
-### Fixed
-
-- prettyfied code
-- fixed onetap account page on login
-- fix minor bug in unfollow function
-
-## [0.6.3] - 2019-09-08
-
-### Added
-
-- Improved documentation
-- Added "no_comments" for Pods
-- Improved Tox / Travis testing
-- Improved random sleep delay
-- Telegram support
-
-### Fixed
-
-- Able to use Domains as a Proxy
-- jsonschema requrements version
-- skip_top_posts function
-- Backup plan for graphql additional / shared data
-
-## [0.6.2] - 2019-08-30
-
-### Added
-
-- New bypass challenge approach (choose sms or email option)
-- Show InstaPy version on initialization
-
-### Fixed
-
-- Login xpath update
-
-## [0.6.1] - 2019-08-12
-
-### Added
-
-- Add log information about the non-working feature (unfollow with All Following option enabled)
-
-### Fixed
-
-- Fix an issue with screen shot file creation
-- Fix an issue with JSON file state creation
-- Fix Get Query Hash function to work on all Python 3.x versions
-- Fix Unfollow with option nonFollowers
-
-## [0.6.0] - 2019-08-12
-
-### Added
-
-- Firefox Extension which hides Selenium
-- Black code formatter
-- Mobile user agent
-- Mobile Mode to enable mobile features
-- Screen shots (rotative screen shots are taken and saved in your InstaPy user folder)
-- Connection State
-
-### Breaking Changes
-
-- removed chromedriver
-- signature changes:
- - set_action_delays(random_range) -> (random_range_from, random_range_to)
- - set_delemit_liking(max, min) ->(max_likes, min_likes)
- - set_delemit_commenting(max, min) ->(max_comments, min_comments)
- - unfollow_users(customList, instapyfollowed) -> (custom_list_enabled, custom_list, custom_list_param, instapy_followed_enabled, instapy_followed_param)
- - set*quota_supervisor(peak*_) ->(peak\_\_\_hourly, peak_\*\_daily)
-
-### Fixed
-
-- Fix follow_likers feature
-- Fix follow_user_followers
-- Fix comment_image feature
-- Update dont_unfollow_active_users to Mobile Mode
-- Fix scroll down (util) function
-- Remove bypass_by_mobile, it will auto detect the mobile if required now
-- Update profile scrapping to use GraphQL (get_users_through_dialog_with_graphql)
-
-## [0.5.8] - 2019-08-01
-
-### Added
-
-- skip user based on profile bio
-
-### Fixed
-
-- xpath error likers from photo
-
-## [0.5.7] - 2019-07-24
-
-### Fixed
-
-- user agent error in firefox
-
-## [0.5.6] - 2019-07-22
-
-### Fixed
-
-- xpath compile multiple errors
-
-### Added
-
-- feature watch stories
-- always use the lastest user-agent
-
-## [0.5.5] - 2019-07-11
-
-### Fixed
-
-- `get_action_delay` check for uninitialized delays in settings
-
-## [0.5.4] - 2019-07-03
-
-### Changed
-
-- Always start chromedriver with --no-sandbox to fix #4607
-
-### Fixed
-
-- `get_action_delay` method always returning default values #4540
-
-## [0.5.3] - 2019-07-02
-
-### Fixed
-
-- Argument Being Interpreted as Sequence in `bypass_suspicious_login`
-
-## [0.5.2] - 2019-06-28
-
-### Fixed
-
-- `session.get_relationship_counts()` broken behavior
-
-## [0.5.1] - 2019-06-18
-
-### Added
-
-- Documentation for basic Selenium Errors
-- Import `Settings` in docs
-
-### Fixed
-
-- `session.follow_user_following()` broken behavior
-
-## [0.5.0] - 2019-06-03
-
-### Added
-
-- Additional check for like block.
-
-### Changed
-
-- Remove support for python2
-- Information regarding the nogui parameter in documentation.
-- XPath Isolation
-- Remove redundant assignment of pod_post_ids
-- Remove address var assigned multiple times without intermediate usage
-- `set_mandatory_language` can maintain multiple character sets
-- Feature finetuning comments for pods
-
-### Fixed
-
-- Interact_by_comments aborts when self.abort is true
-- Media type filter (Photo, Video) in get_links
-- 'Failed to get comments' issue
-- Threaded session ending with exception `ValueError: signal only works in main thread`
-- `like_image` in dev has this arg
-- Verifying mandatory words when the script can not get post description
-- Codacy checks for unused var, out of scope, and missing args
-
-## [0.4.3] - 2019-05-15
-
-### Fixed
-
-- Commenting issue #4409
-
-## [0.4.2] - 2019-04-15
-
-### Fixed
-
-- Fail of whole pod run on exception
-
-## [0.4.1] - 2019-04-06
-
-### Added
-
-- Support for split database with -sdb flag to avoid SQLite lock up
-
-### Fixed
-
-- "Failed to find login button" when trying to login (add KEYS.ENTER to submit login data)
-
-## [0.4.0] - 2019-04-03
-
-### Added
-
-- Improved info provided by log messages in instapy.py and like_util.py
-- Possibility to skip non bussiness accounts
-
-### Changed
-
-- Remove docker from core, moved into instapy-docker repo
-- Remove quickstart templates and only reference instapy-quickstart
-- Restructure README and add new DOCUMENTATION file
-
-### Fixed
-
-- "UnboundLocalError: local variable 'tag' referenced before assignment" when there is no smart-hastag genereated
-- xPath to dialog_address
-
-## [0.3.4] - 2019-03-17
-
-### Added
-
-- (re) add page_reload, after cookie load, on login_user()
-
-### Fixed
-
-- "Failed to load desired amount of users" when trying to read long follower lists
-
-## [0.3.3] - 2019-03-14
-
-### Added
-
-- Add additional exception catch to Login check
-
-### Changed
-
-- Set language on the browser (no clicks required)
-
-### Fixed
-
-- Get_active_users hotfix
-
-## [0.3.2] - 2019-03-12
-
-### Fixed
-
-- Hot fix problems with browser abstraction class
-
-## [0.3.1] - 2019-03-12
-
-### Fixed
-
-- Removed retry decorator
-
-## [0.3.0] - 2019-03-11
-
-### Added
-
-- Allowing `follow_by_tags` to interact with the user
-- Context manager to interaction calls in `like_by_tags` and `follow_likers`
-- Engagement pods feature 🙌
-- Smart Hashtags based on locations `set_smart_location_hashtags`
-- Verify action for unfollow and follow actions
-- Browser abstraction and Decorator that handles Selenium Browser exceptions by reloading
-- Add delay unfollow of follow backers
-
-### Changed
-
-- Expose `threaded_session` of Instapy.end()
-
-### Fixed
-
-- `follow_likers` always fetches zero likers
-- Prevent division by zero in `validate_username`
-
-## [0.2.3] - 2019-03-01
-
-### Changed
-
-- Made Log in text checking more resilient
-
-## [0.2.2] - 2019-02-21
-
-### Fixed
-
-- Chromedriver requirement now >= 2.44 instead of == 2.44
-
-## [0.2.1] - 2019-02-21
-
-### Fixed
-
-- xPath for Log In button
-
-## [0.2.0] - 2019-02-18
-
-### Added
-
-- Accept pending follow requests for private account
-- Feature to `follow_by_locations`
-- Proxy Authentication support for Firefox
-
-### Fixed
-
-- Only import instapy-chromedriver package when needed
-- Avoid user errors providing user names with caps
-- Fix get_active_users wrong behavior on videos
-- Bug in _CLI_ **argparsing** - `proxy_port` & `page_delay` are integers and not strings.
-- Selectors for finding comments and liking comments on posts
-- Temporarily turn off follow for `like_by_tags` interaction
-
-### Changed
-
-- Enable users interact by the comments of their own profiles.
-- Moved elements from docs folder to instapy-docs and instapy-research repositories
-
-## [0.1.3] - 2019-02-05
-
-### Fixed
-
-- Fix "_Failed to load desired amount of users!_" issue.
-
-### Added
-
-- Add _Progress Tracker_ to `get_users_through_dialog()` function.
-- Add Proxy Authentication for Firefox
-
-## [0.1.2] - 2019-02-04
-
-### Fixed
-
-- Fix for scrollIntoView error.
-
-## [0.1.1] - 2019-02-04
-
-### Added
-
-- **Workspace** folders; Now user's data files will be stored at the **workspace** folder.
-- _InstaPy_ has been published to _PyPI_; Now, can install/manage it by **pip** as **instapy** package.
-- _Github_ releases has been initiated; Will be released in-parallel with _PyPI_ deployments.
-- Add Universal Testing Framework- **tox** with **pytest** & **flake8**.
-- Upgrade _Travis CI_ usage (_**tox** as build script_).
-- Send messages to _Discord_ #**status** channel about jobs' build states from _Travis CI_.
-- Add instapy-chromedriver package if no chromedriver is in path.
-- Add _argparsing_ feature. Users are now able to provide credentials (_and more_) through CLI args.
-- Turn off verification based on _relationship bounds_ **by default**, completely (_see #757815f commit_).
-- Simplify the default **quickstart** script much more.
-
-## [Unreleased] - 2019-01-27
-
-### Changed
-
-- Add track post/profile
-- Avoid prints for only one user
-
-### Fixed
-
-- No posts exception when scraping likes
-
-## [Unreleased] - 2019-01-22
-
-### Added
-
-- Now `set_dont_unfollow_active_users()` feature also has a Progress Tracker support.
-
-### Fixed
-
-- Fix `set_dont_unfollow_active_users()` feature completely.
-
-## [Unreleased] - 2019-01-17
-
-### Changed
-
-- Optimizing Dockerfile for smaller docker image.
-
-### Fixed
-
-- Fix "_Unable to locate element: ...xpath","selector":"//div[text()=\'Likes\'..._" error.
-
-## [Unreleased] - 2019-01-16
-
-### Fixed
-
-- Fix "_Failed to load desired amount of users!_" issue.
-
-## [Unreleased] - 2019-01-15
-
-### Fixed
-
-- Handle A/B-Test for comments (graphql edge).
-
-## [Unreleased] - 2019-01-13
-
-### Fixed
-
-- Adjust docker-compose.yml according to new Dockerfile.
-
-## [Unreleased] - 2019-01-11
-
-### Fixed
-
-- Correctly mount Docker volume, make it work properly with chromedriver installed in assets folder.
-
-## [Unreleased] - 2019-01-10
-
-### Added
-
-- Feature to remove outgoing unapproved follow requests from private accounts.
-
-## [Unreleased] - 2019-01-05
-
-### Changed
-
-- Resolve security warning with new pyyaml version, updated pyyaml to version 4.2b1.
-
-## [Unreleased] - 2019-01-04
-
-### Fixed
-
-- Fix for non-authenticated proxies in chrome headless browser.
-
-## [Unreleased] - 2019-01-02
-
-### Fixed
-
-- User without timestamp will use the timestamp of previous user.
-
-## [Unreleased] - 2019-01-01
-
-### Changed
-
-- PEP8 layout changes.
-
-## [Unreleased] - 2018-12-17
-
-### Added
-
-- A new setting - `set_do_reply_to_comments()` to control replying to comments.
-- A new feature - `run_time()` to get information of how many seconds the _session_ is running; Added to "_Sessional Live Report_" and can also be manually requested like `session.run_time()` from **quickstart** scripts, any time.
-
-### Changed
-
-- A few visual changes to source code for PEP8 compliance.
-- Rename `set_reply_comments()` to `set_comment_replies()` out of revised design.
-
-### Fixed
-
-- Fix bug off #3318 which hit python 2 saying, "_TypeError: can't multiply sequence by non-int of type 'float'_" (_raised & solved at #3451_).
-- Fix error occured while liking a comment (raised at #3594).
-- Fix Follow-Likers feature which couldn't fetch likers properly (raised at #3573).
-
-## [Unreleased] - 2018-12-16
-
-### Added
-
-- Save account progress information into database adding the possibility for external tools to collect and organize the account progress.
-
-## [Unreleased] - 2018-12-10
-
-### Fixed
-
-- Fix `person_id` missing in post_unfollow_cleanup() [line 1152].
-
-## [Unreleased] - 2018-12-08
-
-### Fixed
-
-- Remove as it not working and killing the unfollow with error.
-- Fix logging uncertain having no userid nor time log, will be important for sync feature.
-- Fix get active users when Video have no likes button / no posts in page.
-
-## [Unreleased] - 2018-12-08
-
-### Added
-
-- Full docker-compose and complex template + documentation.
-
-### Fixed
-
-- Fixes likers_from_photo when liked counter is "liked by X and N others".
-
-## [Unreleased] - 2018-12-06
-
-### Fixed
-
-- Fix for python 2.7 users, ceil returns a float in python 2.
-
-## [Unreleased] - 2018-12-05
-
-### Added
-
-- Added mandatory_language (updated check_link definition in like_util).
-
-### Fixed
-
-- Add self.aborts for the follow followers and follow following because otherwise InstaPy won't exit properly on them.
-
-## [Unreleased] - 2018-11-28
-
-### Added
-
-- A new feature - Interact By Comments to **auto-like** comments, **auto-reply** to them, etc. (_see **README**_).
-- New text analytics - MeaningCloud Sentiment Analysis API & Yandex Translate API (_Language Detection & Translation_) integrated into **InstaPy** for doing _sophisticated_ text analysis (_see **README**_).
-
-### Changed
-
-- Speed up _logging in_ at least 25 (_default `page_delay`_) seconds (_see #ee6acba commit_).
-- Upgrades to `live_report()` feature (_"Sessional Live Report" uses it.._). Now it is more smarter.
-- Lots of visual changes to source code for PEP8 compliance.
-- Modify `check_authorization()` to dismiss redundant navigations to profile pages. The gain is a few seconds (_~2-3_) saved which is so good.
-
-### Fixed
-
-- Fix a little misbehaviour in `set_relationship_bounds()` with min_posts & max_posts. Now `enabled` parameter controls the whole setting.
-- Update `grpcio` package's version in **requirements.txt** to `1.16.1`. Its `1.16.0` had a bug duplicating logger messages.
-
-## [Unreleased] - 2018-11-26
-
-### Changed
-
-- Switch `mandatory_words` from ALL to ANY.
-
-## [Unreleased] - 2018-11-22
-
-### Fixed
-
-- Added location to image_text in the `check_link()` method of **like_util.py**, so the script also searches for the mandatory words in location information.
-
-## [Unreleased] - 2018-11-17
-
-### Fixed
-
-- "_Cookie file not found, creating cookie..._" bug fixed.
-
-## [Unreleased] - 2018-11-07
-
-### Changed
-
-- Maintain names: 'person' for target user and 'username' for our running user.
-- Verify private users in get_links_for_username.
-- Changed behaviour of validate_username to check if a user is included in the blacklist. If yes will skip it and log why.
-
-## [Unreleased] - 2018-11-01
-
-### Added
-
-- Interact with tagged images of users, and validation of a user to be optional.
-- Use Clarifai to check video content. By default deactivated and should only be used if necessary.
-
-## [Unreleased] - 2018-10-29
-
-### Added
-
-- This CHANGELOG file to hopefully serve as a useful resource for InstaPy fellas to stay up-to-date with the changes happened so far.
-- **Custom action delays** capability (_see **README**_).
-- Now follow engine has the same compact _action verification procedure_ used in the unfollow engine.
-- Lots of stability in action verification steps which are held at newly added `verify_action` function.
-- New quickstart templates from 11 different people shared at #3033.
-
-### Changed
-
-- Now "_already followed_" state is being tracked by the _following status_ result rather than catching a `NoSuchElementException`.
-
-### Fixed
-
-- Stale element reference error raised at #3173 (occured after #3159).
-- Invalid like element issue (occured after IG introduced comment _liking_ to its web interface).
-
-## [0.1.0] - 2016-10-12
-
-### Added
-
-- Working version with basic features.
-- Use Clarifai to check the images for inappropriate content.
-
----
-
-Please, don't dump raw git logs into this file - which is intended for users rather than developers.
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
deleted file mode 100644
index 9253be2fe..000000000
--- a/CODE_OF_CONDUCT.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Contributor Covenant Code of Conduct
-
-## Our Pledge
-
-In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
-
-## Our Standards
-
-Examples of behavior that contributes to creating a positive environment include:
-
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery and unwelcome sexual attention or advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or electronic address, without explicit permission
-* Other conduct which could reasonably be considered inappropriate in a professional setting
-
-## Our Responsibilities
-
-Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
-
-Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
-
-## Scope
-
-This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
-
-## Enforcement
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact.timgrossmann@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
-
-Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
-
-## Attribution
-
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
-
-[homepage]: http://contributor-covenant.org
-[version]: http://contributor-covenant.org/version/1/4/
diff --git a/InstaPy2/setup.py b/InstaPy2/setup.py
new file mode 100644
index 000000000..b50649e95
--- /dev/null
+++ b/InstaPy2/setup.py
@@ -0,0 +1,49 @@
+from setuptools import find_packages, setup
+
+import os
+
+
+def read(file: str) -> str:
+ return open(os.path.join(os.path.dirname(__file__), file)).read()
+
+
+setup(
+ author="Jarrod Norwell",
+ author_email="official.antique@gmail.com",
+ classifiers=[
+ "Development Status :: 4 - Beta",
+ "Environment :: Console",
+ "Intended Audience :: Developers",
+ "Intended Audience :: End Users/Desktop",
+ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
+ "Natural Language :: English",
+ "Operating System :: MacOS",
+ "Operating System :: Microsoft :: Windows",
+ "Operating System :: POSIX",
+ "Programming Language :: Python",
+ "Topic :: Software Development",
+ "Topic :: Utilities",
+ ],
+ description="Instagram automation tool for farming comments, follows and likes, written in Python",
+ install_requires=["emoji", "instagrapi", "Pillow", "python-dotenv"],
+ keywords=[
+ "automation",
+ "bot",
+ "ig",
+ "insta",
+ "instagram",
+ "instagrapi",
+ "instapy",
+ "instapy2",
+ "python",
+ "python3",
+ ],
+ license_file="..\LICENSE.md",
+ long_description=read(file="..\README.md"),
+ long_description_content_type="text/markdown",
+ name="instapy2",
+ package_dir={"": "src"},
+ packages=find_packages(where="src"),
+ url="https://github.com/jarrodnorwell/instapy2",
+ version="1.0.0",
+)
diff --git a/InstaPy2/src/instapy2/__init__.py b/InstaPy2/src/instapy2/__init__.py
new file mode 100644
index 000000000..47fc474a1
--- /dev/null
+++ b/InstaPy2/src/instapy2/__init__.py
@@ -0,0 +1 @@
+from .instapy2 import InstaPy2
\ No newline at end of file
diff --git a/InstaPy2/src/instapy2/authentication.py b/InstaPy2/src/instapy2/authentication.py
new file mode 100644
index 000000000..63b2ea256
--- /dev/null
+++ b/InstaPy2/src/instapy2/authentication.py
@@ -0,0 +1,39 @@
+from .utilities import Comment, Follow, Like, Utility
+
+from instagrapi import Client
+
+from os import getcwd, mkdir, sep
+from os.path import exists
+from pathlib import Path
+
+class Authentication:
+ def __init__(self, username: str, password: str):
+ self.username = username
+ self.password = password
+
+ def login(self):
+ self.client = Client()
+
+ file_folder = getcwd() + sep + "files"
+ if not exists(path=file_folder):
+ mkdir(path=file_folder)
+
+ session_file = file_folder + sep + f"{self.username}.json"
+ try:
+ if not exists(path=session_file):
+ logged_in = self.client.login(username=self.username, password=self.password)
+ self.client.dump_settings(path=Path(session_file))
+ else:
+ self.client.load_settings(path=Path(session_file))
+ logged_in = self.client.login(username=self.username, password=self.password)
+ except:
+ print("Error logging in")
+ logged_in = False
+
+ print(f"Successfully logged {self.username} in." if logged_in else f"Error logging {self.username} in.")
+
+ self.utility = Utility(client=self.client)
+
+ self.comment = Comment(utility=self.utility)
+ self.follow = Follow(utility=self.utility)
+ self.like = Like(utility=self.utility)
\ No newline at end of file
diff --git a/InstaPy2/src/instapy2/instapy2.py b/InstaPy2/src/instapy2/instapy2.py
new file mode 100644
index 000000000..fd3190088
--- /dev/null
+++ b/InstaPy2/src/instapy2/instapy2.py
@@ -0,0 +1,4 @@
+from .authentication import Authentication
+
+class InstaPy2(Authentication):
+ pass
\ No newline at end of file
diff --git a/InstaPy2/src/instapy2/types/__init__.py b/InstaPy2/src/instapy2/types/__init__.py
new file mode 100644
index 000000000..b85d688b5
--- /dev/null
+++ b/InstaPy2/src/instapy2/types/__init__.py
@@ -0,0 +1 @@
+from .fetch_mode import FetchMode
\ No newline at end of file
diff --git a/InstaPy2/src/instapy2/types/fetch_mode.py b/InstaPy2/src/instapy2/types/fetch_mode.py
new file mode 100644
index 000000000..dd4525ed4
--- /dev/null
+++ b/InstaPy2/src/instapy2/types/fetch_mode.py
@@ -0,0 +1,5 @@
+from enum import IntEnum
+
+class FetchMode(IntEnum):
+ RECENT = 0
+ TOP = 1
\ No newline at end of file
diff --git a/InstaPy2/src/instapy2/utilities/__init__.py b/InstaPy2/src/instapy2/utilities/__init__.py
new file mode 100644
index 000000000..cdd994fd0
--- /dev/null
+++ b/InstaPy2/src/instapy2/utilities/__init__.py
@@ -0,0 +1,5 @@
+from .comment import Comment
+from .follow import Follow
+from .like import Like
+
+from .utility import Utility
\ No newline at end of file
diff --git a/InstaPy2/src/instapy2/utilities/comment.py b/InstaPy2/src/instapy2/utilities/comment.py
new file mode 100644
index 000000000..cf3746db6
--- /dev/null
+++ b/InstaPy2/src/instapy2/utilities/comment.py
@@ -0,0 +1,48 @@
+from ..types import FetchMode
+from .utility import Utility
+
+from random import choice
+
+class Comment:
+ def __init__(self, utility: Utility):
+ self.utility = utility
+
+ self.comments = [] # list of comments to randomly select from
+ self.min_comments = 10 # only comment if posts comments are >=
+ self.max_comments = 1000 # only comment if posts comments are <=
+ self.min_followers = 10 # only comment if postees follower count is >=
+ self.max_followers = 1000 # only comment if postees follower count is <=
+
+ def hashtags(self, amount: int = 10, iterable: list[str] = [], mode: FetchMode = FetchMode.RECENT,
+ **kwargs):
+ """
+ Comments on up to the `amount` of posts per hashtag in `iterable`
+
+ Parameters
+ amount (int): amount of posts to fetch per iterable
+ iterable (list[str]): list of hashtags to fetch posts from
+ """
+
+ match mode:
+ case FetchMode.RECENT:
+ hashtags_medias = self.utility.client.hashtag_medias_recent
+ case FetchMode.TOP:
+ hashtags_medias = self.utility.client.hashtag_medias_top
+
+ if "use_openai" in kwargs.keys():
+ self.use_openai = kwargs["use_openai"]
+
+ total_posts = 0
+ commented_posts = 0
+ for index, hashtag in enumerate(iterable=iterable):
+ print(f"Fetching posts for hashtag: {hashtag} at index: {index}")
+
+ posts = hashtags_medias(name=hashtag, amount=amount)
+ total_posts += len(posts)
+ for index, post in enumerate(iterable=posts):
+ print(f"Commenting on post with id: {post.id} at index: {index}")
+
+ if self.utility.client.media_comment(media_id=post.id, text=self.utility.openai.completions.completion_for_media(media=post) if self.use_openai else choice(seq=self.comments)):
+ commented_posts += 1
+
+ print(f"Commented on {commented_posts} out of {total_posts} available posts")
\ No newline at end of file
diff --git a/InstaPy2/src/instapy2/utilities/follow.py b/InstaPy2/src/instapy2/utilities/follow.py
new file mode 100644
index 000000000..e3bb9b944
--- /dev/null
+++ b/InstaPy2/src/instapy2/utilities/follow.py
@@ -0,0 +1,28 @@
+from .utility import Utility
+
+class Follow:
+ def __init__(self, utility: Utility):
+ self.utility = utility
+
+ self.min_comments = 10 # only follow if posts comments are >=
+ self.max_comments = 1000 # only follow if posts comments are <=
+ self.min_followers = 10 # only follow if postees follower count is >=
+ self.max_followers = 1000 # only follow if postees follower count is <=
+
+ def usernames(self, iterable: list[str] = []):
+ """
+ Follows users with the usernames in `iterable`
+
+ Parameters
+ iterable (list[str]): list of usernames of users to follow
+ """
+
+ total_usernames = len(iterable)
+ followed_users = 0
+ for index, username in enumerate(iterable=iterable):
+ print(f"Following user with username: {username} at index: {index}")
+
+ if self.utility.client.user_follow(user_id=self.utility.client.user_id_from_username(username=username)):
+ followed_users += 1
+
+ print(f"Followed {followed_users} out of {total_usernames} available usernames")
\ No newline at end of file
diff --git a/InstaPy2/src/instapy2/utilities/like.py b/InstaPy2/src/instapy2/utilities/like.py
new file mode 100644
index 000000000..7f7204f36
--- /dev/null
+++ b/InstaPy2/src/instapy2/utilities/like.py
@@ -0,0 +1,105 @@
+from .utility import Utility
+from ..types import FetchMode
+
+class Like:
+ def __init__(self, utility: Utility):
+ self.utility = utility
+
+ self.min_comments = 10 # only like if posts comments are >=
+ self.max_comments = 1000 # only like if posts comments are <=
+ self.min_followers = 10 # only like if postees follower count is >=
+ self.max_followers = 1000 # only like if postees follower count is <=
+
+ def hashtags(self, amount: int = 10, iterable: list[str] = [], mode: FetchMode = FetchMode.RECENT):
+ """
+ Likes up to the `amount` of posts per hashtag in `iterable` searched by `mode`
+
+ Parameters
+ amount (int): amount of posts to fetch per iterable
+ iterable (list[str]): list of hashtags to fetch posts from
+ mode (FetchMode): mode to use when fetching posts
+ """
+
+ match mode:
+ case FetchMode.RECENT:
+ hashtags_medias = self.utility.client.hashtag_medias_recent
+ case FetchMode.TOP:
+ hashtags_medias = self.utility.client.hashtag_medias_top
+
+ total_posts = 0
+ liked_posts = 0
+ for index, hashtag in enumerate(iterable=iterable):
+ print(f"Fetching posts for hashtag: {hashtag} at index: {index}")
+
+ posts = hashtags_medias(name=hashtag, amount=amount)
+ total_posts += len(posts)
+ for index, post in enumerate(iterable=posts):
+ print(f"Liking post with id: {post.id} at index: {index}")
+
+ if self.utility.client.media_like(media_id=post.id):
+ liked_posts += 1
+
+ print(f"Liked {liked_posts} out of {total_posts} available posts")
+
+
+ def locations(self, amount: int = 10, iterable: list[str] = [], mode: FetchMode = FetchMode.RECENT):
+ """
+ Likes up to the `amount` of posts per location in `iterable` searched by `mode`
+
+ Parameters
+ amount (int): amount of posts to fetch per iterable
+ iterable (list[str]): list of locations to fetch posts from
+ mode (FetchMode): mode to use when fetching posts
+ """
+
+ match mode:
+ case FetchMode.RECENT:
+ location_medias = self.utility.client.location_medias_recent
+ case FetchMode.TOP:
+ location_medias = self.utility.client.location_medias_top
+
+ total_posts = 0
+ liked_posts = 0
+ for index, location in enumerate(iterable=iterable):
+ print(f"Fetching posts for location: {location} at index: {index}")
+
+ location_pk = self.utility.__get_pk(query=location)
+ if location_pk:
+ posts = location_medias(location_pk=location_pk, amount=amount)
+ total_posts += len(posts)
+ for index, post in enumerate(iterable=posts):
+ print(f"Liking post with id: {post.id} at index: {index}")
+
+ if self.utility.client.media_like(media_id=post.id):
+ liked_posts += 1
+ else:
+ print("Invalid location pk selected. Please select a valid one")
+ exit(1) # exit() or break?
+
+ print(f"Liked {liked_posts} out of {total_posts} available posts")
+
+
+
+ def usernames(self, amount: int = 10, iterable: list[str] = []):
+ """
+ Likes up to the `amount` of posts per username in `iterable`
+
+ Parameters
+ amount (int): amount of posts to fetch per iterable
+ iterable (list[str]): list of usernames to fetch posts from
+ """
+
+ total_posts = 0
+ liked_posts = 0
+ for index, username in enumerate(iterable=iterable):
+ print(f"Fetching posts for username: {username} at index: {index}")
+
+ posts = self.utility.client.user_medias(user_id=int(self.utility.client.user_id_from_username(username=username)), amount=amount)
+ total_posts += len(posts)
+ for index, post in enumerate(iterable=posts):
+ print(f"Liking post with id: {post.id} at index: {index}")
+
+ if self.utility.client.media_like(media_id=post.id):
+ liked_posts += 1
+
+ print(f"Liked {liked_posts} out of {total_posts} available posts")
\ No newline at end of file
diff --git a/InstaPy2/src/instapy2/utilities/openai/__init__.py b/InstaPy2/src/instapy2/utilities/openai/__init__.py
new file mode 100644
index 000000000..726c893ed
--- /dev/null
+++ b/InstaPy2/src/instapy2/utilities/openai/__init__.py
@@ -0,0 +1 @@
+from .openai import OpenAI
\ No newline at end of file
diff --git a/InstaPy2/src/instapy2/utilities/openai/completions.py b/InstaPy2/src/instapy2/utilities/openai/completions.py
new file mode 100644
index 000000000..0294f887b
--- /dev/null
+++ b/InstaPy2/src/instapy2/utilities/openai/completions.py
@@ -0,0 +1,27 @@
+from instagrapi.types import Media
+
+from enum import StrEnum
+from random import choice
+from requests import post
+
+class CompletionModel(StrEnum):
+ TEXT_DAVINCI003 = "text-davinci-003"
+
+class Completions:
+ def __init__(self, api_key: str):
+ self.api_key = api_key
+ self.model = CompletionModel.TEXT_DAVINCI003
+ self.prompts = []
+
+ def completion_for_media(self, media: Media) -> str:
+ response_json = post(url="https://api.openai.com/v1/chat/completions",
+ headers={
+ "Authorization" : f"Bearer {self.api_key}",
+ "Content-Type" : "application/json"
+ },
+ data={
+ "model" : self.model,
+ "prompt" : choice(seq=self.prompts) + f": {media.caption_text}"
+ }
+ ).json()
+ return choice(seq=response_json["choices"])
\ No newline at end of file
diff --git a/InstaPy2/src/instapy2/utilities/openai/openai.py b/InstaPy2/src/instapy2/utilities/openai/openai.py
new file mode 100644
index 000000000..dd5988380
--- /dev/null
+++ b/InstaPy2/src/instapy2/utilities/openai/openai.py
@@ -0,0 +1,5 @@
+from .completions import Completions
+
+class OpenAI:
+ def set_api_key(self, api_key: str):
+ self.completions = Completions(api_key=api_key)
\ No newline at end of file
diff --git a/InstaPy2/src/instapy2/utilities/utility.py b/InstaPy2/src/instapy2/utilities/utility.py
new file mode 100644
index 000000000..846b0d925
--- /dev/null
+++ b/InstaPy2/src/instapy2/utilities/utility.py
@@ -0,0 +1,45 @@
+from .openai import OpenAI
+
+from instagrapi import Client
+from instagrapi.types import Media, User
+
+class Utility:
+ def __init__(self, client: Client):
+ self.client = client
+
+ self.openai = OpenAI()
+
+ def __get_pk(self, query: str) -> int | None:
+ places = self.client.fbsearch_places(query=query)
+ place_tuple = [(place.name, place.city, place.zip, place.pk) for place in places]
+
+ for index, place in enumerate(iterable=place_tuple):
+ name, city, zip, pk = place
+ selection_string = ""
+ for index, element in enumerate(iterable=[name, city, zip, pk]):
+ if element is not None and element != "":
+ selection_string += f"{element}" if index == 0 else f", {element}"
+ print(f"{index + 1}: {selection_string}")
+
+ selection = int(input(f"Enter the index for the correct location (1-{len(place_tuple)}): "))
+ if 1 <= selection <= len(places):
+ _, _, _, pk = place_tuple[selection - 1]
+ return pk
+ else:
+ return None
+
+ def passes_validation(self, media: Media, comments_range: tuple[int, int], followers_range: tuple[int, int]) -> bool:
+ username = media.user.username
+ if username:
+ user_info = self.client.user_info_by_username(username=username)
+ return self.__comments_within_range(media=media, range=comments_range) and self.__followers_within_range(user=user_info, range=followers_range)
+ else:
+ return False
+
+ def __comments_within_range(self, media: Media, range: tuple[int, int]) -> bool:
+ min, max = range
+ return min <= (media.comment_count or 0) <= max
+
+ def __followers_within_range(self, user: User, range: tuple[int, int]) -> bool:
+ min, max = range
+ return min <= user.follower_count <= max
\ No newline at end of file
diff --git a/LICENSE b/LICENSE.md
similarity index 98%
rename from LICENSE
rename to LICENSE.md
index 1d06bb5e0..f288702d2 100644
--- a/LICENSE
+++ b/LICENSE.md
@@ -1,7 +1,7 @@
-GNU GENERAL PUBLIC LICENSE
+ GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
- Copyright (C) 2007 Free Software Foundation, Inc. {http://fsf.org/}
+ Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
- {one line to give the program's name and a brief idea of what it does.}
- Copyright (C) {year} {name of author}
+
+ Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -645,14 +645,14 @@ the "copyright" line and a pointer to where the full notice is found.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program. If not, see {http://www.gnu.org/licenses/}.
+ along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
- PTAM-GPL Copyright (C) 2013 Oxford-PTAM
+ Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
@@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
-{http://www.gnu.org/licenses/}.
+ .
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
-{http://www.gnu.org/philosophy/why-not-lgpl.html}.
+.
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 9c16bce29..000000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,8 +0,0 @@
-include README.md
-include LICENSE
-include requirements.txt
-include instapy/firefox_extension/arrive.js
-include instapy/firefox_extension/manifest.json
-include instapy/firefox_extension/content.js
-
-recursive-include instapy/icons *
diff --git a/README.md b/README.md
index f338077a2..721ea3a70 100644
--- a/README.md
+++ b/README.md
@@ -1,77 +1,4 @@
-
-
-
InstaPy
- Tooling that automates your social media interactions to “farm” Likes, Comments, and Followers on Instagram
-Implemented in Python using the Selenium module.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+# InstaPy2
+Instagram automation tool for farming comments, follows and likes, written in Python
-[Twitter of InstaPy](https://twitter.com/InstaPy) | [Discord Channel](https://discord.gg/FDETsht) | [How it works (FreeCodingCamp)](https://www.freecodecamp.org/news/my-open-source-instagram-bot-got-me-2-500-real-followers-for-5-in-server-costs-e40491358340/) |
-[Talk about automating your Instagram](https://youtu.be/4TmKFZy-ioQ) | [Talk about doing Open-Source work](https://www.youtube.com/watch?v=A_UtST302Og&t=0s&list=PLa4P1NPX9hthXV-wko0xyxFpbhYZFkW7o) | [Listen to the "Talk Python to me"-Episode](https://talkpython.fm/episodes/show/142/automating-the-web-with-selenium-and-instapy)
-
-
-**Newsletter: [Sign Up for the Newsletter here!](http://eepurl.com/cZbV_v)**
-**Guide to Bot Creation: [Learn to Build your own Bots](https://www.udemy.com/course/the-complete-guide-to-bot-creation/?referralCode=7418EBB47E11E34D86C9)**
-
-
-
-# Find the full documentation in [Docs](/docs)
-**Table of contents**
-- [How to install and run InstaPy](/docs/home.md#installation)
- * [Installing InstaPy](/docs/home.md#installation)
- * [Running Instapy](/docs/home.md#installation)
- * [Updating InstaPy](/docs/home.md#updating-instapy)
- * [Guides and tutorials](/docs/home.md#guides)
- * [Video tutorials](/docs/home.md#video-tutorials)
- * [Written guides](/docs/home.md#written-guides)
-- [Externals and additionals tools](/docs/home.md#external-tools)
-- [Running InstaPy on Docker](/docs/home.md#docker)
-- [Documentation of all Instapy's features](/docs/settings.md)
-- [Support](/docs/home.md#support)
-- [Credits](/docs/home.md#credits)
-
-
-
-## Credits
-### Community
-An active and supportive community is what every open-source project needs to sustain. Together we reached every continent and most of the countries in the world!
-Thank you all for being part of the InstaPy community ✌️
-
-
-
-
-
-### Contributors
-
-This project exists thanks to all the people who contribute. [[Contribute](https://github.com/timgrossmann/InstaPy/wiki/How-to-Contribute)].
-
-
-
-### Backers
-
-Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/instapy#backer)]
-
-
-
----
-
-> **Disclaimer** : Please note that this is a research project. I am by no means responsible for any usage of this tool. Use it on your behalf. I'm also not responsible if your accounts get banned due to the extensive use of this tool.
+**TODO**
\ No newline at end of file
diff --git a/docs/actions.md b/docs/actions.md
deleted file mode 100644
index 6cf896a07..000000000
--- a/docs/actions.md
+++ /dev/null
@@ -1,682 +0,0 @@
----
-title: Actions
----
-
-### Like by Tags
-
-```python
-# Like posts based on hashtags
-session.like_by_tags(['natgeo', 'world'], amount=10)
-```
-
-#### Parameters:
- `tags`: The tags that will be searched for and posts will be liked from
-
- `use_random_tags`: The tags that will be searched for and posts will be randomized
-
- `amount`: The amount of posts that will be liked
-
- `skip_top_posts`: Determines whether the first 9 top posts should be liked or not (default is True)
-
- `use_smart_hashtags`: Make use of the [smart hashtag feature](#smart-hashtags)
-
- `use_smart_location_hashtags`: Make use of the [smart location hashtag feature](#smart-location-hashtags)
-
- `interact`: Defines whether the users of the given post should also be interacted with (needs `set_user_interact` to be also set)
-
- `randomize`: Determines whether the first `amount` of posts should be liked or a random selection.
-
- `media`: Determines which media should be liked, Photo or Video (default is `None` which is all)
-
-
-#### Like by Tags and interact with user
-
-```python
-# Like posts based on hashtags and like 3 posts of its poster
-session.set_user_interact(amount=3, randomize=True, percentage=100, media='Photo')
-session.like_by_tags(['natgeo', 'world'], amount=10, interact=True)
-```
-
-
-### Like by Feeds
-
-```python
-# This is used to perform likes on your own feeds
-# amount=100 specifies how many total likes you want to perform
-# randomize=True randomly skips posts to be liked on your feed
-# unfollow=True unfollows the author of a post which was considered
-# inappropriate interact=True visits the author's profile page of a
-# certain post and likes a given number of his pictures, then returns to feed
-
-session.like_by_feed(amount=100, randomize=True, unfollow=True, interact=True)
-```
-
-
-### Like by Locations
-
-```python
-session.like_by_locations(['224442573/salton-sea/'], amount=100)
-
-# or
-session.like_by_locations(['224442573'], amount=100)
-
-# or include media entities from top posts section
-session.like_by_locations(['224442573'], amount=5, skip_top_posts=False, randomize=True)
-```
-
-
-You can find locations for the `like_by_locations` function by:
-- Browsing https://www.instagram.com/explore/locations/
-- Regular instagram search.
-
-Example:
-* Search 'Salton Sea' and select the result with a location icon
-* The url is: https://www.instagram.com/explore/locations/224442573/salton-sea/
-* Use everything after 'locations/' or just the number
-
-
-### Comment by Locations
-
-```python
-session.comment_by_locations(['224442573/salton-sea/'], amount=100)
-# or
-session.comment_by_locations(['224442573'], amount=100)
-# or include media entities from top posts section
-
-session.comment_by_locations(['224442573'], amount=5, skip_top_posts=False)
-```
-
-This method allows commenting by locations, without liking posts. To get locations follow instructions in 'Like by Locations'
-
-
-
-
-### Follow by Tags
-
-```python
-# Follow user based on hashtags (without liking the image)
-
-session.follow_by_tags(['tag1', 'tag2'], amount=10)
-```
-
-#### Parameters:
- `tags`: The tags that will be searched for and authors of the posts will be followed.
-
- `amount`: The amount of posts that the author of the post will be followed
-
- `skip_top_posts`: Determines whether the first 9 top users of posts should be followed or not (default is True)
-
- `use_smart_hashtags`: Make use of the [smart hashtag feature](#smart-hashtags)
-
- `use_smart_location_hashtags`: Make use of the [smart location hashtag feature](#smart-location-hashtags)
-
- `interact`: Defines whether the users of the given post should also be interacted with (needs `set_user_interact` to be also set)
-
- `randomize`: Determines whether the first `amount` of post authors should be liked or a random selection.
-
- `media`: Determines which media should be considered, Photo or Video (default is `None` which is all)
-
-
-### Follow by Locations
-
-```python
-session.follow_by_locations(['224442573/salton-sea/'], amount=100)
-# or
-session.follow_by_locations(['224442573'], amount=100)
-# or include media entities from top posts section
-
-session.follow_by_locations(['224442573'], amount=5, skip_top_posts=False)
-```
-This method allows following by locations, without liking or commenting posts. To get locations follow instructions in 'Like by Locations'
-
-
-
-### Following by a list
-##### This will follow each account from a list of instagram nicknames
-```python
-follow_by_list(followlist=['samantha3', 'larry_ok'], times=1, sleep_delay=600, interact=False)
-```
-_only follows a user once (if unfollowed again) would be useful for the precise targeting_
-`sleep_delay` is used to define break time after some good following (_averagely ~`10` follows_)
-For example, if one needs to get followbacks from followers of a chosen account/group of accounts.
-```python
-accs = ['therock','natgeo']
-session.follow_by_list(accs, times=1, sleep_delay=600, interact=False)
-```
-* You can also **interact** with the followed users by enabling `interact=True` which will use the configuration of `set_user_interact` setting:
-
-```python
-session.set_user_interact(amount=4,
- percentage=50,
- randomize=True,
- media='Photo')
-
-session.follow_by_list(followlist=['samantha3', 'larry_ok'],
- times=2,
- sleep_delay=600,
- interact=True)
-```
-
-
-### Follow someone else's followers
-
-```python
-# Follows the followers of each given user
-# The usernames can be either a list or a string
-# The amount is for each account, in this case 30 users will be followed
-# If randomize is false it will pick in a top-down fashion
-
-session.follow_user_followers(['friend1', 'friend2', 'friend3'], amount=10, randomize=False)
-
-# default sleep_delay=600 (10min) for every 10 user following, in this case
-# sleep for 60 seconds
-
-session.follow_user_followers(['friend1', 'friend2', 'friend3'], amount=10, randomize=False, sleep_delay=60)
-```
-> **Note**: [simulation](#simulation) takes place while running this feature.
-
-
-
-### Follow users that someone else is following
-
-```python
-# Follows the people that a given users are following
-# The usernames can be either a list or a string
-# The amount is for each account, in this case 30 users will be followed
-# If randomize is false it will pick in a top-down fashion
-
-session.follow_user_following(['friend1', 'friend2', 'friend3'], amount=10, randomize=False)
-
-# default sleep_delay=600 (10min) for every 10 user following, in this case
-# sleep for 60 seconds
-
-session.follow_user_following(['friend1', 'friend2', 'friend3'], amount=10, randomize=False, sleep_delay=60)
-```
-> **Note**: [simulation](#simulation) takes place while running this feature.
-
-
-
-### Follow and interact someone else's followers/following
-
-```python
-# For 50% of the 30 newly followed, move to their profile
-# and randomly choose 5 pictures to be liked.
-# Take into account the other set options like the comment rate
-# and the filtering for inappropriate words or users
-
-session.set_user_interact(amount=5, randomize=True, percentage=50, media='Photo')
-session.follow_user_followers(['friend1', 'friend2', 'friend3'], amount=10, randomize=False, interact=True)
-```
-
-
-
-
-### Follow the likers of photos of users
-##### This will follow the people those liked photos of given list of users
-```python
-session.follow_likers(['user1' , 'user2'], photos_grab_amount = 2, follow_likers_per_photo = 3, randomize=True, sleep_delay=600, interact=False)
-```
-_in this case 2 random photos from each given user will be analyzed and 3 people who liked them will be followed, so 6 follows in total_
-The `usernames` can be any list
-The `photos_grab_amount` is how many photos will I grat from users profile and analyze who liked it
-The `follow_likers_per_photo` is how many people to follow per each photo
-`randomize=False` will take photos from newes, true will take random from first 12
-`sleep_delay` is used to define break time after some good following (_averagely ~`10` follows_)
-
-* You can also **interact** with the followed users by enabling `interact=True` which will use the configuration of `set_user_interact` setting:
-```python
-session.set_user_interact(amount=2,
- percentage=70,
- randomize=True,
- media='Photo')
-
-session.follow_likers(['user1' , 'user2'],
- photos_grab_amount = 2,
- follow_likers_per_photo = 3,
- randomize=True,
- sleep_delay=600,
- interact=True)
-```
-
-
-### Follow the commenters of photos of users
-##### This will follow the people those commented on photos of given list of users
-```python
-session.follow_commenters(['user1', 'user2', 'user3'], amount=100, daysold=365, max_pic = 100, sleep_delay=600, interact=False)
-```
-_in this case (max 100 newest photos & maximum 365 days old) from each given user will be analyzed and 100 people who commented the most will be followed_
-The `usernames` can be any list
-The `amount` is how many people to follow
-The `daysold` will only take commenters from photos no older than `daysold` days
-The `max_pic` will limit number of photos to analyze
-`sleep_delay` is used to define break time after some good following (_averagely ~`10` follows_)
-
-* You can also **interact** with the followed users by enabling `interact=True` which will use the configuration of `set_user_interact` setting:
-```python
-session.set_user_interact(amount=3,
- percentage=32,
- randomize=True,
- media='Video')
-session.follow_commenters(['user1', 'user2', 'user3'], amount=100, daysold=365, max_pic = 100, sleep_delay=600, interact=True)
-```
-
-
-### Unfollowing
-###### Unfollows the accounts you're following
-_It will unfollow ~`10` accounts and sleep for ~`10` minutes and then will continue to unfollow..._
-
-##### There are `4` _Unfollow methods_ available to use:
-`|>` **customList** `|>` **InstapyFollowed** `|>` **nonFollowers** `|>` **allFollowing**
-
-**1** - Unfollow **specific users** from a _CUSTOM_ list (_has `2` **track**s- `"all"` and `"nonfollowers"`_):
-_when **track** is `"all"`, it will unfollow **all of the users** in a given list_;
-```python
-custom_list = ["user_1", "user_2", "user_49", "user332", "user50921", "user_n"]
-session.unfollow_users(amount=84, custom_list_enabled=True, custom_list=custom_list, custom_list_param="all", style="RANDOM", unfollow_after=55*60*60, sleep_delay=600)
-```
-_if **track** is `"nonfollowers"`, it will unfollow all of the users in a given list **WHO are not following you back**_;
-```python
-custom_list = ["user_1", "user_2", "user_49", "user332", "user50921", "user_n"]
-session.unfollow_users(amount=84, custom_list_enabled=True, custom_list=custom_list, custom_list_param="nonfollowers", style="RANDOM", unfollow_after=55*60*60, sleep_delay=600)
-```
-* **PRO**: `customList` method can take any kind of _iterable container_, such as `list`, `tuple` or `set`.
-
-**2** - Unfollow the users **WHO** was _followed by `InstaPy`_ (_has `2` **track**s- `"all"` and `"nonfollowers"`_):
-_again, if you like to unfollow **all of the users** followed by InstaPy, use the **track**- `"all"`_;
-```python
-session.unfollow_users(amount=60, instapy_followed_enabled=True, instapy_followed_param="all", style="FIFO", unfollow_after=90*60*60, sleep_delay=501)
-```
-_but if you like you unfollow only the users followed by InstaPy **WHO do not follow you back**, use the **track**- `"nonfollowers"`_;
-```python
-session.unfollow_users(amount=60, instapy_followed_enabled=True, instapy_followed_param="nonfollowers", style="FIFO", unfollow_after=90*60*60, sleep_delay=501)
-```
-
-**3** - Unfollow the users **WHO** `do not` _follow you back_:
-```python
-session.unfollow_users(amount=126, nonFollowers=True, style="RANDOM", unfollow_after=42*60*60, sleep_delay=655)
-```
-
-**4** - `Just` unfollow, **regardless of** a user _follows you or not_:
-```python
-session.unfollow_users(amount=40, allFollowing=True, style="LIFO", unfollow_after=3*60*60, sleep_delay=450)
-```
-
-#### Parameters (_all of these parameters apply to all of the 4 methods available_):
-
-`style`
-You can choose _unfollow style_ as `"FIFO"` (_First-Input-First-Output_) **OR** `"LIFO"` (_Last-Input-First-Output_) **OR** `"RANDOM"`.
-* with `"FIFO"`, it will unfollow users _in the **exact** order they are loaded_ (_`"FIFO"` is the default style unless you **change** it_);
-* with `"LIFO`" it will unfollow users _in the **reverse** order they were loaded_;
-* with `"RANDOM"` it will unfollow users _in the **shuffled** order_;
-
-
-`unfollow_after`
-By using this, you can unfollow users **only after** following them certain amount of time.
-_it will help to provide **seamless** unfollow activity without the notice of the target user_
-To use it, just add `unfollow_after` parameter with the _desired time interval_, _e.g._,
-```python
-session.unfollow_users(amount=94, instapy_followed_enabled=True, instapy_followed_param="all", style="RANDOM", unfollow_after=48*60*60, sleep_delay=600)
-```
-_will unfollow users **only after following them** `48` hours (`2` days)_.
-* Since `unfollow_after`s value is in _seconds_, you can simply give it `unfollow_after=3600` to unfollow after `3600` seconds.
-_Yeah, values kind of `1*60*60`- which is also equal to `1` hour or `3600` seconds, is much more easier to use_.
-
-**Sure** if you like to not use it, give the value of `None`- `unfollow_after=None`.
-
-`sleep_delay`
-Sleep delay _sets_ the time it will sleep **after** every ~`10` unfollows (_default delay is ~`10` minutes_).
-
-> **NOTE**: You should know that, _in one RUN_, `unfollow_users` feature can take only one method from all `4` above.
-That's why, **it is best** to **disable** other `3` methods _while using a one_:
-```python
-session.unfollow_users(amount=200, custom_list_enabled=True, custom_list=["user1", "user2", "user88", "user200"], instapy_followed_enabled=False, nonFollowers=False, allFollowing=False, style="FIFO", unfollow_after=22*60*60, sleep_delay=600)
-```
-_here the unfollow method- **customList** is used_
-**OR** just keep the method you want to use and remove other 3 methods from the feature
-```python
-session.unfollow_users(amount=200, allFollowing=True, style="FIFO", unfollow_after=22*60*60, sleep_delay=600)
-```
-_here the unfollow method- **alFollowing** is used_
-
-
-### Interact on posts at given URLs
-###### Like, comment, follow on the post in the links provided, also can interact the owner of the post
-
-```python
-session.interact_by_URL(urls=["some/URL/1", "some/URL/2" "other/URL"], randomize=True, interact=True)
-```
-
-**To use**, _define_ all of the `interaction settings` and **start** the feature right away!
-```python
-#define interaction settings
-session.set_do_like(enabled=True, percentage=94)
-session.set_do_comment(enabled=True, percentage=24)
-session.set_comments(["Masterful shot", "Chilling!", "Unbelievably great..."])
-session.set_do_follow(enabled=True, percentage=44)
-session.set_user_interact(amount=6, randomize=True, percentage=72, media='Photo')
-
-#start the feature
-session.interact_by_URL(urls=["Fv0J4AJ3Y7r/?taken-at=628416252", "Vb0D4bJgY7r" "Dj0J4VJgY7r"], randomize=True, interact=True)
-```
-##### Parameters:
-`urls`:
-Contains the _URLs_ of the **posts** _to be interacted_.
-* You can provide _URLs_ in these formats:
-**full:** `"https://www.IG.com/p/Aj0J4bJDY7r/?taken-at=128316221"`
-just **post link:** `"https://www.IG.com/p/Aj0J4bJDY7r/"`
-just post **handle:** `"Aj0J4bJDY7r/?taken-at=128316221"`
-just post **ID:** `"Aj0J4bJDY7r"`
-
-`randomize`:
-Shuffles the **order** of the _URLs_ in the given list _before starts to interact_.
-
-`interact`:
-Use it if you like to also _interact the post owner_ **after** doing interactions on the **post itself**.
-
-
-
-### Interact with specific users
-
-```python
-# Interact with specific users
-# set_do_like, set_do_comment, set_do_follow are applicable
-
-session.set_do_follow(enabled=False, percentage=50)
-session.set_comments(["Cool", "Super!"])
-session.set_do_comment(enabled=True, percentage=80)
-session.set_do_like(True, percentage=70)
-session.interact_by_users(['user1', 'user2', 'user3'], amount=5, randomize=True, media='Photo')
-```
-
-### Interact with specific users' tagged posts
-
-```python
-# Interact with specific users' tagged posts
-# set_do_like, set_do_comment, set_do_follow are applicable
-
-session.set_do_follow(enabled=False, percentage=50)
-session.set_comments(["Cool", "Super!"])
-session.set_do_comment(enabled=True, percentage=80)
-session.set_do_like(True, percentage=70)
-session.interact_by_users_tagged_posts(['user1', 'user2', 'user3'], amount=5, randomize=True, media='Photo')
-```
-
-
-### Interact with someone else's followers
-
-```python
-# Interact with the people that a given user is followed by
-# set_do_comment, set_do_follow and set_do_like are applicable
-
-session.set_user_interact(amount=5, randomize=True, percentage=50, media='Photo')
-session.set_do_follow(enabled=False, percentage=70)
-session.set_do_like(enabled=False, percentage=70)
-session.set_comments(["Cool", "Super!"])
-session.set_do_comment(enabled=True, percentage=80)
-session.interact_user_followers(['natgeo'], amount=10, randomize=True)
-```
-> **Note**: [simulation](#simulation) takes place while running this feature.
-
-
-
-
-### Interact with users that someone else is following
-
-```python
-# Interact with the people that a given user is following
-# set_do_comment, set_do_follow and set_do_like are applicable
-
-session.set_user_interact(amount=5, randomize=True, percentage=50, media='Photo')
-session.set_do_follow(enabled=False, percentage=70)
-session.set_do_like(enabled=False, percentage=70)
-session.set_comments(["Cool", "Super!"])
-session.set_do_comment(enabled=True, percentage=80)
-session.interact_user_following(['natgeo'], amount=10, randomize=True)
-```
-> **Note**: [simulation](#simulation) takes place while running this feature.
-
-
-### Interact by Comments
-###### Like comments on posts, reply to them and then interact by the users whose comment was liked on the post
-
-```python
-session.interact_by_comments(usernames=["somebody", "other buddy"],
- posts_amount=10,
- comments_per_post=5,
- reply=True,
- interact=True,
- randomize=True,
- media="Photo")
-```
-#### Parameters
-`usernames`
-: A list containing the _usernames_ of users on WHOSE **posts'** _comments will be interacted_;
-
-`posts_amount`
-: Number of the posts to get from **each user** for interacting by comments;
-
-`comments_per_post`
-: Choose how many comments to interact (_like and then reply_) on **each post**;
-
-`reply`
-: Choose if it **should reply** to comments;
-
-`interact`
-: Use if you also like to _interact the commenters_ **after** finishing liking (_and then replying to_) comments on the **post**;
-
-`randomize`
-: Shuffles the **order** of the **_posts_** from users' feed and **_comments_** in the given post;
-
-`media`
-: Choose the **type of** media to be interacted - _`"Photo"`_ for photos, _`"Video"`_ for videos, `None` for any media;
-
-
-#### Usage
-**To use**, set **replying** and **interaction** configuration(s)
-```python
-session.set_do_reply_to_comments(enabled=True, percentage=14)
-session.set_comment_replies(replies=[u"😎😎😎", u"😁😁😁😁😁😁😁💪🏼", u"😋🎉", "😀🍬", u"😂😂😂👈🏼👏🏼👏🏼", u"🙂🙋🏼♂️🚀🎊🎊🎊", u"😁😁😁", u"😂", u"🎉", u"😎", u"🤓🤓🤓🤓🤓", u"👏🏼😉"],
- media="Photo")
-
-session.set_user_interact(amount=2, percentage=70, randomize=False, media="Photo")
-# also configure [at least] liking to be used while interacting with the commenters ...
-session.set_do_like(enabled=True, percentage=94)
-
-# start the feature
-session.interact_by_comments(usernames=["somebody", "other.buddy"], posts_amount=10, comments_per_post=5, reply=True, interact=True, randomize=True, media="Photo")
-```
-**Note**: To be able to reply to comments, you have to **turn on** _text analytics_- [**Yandex**](#yandex-translate-api) & [**MeaningCloud**](#meaningcloud-sentiment-analysis-api).
-So that they will analyze the content of comments and if it is appropriate, will send a reply to the comment.
-_To configure those text analytics, see the usage in their sections_.
-
-There are **3** **COMBINATIONS** _available_ to use regarding _text analysis_:
-**a**-) ONLY **Sentiment Analysis**;
-_MeaningCloud must be turned on and Yandex must be enabled with a valid API key_,
-```python
-session.set_use_meaningcloud(enabled=True, license_key='', polarity="P")
-session.set_use_yandex(enabled=True, API_key='')
-```
-**b**-) ONLY **Language Match**;
-_Yandex must be turned on_,
-```python
-session.set_use_yandex(enabled=True, API_key='', match_language=False, language_code="en")
-```
-**c**-) BOTH **Sentiment Analysis** and **Language Match**;
-_MeaningCloud and Yandex must be turned on_,
-```python
-session.set_use_meaningcloud(enabled=True, license_key='', polarity="P")
-session.set_use_yandex(enabled=True, API_key='', match_language=True, language_code="en")
-```
-
-If you have **followed** any of those 3 _text analysis_ combinations:
-It will first _analyze comments' content_ and if it _is appropriate_, then it will _first_ like, _then_ will reply to it.
-All those inappropriate comments will neither be liked, nor replied to.
-
-If you have **not followed** any of those 3 _text analysis_ combinations OR **misconfigured** them:
-Comments' content will _not be able to be analyzed_ and that's why _no any comments will be_ replied.
-_Yet_, it will like _all of the comments_ that are available.
-
-In conclusion, the whole block SHOULD look like this,
-```python
-session.set_use_meaningcloud(enabled=True, license_key='', polarity="P")
-session.set_use_yandex(enabled=True, API_key='', match_language=True, language_code="en")
-
-session.set_do_comment(enabled=True, percentage=14)
-session.set_comment_replies(replies=[u"😎😎😎", u"😁😁😁😁😁😁😁💪🏼"], media="Photo")
-
-session.set_user_interact(amount=2, percentage=70, randomize=False, media="Photo")
-session.set_do_like(enabled=True, percentage=100)
-
-session.interact_by_comments(usernames=["somebody", "other.buddy"], posts_amount=10, comments_per_post=5, reply=True, interact=True, randomize=True, media="Photo")
-```
-
-#### Extras
-+ comments from the poster are ignored (_those comments are mostly poster's replies_);
-+ owner's (_logged in user_) comments are also ignored;
-+ if the commenter is in _blacklist_ or `ignored_users` list, that comment will also be ignored;
-+ it will take only one comment from each unique commenter;
-+ as if there are any usable comments, it will first **like the post itself** before _interacting by comments_ cos liking comments and replying to them without liking the post can look spammy;
-+ it will reply to a comment only after liking it;
-+ it will not send the same reply again on overall posts per each username in the list provided by you;
-
-#### PROs
-+ you can use this feature to **auto-like** comments, **auto-reply** to them on your _own_ posts;
-+ else than interacting by the comments in your _own_ posts, you can use this feature to like lots of comments from _other users'_ posts, reply to some of _them_ and interact by those users just after _liking_ & _replying_ to their comments;
-
-#### CONs
-+ liking a comment doesn't fill up your like quota, but replying to a comment does it to the comment quota. Try to compensate it in your style and do not overuse;
-+ using auto-reply capability of this feature can result in unwanted miscommunication between you and the commenter IN CASE OF you do not make an efficient use of text analytics;
-
-### Interact by Likers
-###### Get a user's posts, get the posts' likers and interact with them.
-
-```python
-session.interact_user_likers(usernames=["somebody", "other buddy"],
- posts_grab_amount=10,
- interact_likers_per_post=5,
- randomize=True)
-```
-#### Parameters
-`usernames`
-: A list containing the _usernames_ of users on whose **posts'** _likers will be interacted with_;
-
-`posts_grab_amount`
-: Number of the posts to get from **each user** for getting its likers to interact with;
-
-`interact_likers_per_post`
-: Choose how many likers to get from **each post**;
-
-`randomize`
-: Shuffles the **order** of the **_posts_** from users' feed;
-
-
-### Accept pending follow requests
-
-```python
-session.accept_follow_requests(amount=100, sleep_delay=1)
-```
-
-`amount`
-The maximum amount of follow requests that will be accepted.
-
-`sleep_delay`
-Sleep delay _sets_ the time it will sleep **after** every accepted request (_default delay is ~ `1` second).
-
-
-### Remove outgoing follow requests
-
-```python
-# Remove outgoing unapproved follow requests from private accounts
-
-session.remove_follow_requests(amount=200, sleep_delay=600)
-```
-
-
-### InstaPy Pods
-
- In case you are unfamiliar with the concept do read a little. Here's a blog to learn more about [Pods](https://blog.hubspot.com/marketing/instagram-pods)
-
- ```python
-
- photo_comments = ['Nice shot! @{}',
- 'I love your profile! @{}',
- 'Your feed is an inspiration :thumbsup:',
- 'Just incredible :open_mouth:',
- 'What camera did you use @{}?',
- 'Love your posts @{}',
- 'Looks awesome @{}',
- 'Getting inspired by you @{}',
- ':raised_hands: Yes!',
- 'I can feel your passion @{} :muscle:']
-
- session = InstaPy()
-
- with smart_run(session):
- session.set_comments(photo_comments, media='Photo')
- session.join_pods()
- ```
-
- #### Parameters:
- `topic`:
- Topic of the posts to be interacted with. `general` by default.
-
- > Note : Topics allowed are {'general', 'fashion', 'food', 'travel', 'sports', 'entertainment'}.
-
- `engagement_mode`:
- Desided engagement mode for your posts. There are four levels of engagement modes 'no_comments', 'light', 'normal' and 'heavy'(`normal` by default). Setting engagement_mode to 'no_comments' makes you receive zero comments on your posts from pod members, 'light' encourages approximately 10% of pod members to comment on your post, similarly it's around 30% and 90% for 'normal' and 'heavy' modes respectively. Note: Liking, following or any other kind of engagements doesn't follow these modes.
-
-### Instapy Stories
-
-#### Watching Stories with interact
-
-Will add story watching while interacting with users
-
-```python
-session.set_do_story(enabled = True, percentage = 70, simulate = True)
-```
-
- `simulate`:
- If set to `True` InstaPy will simulate watching the stories (you won't see it in the browser), we just send commands to Instagram saying we have watched the stories.
- If set to `False` Instapy will perform the exact same action as a human user (clicking on stories, waiting until watching finishes, etc...)
-
- Please note: `simulate = False` is the safest settings as it fully disables all additional, simulated interactions
-
-#### Watch stories by Tags
-
-Will watch up to 20 stories published with specified tags.
-
-```python
-session.story_by_tags(['tag1', 'tag2'])
-```
-
-#### Watch stories from users
-
-Take a list of users and watch their stories.
-
-```python
-session.story_by_users(['user1', 'user2'])
-```
diff --git a/docs/additional-information.md b/docs/additional-information.md
deleted file mode 100644
index c18ad1f70..000000000
--- a/docs/additional-information.md
+++ /dev/null
@@ -1,784 +0,0 @@
----
-title: Additional Information
----
-
-### Advanced Installation
-#### 🛠 Install or update to the unreleased version
-For example, there is a **bug** and its **fix** is _merged to the repo_ but a newer version of _InstaPy_ [_containing_ that **fix**] is not yet released to _PyPI_ to be able to be _installed_ or _updated_ by **pip**.
-
-Then, you can do this to install the **actual state** of the _repo_ 😋
-```erlang
-pip install -I https://github.com/timgrossmann/InstaPy/zipball/master
-```
-
-Worths to note that, this installation option does not require _Git_ to be installed, too.
-`-I` flag in there is used to _ignore the installed_ packages and _reinstall_ them instead.
-
-
-
-
- Learn why -I flag is required 🔎
-
-
-
-Since _InstaPy_'s version is not yet being incremented which is the reason you're installing it from a _zipball_, then if you don't use the `-I` flag, **pip** will complain saying,
-- "_Hey, I have already installed the x.y.z version! Skipping installation..._"
-
-But obviously, even though the version is the same, _zipball_ has the current state of the repository.
-That's why you will be able to install the actual state of the repo using the `-I` flag.
-
-
-
-
-
->**PRO** Tip:
- Read the section - [How to avoid _python_ & **pip** confusion](#how-to-avoid-python--pip-confusion) 😄
-
-
-
-#### ⚗ Install manually and manage using advanced git commands
-###### For those who want to tweak or enhance _InstaPy_.
-
-**1**. Clone _InstaPy_ repository into your computer
-```erlang
-git clone https://github.com/timgrossmann/InstaPy.git
-```
-
-**2**. Navigate to the _InstaPy_ project root directory
-```erlang
-cd InstaPy
-```
-
-**3**. Install the _local_ **instapy** package
-```erlang
-pip install -e .
-```
-
-
-
- Learn why -e flag is required 🔎
-
-
-
-Since you're gonna install the local version of _InstaPy_ you'll probably change its code per your need which is the reason you do an advanced installation from a _Git_ source, then if you don't use the `-e` flag, you'll have to install that local package by **pip** every time after making a change.
-
-But fortunately, `-e` flag comes to help;
-`-e` means _editable_ install, so that after editing files you don't need to re-install the package again since it will always refer to the edited files cos with the _editable_ install, it just **links** the project's location to **pip**'s install location _rather than_ adding them to **pip** location separately..
-
-
-or
-
-```erlang
-python setup.py install
-```
-
-
-
-#### ⛑ Install into a Virtual Environment
-
-###### The best way to install _InstaPy_ is to create a virtual environment and install _InstaPy_ there, then, run it from a separate file.
-
-
-
-
- Guide for Pythons >= 3.6 🔎
-
-
-
-##### Mac/Linux
-
-**1**. Clone _InstaPy_ repository into your computer
-```erlang
-git clone https://github.com/timgrossmann/InstaPy.git
-```
-
-**2**. Navigate to the _InstaPy_ project root directory
-```erlang
-cd InstaPy
-```
-
-**3**. Make a virtual environment
-```erlang
-python3 -m venv venv
-```
-
-**4**. Activate the virtual environment
-```erlang
-source venv/bin/activate
-```
-
-**5**. Install the _local_ **instapy** package
-```erlang
-pip install -e .
-```
-
-
-
-##### Windows
-
-**1**. Clone _InstaPy_ repository into your computer
-```erlang
-git clone https://github.com/timgrossmann/InstaPy.git
-```
-
-**2**. Navigate to the _InstaPy_ project root directory
-```erlang
-cd InstaPy
-```
-
-**3**. Make a virtual environment
-```erlang
-python3 -m venv venv
-```
-
-**4**. Activate the virtual environment
-```erlang
-venv\Scripts\activate.bat
-```
-
-**5**. Install the _local_ **instapy** package
-```erlang
-pip install -e .
-```
-
-
-If you're not _familiar_ with **venv**, please [read about it here](https://docs.python.org/3/library/venv.html) and use it to your advantage;
-
-- Running `source venv/bin/activate` will _activate_ the correct _python_ to run _InstaPy_. To exit an activated **venv** run `deactivate`.
-- Now, copy & paste the **quickstart.py** _python_ code below and then run your first _InstaPy_ script.
- Remember to run it with _python_ from the **venv**.
-- To make sure which _python_ is used, run `which python` which will tell you the active version of _python_.
-- Whenever you run the script, the virtual environment must be _active_.
-
-
-
-
-
-
-
- Guide for Pythons greater 3.6 🔎
-
-
-
-**1**. Make a virtual environment
-```erlang
-virtualenv venv
-```
-
-**2**. Activate the virtual environment
-```erlang
-source venv/bin/activate
-```
-
-**3**. Install the **instapy** package from _Git_ by using **pip**
-```erlang
-pip install git+https://github.com/timgrossmann/InstaPy.git
-```
-
-
-If you're not _familiar_ with **virtualenv**, please [read about it here](https://virtualenv.pypa.io/en/stable/) and use it to your advantage;
-
-In essence,
- - This is be the **only** _python_ library you should install as `root` (_e.g., with `sudo`_).
- - All other _python_ libraries should be inside a **virtualenv**.
- - Running `source venv/bin/activate` will activate the correct _python_ to run _InstaPy_.
- And to exit an activated **virtualenv** run `deactivate`.
- - Now, copy & paste the **quickstart.py** _python_ code below and run your first _InstaPy_ script.
- Remember to run it with _python_ from the **virtualenv**, so from **venv/bin/python**.
- - To make sure which _python_ is used, run `which python` which would tell you the active version of _python_.
-
-
-
-
-
-#### **Install** a _**specific** version_
-```elm
-pip install instapy==0.1.1
-```
-
-#### **Uninstall**
-```elm
-pip uninstall instapy
-```
-
-
-
-
-## Workspace folders
-### Migrating your data to the workspace folder
-After installing InstaPy with pip, you have to run it once by calling `python quickstart.py`. Once the web browser opens, you can abort the session by closing the browser or your terminal.
-
-You will now find an `InstaPy` folder located at the above mentioned home folder.
-Simply copy and paste the content of your logs folder into that workspace folder in order to assure that all your data is migrated.
-
-> Please note that you only have to do this once. After that, you can get rid of your old, downloaded version of this repository since the InstaPy folder in your home folder will now be the default location for your data.
-
-
-###### _InstaPy_ stores user's data files inside the **workspace** folder.
-
-By default, it is gonna be the **InstaPy** folder at your home folder.
-Such as, if your username is `Cherry`, let's show where your InstaPy folder would be,
-
-| OS | home folder | _InstaPy_ **workspace** folder |
-| ------- | --------------------- | ------------------------------ |
-| Windows | `C:\\Users\\Cherry\\` | `C:\\Users\\Cherry\\InstaPy\\` |
-| Mac | `/Users/Cherry/` | `/Users/Cherry/InstaPy/` |
-| Linux | `/home/Cherry/` | `/home/Cherry/InstaPy/` |
-
-Note that, at the start of each run, it shows you the **workspace** folder in use.
-
-
-
-
-
-
- What will be stored at the workspace folder? 🔍
-
-
-
-Anything that is _user's **data file**_ will be stored in there.
-Such as,
-- **logs** folder - _log and other storage files_
-- **assets** folder - _e.g. user chosen chromedriver executable(s)_
-- **db** folder - _databases_
-- etc.
-
-
-
-
-### Set a _custom_ workspace folder
-You can use `set_workspace()` function to set a custom **workspace** folder,
-```python
-from instapy import InstaPy
-from instapy import set_workspace
-
-set_workspace("C:\\My\\Custom\\Path\\InstaPy\\")
-
-session = InstaPy(...)
-```
-
-
-
-
- Rules 🔎
-
-
-
-**1**-) You have to set your custom **workspace** folder before instantiates _InstaPy_.
-**2**-) Your custom **workspace** folder must have `InstaPy` (*_case sensitive_) word in its name.
-+ If your path does not have it,
-`set_workspace("C:\\Other\\Path\\InstaPie\\")`
-then your **workspace** folder will be named and made as,
-`"C:\\Other\\Path\\InstaPie\\InstaPy\\"`
-👆🏼 `InstaPy` directory will be added as a new subdirectory in there, and be your **workspace** folder.
-
-+ If your custom **workspace** folder name has a case-insensitive default name in it- `Instapy`, `instapy`, `instaPY`, etc.,
-`set_workspace("C:\\Other\\Path\\instapy2\\")`
-then your **workspace** folder will be,
-`"C:\\Other\\Path\\InstaPy2\\"`
-as you can see, it normalizes name and sets the **workspace** folder.
-
-
-##### _Why naming is so important?_
- - It will help to easily adapt to the flexible _InstaPy_ usage with that default formal name.
-
-
-
-
-### Set a custom **workspace** folder _permanently_ with ease
-If you want to set your custom **workspace** folder permanently and more easily, add a new environmental variable named `INSTAPY_WORKSPACE` with the value of the path of the desired **workspace** folder to your operating system.
-Then that will be the default **workspace** folder in all sessions [unless you change it using `set_workspace()` or so].
-
-
-### _Get_ the location of the workspace folder in use
-If you ever want to **get** the _location_ of your **workspace** folder, you can use
-the `get_workspace()` function,
-```python
-from instapy import InstaPy
-from instapy import smart_run
-from instapy import set_workspace
-from instapy import get_workspace
-
-set_workspace(path="C:\\Custom\\Path\\InstaPy_super\\")
-
-session = InstaPy(username="abc", password="123")
-
-with smart_run(session):
- # lots of code
- workspace_in_use = get_workspace()
- print(workspace_in_use["path"])
- # code code
-```
-Note that, `get_workspace()` is a function used _internally_ and makes a **workspace** folder [by default at home folder] if not exists.
-It means, you must use only the `set_workspace()` feature to set a custom **workspace** folder and not try to use `get_workspace()` for that purpose..
-
-
-### Set a custom _location_
-You can set any of the **custom** _locations_ you like, **any time**!
-E.g. setting the _location_ of the **database** file,
-```python
-from instapy import InstaPy
-from instapy import set_workspace
-from instapy import Settings
-
-
-set_workspace(...) # if you will set a custom workspace, set it before anything
-Settings.db_location = "C:\\New\\Place\\DB\\instapy.db"
-
-session = InstaPy(...)
-# code code
-```
-
-
-
-
-
- Restrictions 🔎
-
-
-
-**a**-) You cannot set a custom **workspace** folder after _InstaPy_ has been instantiated;
-_E.g. while instantiating _InstaPy_, you make a logger at that given location and trying to change the_ `log_location` _really needs to restart the LOGGER adapter and make another logger instance, but it can be achieved in future_.
-
-**b**-) If you set a custom **workspace** once and then set it again then your data locations will still use the previous locations:
-```python
-from instapy import InstaPy
-from instapy import set_workspace
-from instapy import Settings
-
-# first time settings custom workspace folder
-set_workspace("C:\\Users\\MMega\\Desktop\\My_InstaPy\\")
-# second time settings custom workspace folder
-set_workspace("C:\\Users\\MMega\\Documents\\My_InstaPy\\")
-
-# locations of data files, e.g. chromedriver executable, logfolder, db will use first custom workspace locations.
-# if you still want to change their location to second one, then do this one by one:
-Settings.log_location = "C:\\Users\\MMega\\Documents\\My_InstaPy\\logs\\"
-Settings.database_location = "C:\\Users\\MMega\\Documents\\My_InstaPy\\db\\instapy.db"
-Settings.chromedriver_location = "C:\\Users\\MMega\\Documents\\My_InstaPy\\logs\\chromedriver.exe"
-```
-As you can see, you have to use `set_workspace()` only once.
-Why it is so difficult in those 👆🏼 regards?
- - It's to preserve custom location assignments alive (`Settings.*`) cos otherwise setting another **workspace** would override any previously _manually_ assigned location(s).
-
-
-
-
-### Pass arguments by CLI
-###### It is recommended to pass your credentials from command line interface rather than storing them inside quickstart scripts.
-
-Note that, arguments passed from the CLI has higher priorities than the arguments inside a **quickstart** script.
-E.g., let's assume you have,
-```python
-# inside quickstart script
-
-session = InstaPy(username="abc")
-```
-and you start that **quickstart** script as,
-```erlang
-python quickstart.py -u abcdef -p 12345678
-```
-Then, your _username_ will be set as `abcdef` rather than `abc`.
-_And obviously, if you don't pass the flag, it'll try to get that argument from the **quickstart** script [if any]_.
-
-#### Currently these _flags_ are supported:
- 🚩 `-u` abc, `--username` abc
- - Sets your username.
-
- 🚩 `-p` 123, `--password` 123
- - Sets your password.
-
- 🚩 `-pd` 25, `--page-delay` 25
- - Sets the implicit wait.
-
- 🚩 `-pa` 192.168.1.1, `--proxy-address` 192.168.1.1
- - Sets the proxy address.
-
- 🚩 `-pp` 8080, `--proxy-port` 8080
- - Sets the proxy port.
-
- 🚩 `-hb`, `--headless-browser`
- - Enables headless mode.
-
- 🚩 `-dil`, `--disable-image-load`
- - Disables image load.
-
- 🚩 `-bsa`, `--bypass-suspicious-attempt`
- - Bypasses suspicious attempt.
-
- 🚩 `-bwm`, `--bypass-with-mobile`
- - Bypasses with mobile phone.
-
-To get the list of available commands, you can type,
-```erlang
-python quickstart.py -h
-# or
-python quickstart.py --help
-```
-
-#### Examples
-⚽ Let's quickly set your username and password right by CLI,
-```erlang
-python quickstart.py -u Toto.Lin8 -p 4X27_Tibor
-# or
-python quickstart.py --username Toto.Lin8 --password 4X27_Tibor
-# or
-python quickstart.py -u "Toto.Lin8" -p "4X27_Tibor"
-```
-
-
-
-
- Advanced 🔎
-
-
-
-You can **pass** and then **parse** the **_custom_** CLI arguments you like right inside the **quickstart** script.
-To do it, open up your **quickstart** script and add these lines,
-```python
-# inside quickstart script
-
-import argparse
-
-my_parser = argparse.ArgumentParser()
-# add the arguments as you like WHICH you will pass
-# e.g., here is the simplest example you can see,
-my_parser.add_argument("--my-data-files-name")
-args, args_unknown = my_parser.parse_known_args()
-
-filename = args.my_data_files_name
-
-# now you can print it
-print(filename)
-
-# or open that file
-with open(filename, 'r') as f:
- my_data = f.read()
-```
-After adding your custom arguments to the **quickstart** script, you can now **pass** them by CLI, comfortably,
-```erlang
-python quickstart.py --my-data-files-name "C:\\Users\\Anita\\Desktop\\data_file.txt"
-```
->**NOTE**:
-Use **dash** in flag and parse them with **underscores**;
-E.g., we have used the flag as **`--my-data-files-name`** and parsed it as `args.`**`my_data_files_name`** ...
-
->**PRO**:
-See `parse_cli_args()` function [used internally] inside the **util.py** file to write & parse more advanced flags.
-You can also import that function into your **quickstart** script and parse the **formal** flags into there to be used, as well.
-
-```python
-# inside quickstart script
-
-from instapy.util import parse_cli_args
-
-
-cli_args = parse_cli_args()
-username = cli_args.username
-
-print(username)
-```
-👆🏼👉🏼 as you will pass the _username_ like,
-```erlang
-python quickstart.py -u abc
-```
-
-
-
-
-
-
-## Extensions
-[1. Session scheduling with Telegram](https://github.com/Tkd-Alex/Telegram-InstaPy-Scheduling)
-
-
-### Custom geckodriver
-By default, InstaPy downloads the latest version of the geckodriver.
-Unless you need a specific version of the geckodriver, you're ready to go.
-
-You can manually download the geckodriver binary and put the path as an argument to the InstaPy constructor:
-
-```python
-session = InstaPy(..., geckodriver_path = '/path/to/binary', ...)
-```
-
-### Using one of the templates
-
-If you're interested in what other users setup looks like, feel free to check out the `quickstart_templates` folder which includes several working setups with different features.
-
-In order to use them, just copy the desired file and put it next to the `quickstart.py` file in the, what is called root, directory.
-
-Finally simply adjust the username and any tags or firend lists before executing it.
-That's it.
-
-
-### How not to be banned
-Built-in delays prevent your account from getting banned.
-However, excessive use of this tool may result in action blocks or permanent bans.
-Use the Quota Supervisor feature to set some fixed limits for the bot for maximum safety.
-
-
-### Disable Image Loading
-If you want to save some bandwidth, you can simply disable the image/video loading. This will lead to, if you watch InstaPy running, not downloading and displaying any more images and videos.
-
-> Note: This can save a tremendous amount of data. This is turned off by default (`False`).
-
-To do this simply pass the `disable_image_load=True` parameter in the InstaPy constructor like so:
-```python
-session = InstaPy(username=insta_username,
- password=insta_password,
- headless_browser=False,
- disable_image_load=True,
- multi_logs=True)
-```
-
-### Changing DB or location
-If you want to change the location/path of the DB, simply head into the `instapy/settings.py` file and change the following lines.
-Set these in instapy/settings.py if you're locating the library in the /usr/lib/pythonX.X/ directory.
-```
-Settings.database_location = '/path/to/instapy.db'
-```
-
-### Split SQLite by Username
-If you experience issue with multiple accounts Instapy.db lockup. You can add the following flag
-
-`-sdb` when running in Command line
-
-or
-
-To do this simply pass the `split_db=True` parameter in the InstaPy constructor like so:
-
-```python
-session = InstaPy(username=insta_username,
- password=insta_password,
- headless_browser=False,
- split_db=True,
- multi_logs=True)
-```
-
-
-
-### How to avoid _python_ & **pip** confusion
-
-Sometimes you have **multiple** _python_ installations in your system.
-Then you'll obviously have crazy aliases linked to _python_ and **pip** commands.
-
-For example, let's assume you have _python_ 2.7 & _python_ 3.7 installed in your system,
-
-| _python_ version | _python_ alias | **pip** alias |
-| ---------------- | -------------- | ------------- |
-| 2.7 | `py2` | `pip` |
-| 3.7 | `python` | `pip3` |
-
-And once you install a package by the `pip` command and try to run it with `python` command, it will confuse you.
-
-Why? - cos,
-- `pip` command is for _python_ 2.7
-- `python` command is for _python_ 3.7
-
-To solve that confusion, use this **style** to install packages by **pip**,
-```powershell
-# install "instapy" package into python 3.7
-python -m pip install instapy
-
-# install "instapy" package into python 2.7
-py2 -m pip install instapy
-```
-
-As you can see, it is,
-`python -m pip ...`
-rather than,
-`pip ...`
-
-Other **pip** commands can be accomplished the same way, too.
-Such as,
-```powershell
-# update "instapy" package
-python -m pip install instapy -U
-
-# uninstall "instapy" package
-python -m pip uninstall instapy
-
-# show details of the "instapy" package installed by pip
-python -m pip show instapy
-```
-
-Using this style, you will never have to worry about what is the correct alias of the **pip** for you specific _python_ installation and all you have to know is just the _python_'s alias you use.
-
-### Dealing with Selenium Common Exception Issues
-
-##### selenium.common.exceptions.WebDriverException: Message: unknown error: Cannot read property 'entry_data' of undefined
-This error could also caused by unstable Internet connection or Instagram's web changed their data-structure.
-
-##### TL;DR - Make sure your chromedriver version is compatible with your Google Chrome version.
-Occasionally *Instapy* will stop working because one of the issues below has been thrown.
-
->_Traceback (most recent call last):
-....// File list with the exception trace
-selenium.common.exceptions.WebDriverException: Message: unknown error: Cannot read property 'entry_data' of undefined
-(Session info: headless **chrome=75.0.3770.80**)
-(Driver info: **chromedriver=2.36.540469** (1881fd7f8641508feb5166b7cae561d87723cfa8),platform=Mac OS X 10.14.5 x86_64)
-
->_Traceback (most recent call last):
-....// File list with the exception traceselenium.common.exceptions.WebDriverException: Message: unknown error: unknown sessionId
-(Session info: headless **chrome=75.0.3770.80**)
-(Driver info: **chromedriver=2.36.540469** (1881fd7f8641508feb5166b7cae561d87723cfa8),platform=Mac OS X 10.14.5 x86_64)
-
-Notice that *chrome* version is **75** and the *chromedriver* version is **2.36**.
-
-According to the [release notes](https://chromedriver.storage.googleapis.com/2.36/notes.txt) for chromedriver, version 2.36 only supports Chrome versions 63-65.
-
-Which means, there is a mismatch in chromedriver and Chrome that installed on my machine.
-
-There several steps to this fix.
-
-1. Completely uninstall Google Chrome.
-2. Download an older version.
-3. Prevent Google Chrome from auto-updating.
-
-
-#### MAC FIX
-Since *Instapy* seems to work well, in my experience on my Mac, with chromedriver version 2.36, I will downgrade my Google Chrome. I do not use Google Chrome, so this isn't an issue.
-
-
-1. **Uninstall Google Chrome**
- I used an app called [App Cleaner](https://freemacsoft.net/appcleaner/) to remove Chrome.
- After you install App Cleaner, simply drag Google Chrome, from the Applications folder to App Cleaner and Remove All
-
-2. **Download Chrome 65** *(Read this step completely before proceeding)*
- - Find and install Chrome 65 from [sllimjet.com](https://www.slimjet.com/chrome/google-chrome-old-version.php)
-
- - After you have installed Chrome 65, open and click the Apple Security Ok button that alerts you to the fact this was downloaded from the internet.
- - THEN, immediately close Google Chrome completely by holding **`CMD+Q`**. This is extremely important! Google Chrome will being its auto-update function. So it must be completely closed, not just the window.
- *We need Chrome to run first and put all its files where it needs them.*
-
-3. **Prevent Google Chrome from updating**
- - Open **Terminal** and type
- `sudo chmod -R 000 ~/Library/Google`
-
- - You will be asked for your computer password, enter it.
-
- - Next run the command
- `sudo rm -rf /Library/Google/`
-
- Google Chrome should not be able to auto-update now.
-
-If for some reason Chrome is still updating, or you're unable to run the command in step 3, you can edit your `/etc/hosts file` to include the following line: `0.0.0.0 tools.google.com`
-
-
-#### Windows Fix
-Coming soon
-
-#### Raspberry Pi Fix
-Coming Soon
-
-
----
-
-###### Have Fun & Feel Free to report any issues
-### [Windows Task Scheduler](https://msdn.microsoft.com/en-us/library/windows/desktop/aa383614(v=vs.85).aspx)
-### [Windows Task Scheduler](https://msdn.microsoft.com/en-us/library/windows/desktop/aa383614(v=vs.85).aspx)
-### [Windows Task Scheduler](https://msdn.microsoft.com/en-us/library/windows/desktop/aa383614(v=vs.85).aspx)
-
-You can use Window's built in Task Scheduler to automate InstaPy, using a variety of trigger types: time, login, computer idles, etc. To schedule a simple daily run of an Instapy script follow the below directions
-1. Open [Windows Task Scheduler](https://msdn.microsoft.com/en-us/library/windows/desktop/aa383614(v=vs.85).aspx)
-2. Select "Create Basic Task"
-3. Fill out "Name" and "Description" as desired, click "Next"
-4. On "Trigger" screen select how frequently to run, click "Next" (Frequency can be modified later)
-5. On "Daily" screen, hit "Next"
-6. "Action Screen" select "Start a program" and then click "Next"
-7. "Program/script" enter the path, or browse to select the path to python. ([How to find python path on Windows](https://stackoverflow.com/questions/647515/how-can-i-get-python-path-under-windows))
-8. "Add arguments" input the InstaPy script path you wish to run. (Example: C:\Users\USER_NAME\Documents\GitHub\InstaPy\craigquick.py)
-9. "Start in" input Instapy install location (Example: C:\Users\USER_NAME\Documents\GitHub\InstaPy\). Click "Next"
-10. To finish the process, hit "Finish"
-
-### `cron`
-You can add InstaPy to your crontab, so that the script will be executed regularly. This is especially useful for servers, but be sure not to break Instagrams follow and like limits.
-
-```
-# Edit or create a crontab
-crontab -e
-# Add information to execute your InstaPy regularly.
-# With cd you navigate to your InstaPy folder, with the part after &&
-# you execute your quickstart.py with python. Make sure that those paths match
-# your environment.
-45 */4 * * * cd /home/user/InstaPy && /usr/bin/python ./quickstart.py
-```
-
-
-### [Schedule](https://github.com/dbader/schedule)
-> Schedule is an in-process scheduler for periodic jobs that uses the builder pattern for configuration. Schedule lets you run Python functions periodically at pre-determined intervals using a simple, human-friendly syntax.
-
-```shell
-pip install schedule
-```
-
-```python
-from instapy import InstaPy
-from instapy import smart_run
-from instapy import set_workspace
-import schedule
-import time
-
-#your login credentials
-insta_username=''
-insta_password=''
-
-#path to your workspace
-set_workspace(path=None)
-
-def job():
- session = InstaPy(username=insta_username, password=insta_password)
- with smart_run(session):
- session.set_do_comment(enabled=True, percentage=20)
- session.set_comments(['Well done!'])
- session.set_do_follow(enabled=True, percentage=5, times=2)
- session.like_by_tags(['love'], amount=100, media='Photo')
-
-
-schedule.every().day.at("6:35").do(job)
-schedule.every().day.at("16:22").do(job)
-
-while True:
- schedule.run_pending()
- time.sleep(10)
-```
-
-You can use Window's built in Task Scheduler to automate InstaPy, using a variety of trigger types: time, login, computer idles, etc. To schedule a simple daily run of an Instapy script follow the below directions
-1. Open [Windows Task Scheduler](https://msdn.microsoft.com/en-us/library/windows/desktop/aa383614(v=vs.85).aspx)
-2. Select "Create Basic Task"
-3. Fill out "Name" and "Description" as desired, click "Next"
-4. On "Trigger" screen select how frequently to run, click "Next" (Frequency can be modified later)
-5. On "Daily" screen, hit "Next"
-6. "Action Screen" select "Start a program" and then click "Next"
-7. "Program/script" enter the path, or browse to select the path to python. ([How to find python path on Windows](https://stackoverflow.com/questions/647515/how-can-i-get-python-path-under-windows))
-8. "Add arguments" input the InstaPy script path you wish to run. (Example: C:\Users\USER_NAME\Documents\GitHub\InstaPy\craigquick.py)
-9. "Start in" input Instapy install location (Example: C:\Users\USER_NAME\Documents\GitHub\InstaPy\). Click "Next"
-10. To finish the process, hit "Finish"
-
-
-
diff --git a/docs/automate-instapy.md b/docs/automate-instapy.md
deleted file mode 100644
index 96106bebf..000000000
--- a/docs/automate-instapy.md
+++ /dev/null
@@ -1,81 +0,0 @@
----
-title: Automate InstaPy
----
-
-### [Windows Task Scheduler](https://msdn.microsoft.com/en-us/library/windows/desktop/aa383614(v=vs.85).aspx)
-
-You can use Window's built in Task Scheduler to automate InstaPy, using a variety of trigger types: time, login, computer idles, etc. To schedule a simple daily run of an Instapy script follow the below directions
-1. Open [Windows Task Scheduler](https://msdn.microsoft.com/en-us/library/windows/desktop/aa383614(v=vs.85).aspx)
-2. Select "Create Basic Task"
-3. Fill out "Name" and "Description" as desired, click "Next"
-4. On "Trigger" screen select how frequently to run, click "Next" (Frequency can be modified later)
-5. On "Daily" screen, hit "Next"
-6. "Action Screen" select "Start a program" and then click "Next"
-7. "Program/script" enter the path, or browse to select the path to python. ([How to find python path on Windows](https://stackoverflow.com/questions/647515/how-can-i-get-python-path-under-windows))
-8. "Add arguments" input the InstaPy script path you wish to run. (Example: C:\Users\USER_NAME\Documents\GitHub\InstaPy\craigquick.py)
-9. "Start in" input Instapy install location (Example: C:\Users\USER_NAME\Documents\GitHub\InstaPy\). Click "Next"
-10. To finish the process, hit "Finish"
-
-
-### `cron`
-You can add InstaPy to your crontab, so that the script will be executed regularly. This is especially useful for servers, but be sure not to break Instagrams follow and like limits.
-
-```
-# Edit or create a crontab
-crontab -e
-# Add information to execute your InstaPy regularly.
-# With cd you navigate to your InstaPy folder, with the part after &&
-# you execute your quickstart.py with python. Make sure that those paths match
-# your environment.
-45 */4 * * * cd /home/user/InstaPy && /usr/bin/python ./quickstart.py
-```
-
-
-### [Schedule](https://github.com/dbader/schedule)
-> Schedule is an in-process scheduler for periodic jobs that uses the builder pattern for configuration. Schedule lets you run Python functions periodically at pre-determined intervals using a simple, human-friendly syntax.
-
-```shell
-pip install schedule
-```
-
-```python
-from instapy import InstaPy
-from instapy import smart_run
-from instapy import set_workspace
-import schedule
-import time
-
-#your login credentials
-insta_username=''
-insta_password=''
-
-#path to your workspace
-set_workspace(path=None)
-
-def job():
- session = InstaPy(username=insta_username, password=insta_password)
- with smart_run(session):
- session.set_do_comment(enabled=True, percentage=20)
- session.set_comments(['Well done!'])
- session.set_do_follow(enabled=True, percentage=5, times=2)
- session.like_by_tags(['love'], amount=100, media='Photo')
-
-
-schedule.every().day.at("6:35").do(job)
-schedule.every().day.at("16:22").do(job)
-
-while True:
- schedule.run_pending()
- time.sleep(10)
-```
-
-
-
diff --git a/docs/home.md b/docs/home.md
deleted file mode 100644
index 75ff8cbb9..000000000
--- a/docs/home.md
+++ /dev/null
@@ -1,177 +0,0 @@
----
-title: Home
-hide_title: true
-slug: /
----
-
-
-
-
InstaPy
- Tooling that automates your social media interactions to "farm" Likes, Comments, and Followers on Instagram implemented in Python using the Selenium module.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-[Twitter of InstaPy](https://twitter.com/InstaPy) | [Discord Channel](https://discord.gg/FDETsht) | [How it works (FreeCodingCamp)](https://www.freecodecamp.org/news/my-open-source-instagram-bot-got-me-2-500-real-followers-for-5-in-server-costs-e40491358340/) |
-[Talk about automating your Instagram](https://youtu.be/4TmKFZy-ioQ) | [Talk about doing Open-Source work](https://www.youtube.com/watch?v=A_UtST302Og&t=0s&list=PLa4P1NPX9hthXV-wko0xyxFpbhYZFkW7o) | [Listen to the "Talk Python to me"-Episode](https://talkpython.fm/episodes/show/142/automating-the-web-with-selenium-and-instapy)
-
-
-**Newsletter: [Sign Up for the Newsletter here!](http://eepurl.com/cZbV_v)**
-**Guide to Bot Creation: [Learn to Build your own Bots](https://www.udemy.com/course/the-complete-guide-to-bot-creation/?referralCode=7418EBB47E11E34D86C9)**
-
-
-
-## **Installation**
-```elm
-pip install instapy
-```
-__Important:__ depending on your system, make sure to use `pip3` and `python3` instead.
-
-
-**That's it! 🚀**
-If you're on Ubuntu, read the specific guide on [Installing on Ubuntu (64-Bit)](https://github.com/InstaPy/instapy-docs/blob/master/How_Tos/How_To_DO_Ubuntu_on_Digital_Ocean.md). If you're on a Raspberry Pi, read the [Installing on RaspberryPi](https://github.com/InstaPy/instapy-docs/blob/master/How_Tos/How_to_Raspberry.md) guide instead.
-
->If you would like to install a specific version of Instapy you may do so with:
->```elm
->pip install instapy==0.1.1
->```
-
-#### Running Instapy
-
-To run InstaPy, you'll need to run the **[quickstart](https://github.com/InstaPy/instapy-quickstart)** script you've just downloaded.
-
-- [Here is the easiest **quickstart** script you can use](https://github.com/InstaPy/instapy-quickstart/blob/master/quickstart.py)
-
-- [And here you can find lots of sophisticated **quickstart** templates shared by the community!](https://github.com/InstaPy/instapy-quickstart/tree/master/quickstart_templates)
-
-You can put in your account details now by passing the username and password parameters to the `InstaPy()` function in your **quickstart** script, like so:
-```python
-InstaPy(username="abcd",
- password="1234")
-```
-Or you can [pass them using the Command Line Interface (CLI)](/additional-information#pass-arguments-by-cli).
-
-Once you have your **quickstart** script configured you can execute the script with the following commands.
-
-```elm
-python quickstart.py
--- or
-python quickstart.py --username abcd --password 1234
-```
-
-InstaPy will now open a browser window and start working.
-
-> If want InstaPy to run in the background pass the `--headless-browser` option when running from the CLI
-Or add the `headless_browser=True` parameter to the `InstaPy(headless_browser=True)` constructor.
-
-#### Updating InstaPy
-```elm
-pip install instapy -U
-```
-
-## Guides
-
-#### Video tutorials:
-**[Complete Guide to Bot Creation](https://www.udemy.com/course/the-complete-guide-to-bot-creation/?referralCode=7418EBB47E11E34D86C9)**
-
-**[Installation on Windows](https://www.youtube.com/watch?v=9DkEl2MrFQk&list=PLa4P1NPX9hthXV-wko0xyxFpbhYZFkW7o&index=11&t=40s)**
-
-**[Installation on MacOS](https://www.youtube.com/watch?v=TqQWM63Hhh4&t=11s&list=PLa4P1NPX9hthXV-wko0xyxFpbhYZFkW7o&index=12)**
-
-**[Installation on Linux](https://www.youtube.com/watch?v=sZ-SFy9vKHg&list=PLa4P1NPX9hthXV-wko0xyxFpbhYZFkW7o&index=10&t=28s)**
-
-**[Installation on DigitalOcean Server](https://www.youtube.com/watch?v=my0FM5hra_s&t=14s&list=PLa4P1NPX9hthXV-wko0xyxFpbhYZFkW7o&index=9)**
-
-#### Written Guides:
-**[How to Ubuntu (64-Bit)](https://github.com/InstaPy/instapy-docs/blob/master/How_Tos/How_To_DO_Ubuntu_on_Digital_Ocean.md) **
-
-**[How to RaspberryPi](https://github.com/InstaPy/instapy-docs/blob/master/How_Tos/How_to_Raspberry.md) **
-
-**[RealPythons InstaPy Guide](https://realpython.com/instagram-bot-python-instapy/) **
-
-**[InstaPy : développez vous-même votre bot Instagram !](https://www.yubigeek.com/instapy-bot-instagram/) **
-
-## External Tools:
-
-**[InstaPy Dashboard (Deprecated) ](https://github.com/converge/instapy-dashboard)**
-> InstaPy Dashboard is an Open Source project developed by [@converge](https://github.com/converge/) to visualize Instagram accounts progress and real-time InstaPy logs on the browser.
-
-**[InstaPy GUI](https://github.com/breuerfelix/instapy-gui)**
-> InstaPy GUI is a Graphical User Interface including some useful Analytics developed by [@breuerfelix](https://github.com/breuerfelix).
-
-
-## Docker
-All information on how to use InstaPy with Docker can be found in the [instapy-docker](https://github.com/InstaPy/instapy-docker) repository.
-
-## Support
-
-### Do you need help?
-If you should encounter any issue, please first [search for similar issues](https://github.com/timgrossmann/InstaPy/issues) and only if you can't find any, create a new issue or use the [discord channel](https://discord.gg/FDETsht) for help.
-
-
-
-
-
-### Do you want to support us?
-
-
-
-
-
-
-
-**Help build InstaPy!**
-Check out this short guide on [how to start contributing!](https://github.com/InstaPy/instapy-docs/blob/master/CONTRIBUTORS.md).
-
-## Credits
-
-### Community
-An active and supportive community is what every open-source project needs to sustain. Together we reached every continent and most of the countries in the world!
-Thank you all for being part of the InstaPy community ✌️
-
-
-
-### Contributors
-
-This project exists thanks to all the people who contribute. [[Contribute](https://github.com/timgrossmann/InstaPy/wiki/How-to-Contribute)].
-
-
-
-### Backers
-
-Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/instapy#backer)]
-
-
-
-### Sponsors
-
-Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/instapy#sponsor)]
-
-
-
-
-
----
-
-> **Disclaimer** : Please Note that this is a research project. I am by no means responsible for any usage of this tool. Use on your own behalf. I'm also not responsible if your accounts get banned due to extensive use of this tool.
diff --git a/docs/instance-settings.md b/docs/instance-settings.md
deleted file mode 100644
index 522ddb2f5..000000000
--- a/docs/instance-settings.md
+++ /dev/null
@@ -1,143 +0,0 @@
----
-title: Instance Settings
----
-
-### Running on a Headless Browser
-
-Use `headless_browser` parameter to run the bot via the CLI. Works great if running the scripts locally, or to deploy on a server. No GUI, less CPU intensive. [Example](http://g.recordit.co/BhEgXANLhJ.gif)
-
-**Warning:** Some users discourage the use of this feature as Instagram could [detect](https://antoinevastel.com/bot%20detection/2017/08/05/detect-chrome-headless.html) this headless mode!
-
-```python
-session = InstaPy(username='test', password='test', headless_browser=True)
-```
-
-**(Alternative)**
-If the web driver you're using doesn't support headless mode (or the headless mode becomes very detectable), you can use the `nogui` parameter which displays the window out of view. Keep in mind, this parameter lacks support and ease of use, only supporting Linux based operating systems (or those that have Xvfb, Xephyr and Xvnc display software).
-
-```python
-session = InstaPy(username='test', password='test', nogui=True)
-```
-
-### Bypass Suspicious Login Attempt
-
-InstaPy detects automatically if the Security Code Challenge
-is active, if yes, it will ask you for the Security Code on
-the terminal.
-
-The Security Code is send to your Email or SMS by Instagram, Email is the default option, but you can choose SMS also with:
-
-`bypass_security_challenge_using='sms'` or `bypass_security_challenge_using='email'`
-
-```python
-InstaPy(username=insta_username,
- password=insta_password,
- bypass_security_challenge_using='sms')
-```
-
-### Two Factor Authentication
-InstaPy detects automatically if the account is protected with the Two Factor Authentication, if yes InstaPy user need to provide the Security codes in the session constructor; at least one code is required.
-
-Security codes can be found in: `Settings` -> `Security` -> `Two-Factor-Authentication` -> `Backup Codes`
-
-```python
-InstaPy(username=insta_username,
- password=insta_password,
- security_codes=["01234567", "76543210", "01237654"],)
-```
-
-
-
-
-### Use a proxy
-
-You can use InstaPy behind a proxy by specifying server address, port and/or proxy authentication credentials. It works with and without ```headless_browser``` option.
-
-Simple proxy setup example:
-
-```python
-session = InstaPy(username=insta_username,
- password=insta_password,
- proxy_address='8.8.8.8',
- proxy_port=8080)
-```
-
-Proxy setup with authentication example:
-
-```python
-session = InstaPy(username=insta_username,
- password=insta_password,
- proxy_username='',
- proxy_password='',
- proxy_address='8.8.8.8',
- proxy_port=4444)
-```
-
-### Running internet connection checks
-InstaPy can perform a few checks online, including you connection and the availability of Instagram servers. These checks sometimes fail because Instapy uses third party services to perform these checks. If this should be the case. you can override these checks with this variable: `want_check_browser`.
-
-`want_check_browser` default is False, you can set it to True at session start. Recommend to do this if you want to add additional checks for the connection to the web and Instagram.
-
-For example:
-
-```python
-session = InstaPy(username=insta_username,
- password=insta_password,
- want_check_browser=True)
-```
-
-### Running in threads
-If you're running InstaPy in threads and get exception `ValueError: signal only works in main thread` , you have to properly close the session.
-There is two ways to do it:
-
-Closing session in smart_run context:
-
-```python
-session = InstaPy()
-with smart_run(session, threaded=True):
- """ Activity flow """
- # some activity here ...
-```
-
-Closing session with `end()` method
-
-```python
-session = InstaPy()
-session.login()
-# some activity here ...
-session.end(threaded_session=True)
-```
-
-### Choose the browser version
-If you have more than one Firefox version on your system or if you are using a portable version you can instruct InstaPy to use that version using the `browser_executable_path` argument in the class initializer.
-
-Specifying the Firefox executable path can also help you if you are getting the following error message:
-
-`selenium.common.exceptions.SessionNotCreatedException: Message: Unable to find a matching set of capabilities`
-
-Example on a Windows machine (with the right path also works on Linux and macOS)
-
-```python
-session = InstaPy(username=insta_username,
- password=insta_password,
- browser_executable_path=r"D:\Program Files\Mozilla Firefox\firefox.exe")
-```
-
-
-
diff --git a/docs/relationship-tools.md b/docs/relationship-tools.md
deleted file mode 100644
index a85c8ce41..000000000
--- a/docs/relationship-tools.md
+++ /dev/null
@@ -1,379 +0,0 @@
----
-title: Relationship Tools
----
-
-### Grab Followers of a user
-
-###### Gets and returns `followers` of the given user in desired amount, also can save locally
-```python
-popeye_followers = session.grab_followers(username="Popeye", amount="full", live_match=True, store_locally=True)
-##now, `popeye_followers` variable which is a list- holds the `Followers` data of "Popeye" at requested time
-```
-#### Parameters:
-`username`:
-A desired username to grab its followers
-* It can be your `own` username **OR** a _username of some `non-private` account._
-
-`amount`:
-Defines the desired amount of usernames to grab from the given account
-* `amount="full"`:
- + Grabs followers **entirely**
-* `amount=3089`:
- * Grabs `3089` usernames **if exist**, _if not_, grabs **available** amount
-
-`live_match`:
-Defines the method of grabbing `Followers` data
-> **Knowledge Base**:
-Every time you grab `Followers` data in `"full"` range of **any** user, it is also gonna be _stored in some corner_ of `InstaPy` **for that session**.
-
-+ `live_match=False`:
- + If the user **already do have** a `Followers` data loaded _earlier_ in the **same** session, it will run a _smart_ `data-matching` _algorithm_.
- And **there**, it will **load only the new data** _from the server_ and then **return a compact result** of _current data_.
- The _algorithm_ **works like**: _load the usernames **until hits the** ones from the **previous query** at certain amount_.
- + **Also if** the `live_match` is `False` and the user has **no any** _sessional_ `Followers` data, **then** it will load `live` data at _requested range_.
- + As a **result**, `live_match=False` saves lots of `precious time` and `server requests`.
-+ `live_match=True`:
- + It will **always** load `live` data from the server at _requested range_.
-
-`store_locally`:
-Gives the _option_ to `save` the loaded `Followers` data in a **local storage**
-The files will be saved _into_ your **logs folder**, `~/InstaPy/logs/YourOwnUsername/relationship_data/Popeye/followers/` directory.
-Sample **filename** `14-06-2018~full~6874.json`:
-+ `14-06-2018` means the **time** of the data acquisition.
-+ `"full"` means the **range** of the data acquisition;
-_If the data is requested at the range **else than** `"full"`, it will write **that** range_.
-+ `6874` means the **count** of the usernames retrieved.
-+ `json` is the **filetype** and the data is stored as a `list` in it.
-
-`verified_only`:
-Gives the _option_ to only return followers with a Verified status.
-* `verified_only=True`:
- + Only returns followers that contain `is_verified` key
-* `verified_only=False`:
- + Default option, Returns all followers for user
-
-
-There are **several** `use cases` of this tool for **various purposes**.
-_E.g._, inside your **quickstart** script, you can **do** _something like this_:
-```python
-#get followers of "Popeye" and "Cinderella"
-popeye_followers = session.grab_followers(username="Popeye", amount="full", live_match=True, store_locally=True)
-sleep(600)
-cinderella_followers = session.grab_followers(username="Cinderella", amount="full", live_match=True, store_locally=True)
-
-#find the users following "Popeye" WHO also follow "Cinderella" :D
-popeye_cinderella_followers = [follower for follower in popeye_followers if follower in cinderella_followers]
-```
-
-#### PROs
-You can **use** this tool to take a **backup** of _your_ **or** _any other user's_ **current** followers.
-
-
-
-
-### Grab Following of a user
-###### Gets and returns `following` of the given user in desired amount, also can save locally
-```python
-lazySmurf_following = session.grab_following(username="lazy.smurf", amount="full", live_match=True, store_locally=True)
-##now, `lazySmurf_following` variable which is a list- holds the `Following` data of "lazy.smurf" at requested time
-```
-#### Parameters:
-`username`:
-A desired username to grab its following
-* It can be your `own` username **OR** a _username of some `non-private` account._
-
-`amount`:
-Defines the desired amount of usernames to grab from the given account
-* `amount="full"`:
- + Grabs following **entirely**
-* `amount=3089`:
- * Grabs `3089` usernames **if exist**, _if not_, grabs **available** amount
-
-`live_match`:
-Defines the method of grabbing `Following` data
-> **Knowledge Base**:
-Every time you grab `Following` data in `"full"` range of **any** user, it is also gonna be _stored in some corner_ of `InstaPy` **for that session**.
-
-+ `live_match=False`:
- + If the user **already do have** a `Following` data loaded _earlier_ in the **same** session, it will run a _smart_ `data-matching` _algorithm_.
- And **there**, it will **load only the new data** _from the server_ and then **return a compact result** of _current data_.
- The _algorithm_ **works like**: _load the usernames **until hits the** ones from the **previous query** at certain amount_.
- + **Also if** the `live_match` is `False` and the user has **no any** _sessional_ `Following` data, **then** it will load `live` data at _requested range_.
- + As a **result**, `live_match=False` saves lots of `precious time` and `server requests`.
-+ `live_match=True`:
- + It will **always** load `live` data from the server at _requested range_.
-
-`store_locally`:
-Gives the _option_ to `save` the loaded `Following` data in a **local storage**
-The files will be saved _into_ your **logs folder**, `~/InstaPy/logs/YourOwnUsername/relationship_data/lazy.smurf/following/` directory.
-Sample **filename** `15-06-2018~full~2409.json`:
-+ `15-06-2018` means the **time** of the data acquisition.
-+ `"full"` means the **range** of the data acquisition;
-_If the data is requested at the range **else than** `"full"`, it will write **that** range_.
-+ `2409` means the **count** of the usernames retrieved.
-+ `json` is the **filetype** and the data is stored as a `list` in it.
-
-
-There are **several** `use cases` of this tool for **various purposes**.
-_E.g._, inside your **quickstart** script, you can **do** _something like this_:
-```python
-##as we know that all lazy Smurf care is to take some good rest, so by mistake, he can follow somebody WHOM Gargamel also follow!
-#so let's find it out to save Smurfs from troubles! :D
-
-#get following of "lazy.smurf" and "Gargamel"
-lazySmurf_following = session.grab_following(username="lazy.smurf", amount="full", live_match=True, store_locally=True)
-sleep(600)
-gargamel_following = session.grab_following(username="Gargamel", amount="full", live_match=True, store_locally=True)
-
-#find the users "lazy.smurf" is following WHOM "Gargamel" also follow :D
-lazySmurf_gargamel_following = [following for following in lazySmurf_following if following in gargamel_following]
-```
-
-#### PROs
-You can **use** this tool to take a **backup** of _your_ **or** _any other user's_ **current** following.
-
-
-### Pick Unfollowers of a user
-###### Compares the `followers` stored in a local storage against current followers and returns absent followers
-```python
-all_unfollowers, active_unfollowers = session.pick_unfollowers(username="Bernard_bear", compare_by="month", compare_track="first", live_match=True, store_locally=True, print_out=True)
-##now, `all_unfollowers` and `all_unfollowers` variables which are lists- hold the `Unfollowers` data of "Bernard_bear" at requested time
-#`all_unfollowers` holds all of the unfollowers WHILST `active_unfollowers` holds the unfollowers WHOM "Bernard_bear" is still following
-```
-#### Parameters:
-`username`:
-A desired username to pick its unfollowers
-* It can be your `own` username **OR** a _username of some `non-private` account._
-
-`compare_by`:
-Defines the `compare point` to pick unfollowers
-+ Available **value**s are:
- + `"latest"` chooses the very latest record from the existing records in the local folder
- + `"earliest"` chooses the very earliest record from the existing records in the local folder
-
- The compare points below needs a **compare track** defined, too:
- + `"day"` chooses from the existing records of today in the local folder
- + `"month"` chooses from the existing records of this month in the local folder
- + `"year"` chooses from the existing records of this year in the local folder
-
-`compare_track`:
-Defines the track to choose a file to compare for `"day"`, `"month"` and `"year"` compare points
-+ Available **value**s are:
- + `"first"` selects the first record from the given `day`, `month` or `year`
- + `"median"` selects the median (_the one in the middle_) record from the given `day`, `month` or `year`
- + `"last"` selects the last record from the given `day`, `month` or `year`
-
-`live_match`:
-Defines the method of grabbing **new** `Followers` data to compare with **existing** data
-> **Knowledge Base**:
-Every time you grab `Followers` data in `"full"` range of **any** user, it is also gonna be _stored in some corner_ of `InstaPy` **for that session**.
-
-+ `live_match=False`:
- + If the user **already do have** a `Followers` data loaded _earlier_ in the **same** session, it will run a _smart_ `data-matching` _algorithm_.
- And **there**, it will **load only the new data** _from the server_ and then **return a compact result** of _current data_.
- The _algorithm_ **works like**: _load the usernames **until hits the** ones from the **previous query** at certain amount_.
- + **Also if** the `live_match` is `False` and the user has **no any** _sessional_ `Followers` data, **then** it will load `live` data at _requested range_.
- + As a **result**, `live_match=False` saves lots of `precious time` and `server requests`.
-+ `live_match=True`:
- + It will **always** load `live` data from the server at _requested range_.
-
-`store_locally`:
-Gives the _option_ to `save` the loaded `Unfollowers` data in a **local storage**
-There will be 2 files saved in their own directory:
-+ `all_unfollowers`:
- + Will store all of the unfollowers in there
- + Its files will be saved at **logs folder**, `~/InstaPy/logs/YourOwnUsername/relationship_data/Bernard_bear/unfollowers/all_unfollowers/` directory.
-+ `active_unfollowers`:
- + Will store only the unfollowers WHOM you are currently following.
- + Its files will be saved at **logs folder**, `~/InstaPy/logs/YourOwnUsername/relationship_data/Bernard_bear/unfollowers/active_unfollowers/` directory.
-
-Sample **filename** `03-06-2018~all~75.json`:
-+ `03-06-2018` means the **time** of the data acquisition.
-+ `"all"` means that it is all of the unfollowers data;
-_*`"active"` unfollowers files will have `"active"` written in there_.
-+ `75` means the **count** of the unfollowers retrieved.
-+ `json` is the **filetype** and the data is stored as a `list` in it.
-
-`print_out`:
-Use this parameter if you would like the `see` those unfollowers **printed** into the **console output** _right after finding them_.
-
-There are **several** `use cases` of this tool for **various purposes**.
-+ You can the get the unfollowers you have had from the **start of the** _year_, or from the **middle of the** _year_ or from the start of the **month**, etc.
-And then, e.g. do some `useful` **analysis** with that _generated unfollowers data_.
-+ _And_ you can also **find** the unfollowers to `block` them **all**.
-+ Also, you can **unfollow back** those `active unfollowers` _right away_:
-```python
-#find all of the active unfollowers of Bernard bear
-all_unfollowers, active_unfollowers = session.pick_unfollowers(username="Bernard_bear", compare_by="earliest", compare_track="first", live_match=True, store_locally=True, print_out=True)
-sleep(200)
-#let's unfollow them immediately cos Bernard will be angry if heards about those unfollowers! :D
-session.unfollow_users(amount=len(active_unfollowers), customList=(True, active_unfollowers, "all"), style="RANDOM", unfollow_after=None, sleep_delay=600)
-```
-
-
-
-
-### Pick Nonfollowers of a user
-###### Compares the `Followers` data against `Following` data of a user and returns the `Nonfollowers` data
-```python
-scoobyDoo_nonfollowers = session.pick_nonfollowers(username="ScoobyDoo", live_match=True, store_locally=True)
-#now, `scoobyDoo_nonfollowers` variable which is a list- holds the `Nonfollowers` data of "ScoobyDoo" at requested time
-```
-#### Parameters:
-`username`:
-A desired username to pick its nonfollowers
-* It can be your `own` username **OR** a _username of some `non-private` account._
-
-`live_match`:
-Defines the method of grabbing `Followers` and `Following` data to compare with each other to find **nonfollowers**
-> **Knowledge Base**:
-Every time you grab `Followers` and/or `Following` data in `"full"` range of **any** user, it is also gonna be _stored in some corner_ of `InstaPy` **for that session**.
-
-+ `live_match=False`:
- + If the user **already do have** a `Followers` and/or `Following` data loaded _earlier_ in the **same** session, it will run a _smart_ `data-matching` _algorithm_.
- And **there**, it will **load only the new data** _from the server_ and then **return a compact result** of _current data_.
- The _algorithm_ **works like**: _load the usernames **until hits the** ones from the **previous query** at certain amount_.
- + **Also if** the `live_match` is `False` and the user has **no any** _sessional_ `Followers` and/or `Following` data, **then** it will load `live` data at _requested range_.
- + As a **result**, `live_match=False` saves lots of `precious time` and `server requests`.
-+ `live_match=True`:
- + It will **always** load `live` data from the server at _requested range_.
-
-`store_locally`:
-Gives the _option_ to `save` the loaded `Nonfollowers` data in a **local storage**
-The files will be saved _into_ your **logs folder**, `~/InstaPy/logs/YourOwnUsername/relationship_data/ScoobyDoo/nonfollowers/` directory.
-Sample **filename** `01-06-2018~[5886-3575]~2465.json`:
-+ `01-06-2018` means the **time** of the data acquisition.
-+ `5886` means the **count** of the followers retrieved.
-+ `3575` means the **count** of the following retrieved.
-+ `2465` means the **count** of the nonfollowers picked.
-+ `json` is the **filetype** and the data is stored as a `list` in it.
-
-
-There are **several** `use cases` of this tool for **various purposes**.
-+ You can get the nonfollowers of several users and then do analysis.
- + _e.g., in this example Scooby Do used it like this_:
- ```python
- ##Scooby Doo always wonders a lot and this time he wonders if there are people Shaggy is following WHO do not follow him back...
- shaggy_nonfollowers = session.pick_nonfollowers(username="Shaggy", live_match=True, store_locally=True)
-
- #now Scooby Doo will tell his friend Shaggy about this, who knows, maybe Shaggy will unfollow them all or even add to block :D
- ```
-
-
-### Pick Fans of a user
-###### Returns Fans data- all of the accounts who do follow the user WHOM user itself do not follow back
-```python
-smurfette_fans = session.pick_fans(username="Smurfette", live_match=True, store_locally=True)
-#now, `smurfette_fans` variable which is a list- holds the `Fans` data of "Smurfette" at requested time
-```
-#### Parameters:
-`username`:
-A desired username to pick its fans
-* It can be your `own` username **OR** a _username of some `non-private` account._
-
-`live_match`:
-Defines the method of grabbing `Followers` and `Following` data to compare with each other to find **fans**
-> **Knowledge Base**:
-Every time you grab `Followers` and/or `Following` data in `"full"` range of **any** user, it is also gonna be _stored in some corner_ of `InstaPy` **for that session**.
-
-+ `live_match=False`:
- + If the user **already do have** a `Followers` and/or `Following` data loaded _earlier_ in the **same** session, it will run a _smart_ `data-matching` _algorithm_.
- And **there**, it will **load only the new data** _from the server_ and then **return a compact result** of _current data_.
- The _algorithm_ **works like**: _load the usernames **until hits the** ones from the **previous query** at certain amount_.
- + **Also if** the `live_match` is `False` and the user has **no any** _sessional_ `Followers` and/or `Following` data, **then** it will load `live` data at _requested range_.
- + As a **result**, `live_match=False` saves lots of `precious time` and `server requests`.
-+ `live_match=True`:
- + It will **always** load `live` data from the server at _requested range_.
-
-`store_locally`:
-Gives the _option_ to `save` the loaded `Fans` data in a **local storage**
-The files will be saved _into_ your **logs folder**, `~/InstaPy/logs/YourOwnUsername/relationship_data/Smurfette/fans/` directory.
-Sample **filename** `05-06-2018~[4591-2575]~3477.json`:
-+ `05-06-2018` means the **time** of the data acquisition.
-+ `4591` means the **count** of the followers retrieved.
-+ `2575` means the **count** of the following retrieved.
-+ `3477` means the **count** of the fans picked.
-+ `json` is the **filetype** and the data is stored as a `list` in it.
-
-
-There are **several** `use cases` of this tool for **various purposes**.
-+ You can get the fans of several users and then do analysis.
- + _e.g., in this example Smurfette used it like this_:
- ```python
- ##Smurfette is so famous in the place and she wonders which smurfs is following her WHOM she doesn't even know of :D
- smurfette_fans = session.pick_fans(username="Smurfette", live_match=True, store_locally=True)
- #and now, maybe she will follow back some of the smurfs whom she may know :P
- ```
-
-
-### Pick Mutual Following of a user
-###### Returns `Mutual Following` data- all of the accounts who do follow the user WHOM user itself **also** do follow back
-```python
-Winnie_mutualFollowing = session.pick_mutual_following(username="WinnieThePooh", live_match=True, store_locally=True)
-#now, `Winnie_mutualFollowing` variable which is a list- holds the `Mutual Following` data of "WinnieThePooh" at requested time
-```
-#### Parameters:
-`username`:
-A desired username to pick its mutual following
-* It can be your `own` username **OR** a _username of some `non-private` account._
-
-`live_match`:
-Defines the method of grabbing `Followers` and `Following` data to compare with each other to find **mutual following**
-> **Knowledge Base**:
-Every time you grab `Followers` and/or `Following` data in `"full"` range of **any** user, it is also gonna be _stored in some corner_ of `InstaPy` **for that session**.
-
-+ `live_match=False`:
- + If the user **already do have** a `Followers` and/or `Following` data loaded _earlier_ in the **same** session, it will run a _smart_ `data-matching` _algorithm_.
- And **there**, it will **load only the new data** _from the server_ and then **return a compact result** of _current data_.
- The _algorithm_ **works like**: _load the usernames **until hits the** ones from the **previous query** at certain amount_.
- + **Also if** the `live_match` is `False` and the user has **no any** _sessional_ `Followers` and/or `Following` data, **then** it will load `live` data at _requested range_.
- + As a **result**, `live_match=False` saves lots of `precious time` and `server requests`.
-+ `live_match=True`:
- + It will **always** load `live` data from the server at _requested range_.
-
-`store_locally`:
-Gives the _option_ to `save` the loaded `Mutual Following` data in a **local storage**
-The files will be saved _into_ your **logs folder**, `~/InstaPy/logs/YourOwnUsername/relationship_data/WinnieThePooh/mutual_following/` directory.
-Sample **filename** `11-06-2018~[3872-2571]~1120.json`:
-+ `11-06-2018` means the **time** of the data acquisition.
-+ `3872` means the **count** of the followers retrieved.
-+ `2571` means the **count** of the following retrieved.
-+ `1120` means the **count** of the mutual following picked.
-+ `json` is the **filetype** and the data is stored as a `list` in it.
-
-
-There are **several** `use cases` of this tool for **various purposes**.
-+ You can get the mutual following of several users and then do analysis.
- + _e.g., in this example Winnie The Pooh used it like this_:
- ```python
- #Winnie The Pooh is a very friendly guy and almost everybody follows him back, but he wants to be sure about it :D
- Winnie_mutual_following = session.pick_mutual_following(username="WinnieThePooh", live_match=True, store_locally=True)
- ##now, he will write a message to his mutual followers to help him get a new honey pot :>
- ```
-
-
-
diff --git a/docs/settings.md b/docs/settings.md
deleted file mode 100644
index 80fce9ab7..000000000
--- a/docs/settings.md
+++ /dev/null
@@ -1,658 +0,0 @@
----
-title: Settings
----
-
-### Liking
-This method is only needed for the `interact_by_...` actions.
-Posts will be liked by default when using `like_by_...` actions.
-
-```python
-# ~70% of the by InstaPy viewed posts will be liked
-
-session.set_do_like(enabled=True, percentage=70)
-```
-
-
-### Commenting
-
-```python
-# enable comments (by default enabled=False) and set commenting probability to 25% so ~ every 4th image will be commented on
-
-session.set_do_comment(enabled=True, percentage=25)
-```
-``` python
-# Configure a simple list of optional comments, one will be selected at random when commenting:
-session.set_comments(['Awesome', 'Really Cool', 'I like your stuff'])
-```
-
-Or configure conditional comments to provide a more contextual commenting based on the caption of the image:
-Conditional comments are created as a list of dictionaries, each one contains a definition of
-[mandatory words](#mandatory-words) and a list of comments.
-The list of conditional comments is scanned until the first item that satisfies the mandatory words condition is found
-and then one of the comments associated with that item is selected at random to be used.
-This can best be understood with an example:
-``` python
-comments=[
- # either "icecave" OR "ice_cave" will satisfy this:
- {'mandatory_words': ["icecave", "ice_cave"], 'comments': ["Nice shot. Ice caves are amazing", "Cool. Aren't ice caves just amazing?"]},
-
- # either "high_mountain" OR ("high" AND "mountain") will satisfy this:
- {'mandatory_words': ["high_mountain", ["high", "mountain"]], 'comments': ["I just love high mountains"]},
-
- # Only ("high" AND "tide" together) will satisfy this:
- {'mandatory_words': [["high", "tide"]], 'comments': ["High tides are better than low"]}
-
- # Only "summer" AND ("lake" OR "occean") will satisfy this:
- {'mandatory_words': [["summer", ["lake", "occean"]]], 'comments': ["Summer fun"]}
-
-]
-session.set_comments(comments)
-```
-
-You can also set comments for specific media types (Photo / Video)
-``` python
-session.set_comments(['Nice shot!'], media='Photo')
-session.set_comments(['Great Video!'], media='Video')
-
-# and you can add the username of the poster to the comment by using
-
-session.set_comments(['Nice shot! @{}'], media='Photo')
-```
-
-
-### Emoji Support
-To use an emoji just add an `u` in front of the opening apostrophe:
-
-```python
-session.set_comments([u'This post is 🔥',u'More emojis are always better 💯',u'I love your posts 😍😍😍']);
-# or
-session.set_comments([u'Emoji text codes are also supported :100: :thumbsup: :thumbs_up: \u2764 💯💯']);
-```
-
-Emoji text codes are implemented using 2 different naming codes. A complete list of emojis codes can be found on the [Python Emoji Github](https://github.com/carpedm20/emoji/blob/master/emoji/unicode_codes.py), but you can use the alternate shorted naming scheme found for Emoji text codes [here](https://www.webpagefx.com/tools/emoji-cheat-sheet). Note: Every Emoji has not been tested. Please report any inconsistencies.
-
-
-### Following
-
-```python
-# default enabled=False, follows ~ 10% of the users from the images, times=1
-# (only follows a user once (if unfollowed again))
-
-session.set_do_follow(enabled=True, percentage=10, times=2)
-```
-
-
-### Smart Hashtags
-
-```python
-# Generate smart hashtags based on https://displaypurposes.com ranking,
-# banned and spammy tags are filtered out.
-# (limit) defines amount limit of generated hashtags by hashtag
-# (sort) sort generated hashtag list 'top' and 'random' are available
-# (log_tags) shows generated hashtags before use it
-# (use_smart_hashtags) activates like_by_tag to use smart hashtags
-
-session.set_smart_hashtags(['cycling', 'roadbike'], limit=3, sort='top', log_tags=True)
-session.like_by_tags(amount=10, use_smart_hashtags=True)
-```
-
-
-### Smart Location Hashtags
- Generate smart hashtags based on https://displaypurposes.com/map ranking.
- Banned and spammy tags are filtered out.
-
- ```python
- Use_smart_location_hashtags activates like_by_tag to use smart hashtags
-
- session.set_smart_location_hashtags(['204517928/chicago-illinois', '213570652/nagoya-shi-aichi-japan'], radius=20, limit=10)
- session.like_by_tags(amount=10, use_smart_location_hashtags=True)
- ```
-
- #### Parameters
- `radius`: Radius around the location in Miles
- `limit`: Defines amount limit of generated hashtags by hashtag
- `log_tags`: Shows generated hashtags before use it (default is True)
-
-
-
-
-### Quota Supervisor
-###### Take full control of the actions with the most sophisticated approaches
-
-```python
-session.set_quota_supervisor(enabled=True,
- sleep_after=["likes", "comments_d", "follows", "unfollows", "server_calls_h"],
- sleepyhead=True,
- stochastic_flow=True,
- notify_me=True,
- peak_likes_hourly=57,
- peak_likes_daily=585,
- peak_comments_hourly=21,
- peak_comments_daily=182,
- peak_follows_hourly=48,
- peak_follows_daily=None,
- peak_unfollows_hourly=35,
- peak_unfollows_daily=402,
- peak_server_calls_hourly=None,
- peak_server_calls_daily=4700)
-```
-#### Parameters:
-`enabled`: put `True` to **activate** or `False` to **deactivate** supervising any time
-
-
-If you **don't want to** _supervise_ likes **at all**, simply **remove** `peak_likes` parameter **OR** use `peak_likes=(None, None)`.
-_Once_ likes **reach** peak, it will **jump** every other like, _yet_, **will do all available actions** (_e.g. follow or unfollow_).
-+ Only `server calls` **does not** jump, it exits the program **once reaches the peak**.
-> Although, you can put server calls to sleep once reaches peak, read `sleep_after` parameter.
-+ _Every action_ will be **jumped** separately after reaching it's peak, _except_ comments. Cos commenting without a like isn't welcomed that's why as like peak is reached, it will jump comments, too.
-
-`sleep_after`: is used to put **InstaPy** to _sleep_ **after reaching peak** _rather than_ **jumping the action** (_or exiting- **for** server calls_)
-_Any action_ can be included `["likes", "comments", "follows", "unfollows", "server_calls"]`.
-_As if_ you want to put _sleep_ **only after** reaching **hourly** like peak, put `"likes_h"` **OR** put `"likes_d"` for _sleeping_ **only after** reaching **daily** like peak.
-_such as_,
-+ `sleep_after=['follows_h']` will _sleep_ after reaching **hourly** follow peak
-+ `sleep_after=['likes_d', 'follows', 'server_calls_h']` will _sleep_ after reaching **daily** like peak, follow peaks (_**hourly** and **daily**_) and **hourly** server call peak.
-
-**Notice**: there can be _either_ `"likes"` (_for both **hourly** and **daily** sleep_) **OR** `"likes_h"` (_for **hourly** sleep only_) **OR** `"likes_d"` (_for **daily** sleep only_).
->_Once_ gone to sleep, it will **wake up** as _new_ **hour**/**day** (_according to the interval_) arrives AND **continue** the activity.
-
-
-`sleepyhead`: can help to _sound_ **more humanly** which will **wake up a little bit later** in a randomly chosen time interval around accurate wake up time.
->_e.g._, if remaining time is `17` minutes, it will sleep `20` minutes instead (_random values each time_)..
-
-
-`stochastic_flow`: can provide _smooth_ peak value generation by your original values.
-+ Every ~**hour**/**day** it will generate peaks **at close range** _around_ your **original peaks** (_but below them_).
-> _e.g._, your peak likes **hourly** is `45`, next hour that peak will be `39`, the next `43`, etc.
-
-
-`notify_me`: sends **toast notifications** (_directly to your OS_) _about_ the **important states of** _supervisor_- **sleep**, **wake up** and **exit** messages.
-
-#### Mini-Examples:
-+ Claudio has written **a new 😊 quickstart** script where it **mostly** _put likes and comments_. He wants the program to **comment safely** cos he is _afraid of exceeding_ **hourly** & **daily** comment limits,
-```python
-session.set_quota_supervisor(enabled=True, peak_comments_daily=21, peak_comments_hourly=240)
-```
->_That's it! When it reaches the comments peak, it will just jump all of the comments and will again continue to put comments when is available [in the next hour/day]_.
-
-+ Alicia has a **24**/**7** 🕦 working **quickstart** script and **would like to** keep _server calls_ in control to AVOID **excessive amount of requests** to the _server_ in **hourly** basis, also,
- + **wants** the program to **sleep after** reaching **hourly** _server calls_ peak: **adds** `"server_calls_h"` into `sleep_after` parameter
- + **wants** the program to **wake up** _a little bit later_ than real sleep time [once reaches the peaks]: **uses** `sleepyhead=True` parameter
-```python
-session.set_quota_supervisor(enabled=True, peak_server_calls_daily=490, sleep_after=["server_calls_h"], sleepyhead=True)
-```
->_It will sleep after **hourly** server calls reaches its peak given - `490` and **never allow** one more extra request to the server out of the peak and **wake up** when **new hour** comes in WHILST **daily** server calls **will not be** supervised at all- as Alicia wishes_.
-
-+ Sam has a _casual_ 🦆 **quickstart** script full of _follow_/_unfollow_ features and he wants to **do it safely**, also,
- + is **gonna** run on local computer and **wants** to receive **toast notifications** 😋 on _supervising states_: **uses** `notify_me` parameter
- + **wants** QS to _randomize_ his `pre-defined` peak values [at close range] each new _hour_/_day_: **uses** `stochastic_flow=True` parameter
- + **wants** the program to sleep after reaching **hourly** _follow_ peak and **daily** _unfollow_ peak: **adds** `"follows_h"` and `"unfollows_d"`into `sleep_after` parameter
-```python
-session.set_quota_supervisor(enabled=True, peak_follows_daily=560, peak_follows_hourly=56, peak_unfollows_hourly=49, peak_unfollows_daily=550, sleep_after=["follows_h", "unfollows_d"], stochastic_flow=True, notify_me=True)
-```
-
----
->**Big Hint**: _Find your NEED_ 🤔 _and supervise it!_
-+ _EITHER_ **fully** configure QS to supervise **all** of the _actions_ all time
-+ _OR_ **just** supervise the desired _action_(_s_) in desired _interval_(_s_) [**hourly** and/or **daily**] per your need
-
-
-### Restricting Likes
-
-```python
-session.set_dont_like(['#exactmatch', '[startswith', ']endswith', 'broadmatch'])
-```
-
-`.set_dont_like` searches the description and owner comments for hashtags and
-won't like the image if one of those hashtags are in there
-
-You have 4 options to exclude posts from your InstaPy session:
-* words starting with `#` will match only exact hashtags (e. g. `#cat` matches `#cat`, but not `#catpic`)
-* words starting with `[` will match all hashtags starting with your word (e. g. `[cat` matches `#catpic`, `#caturday` and so on)
-* words starting with `]` will match all hashtags ending with your word (e. g. `]cat` matches `#mycat`, `#instacat` and so on)
-* words without these prefixes will match all hashtags that contain your word regardless if it is placed at the beginning, middle or end of the hashtag (e. g. `cat` will match `#cat`, `#mycat`, `#caturday`, `#rainingcatsanddogs` and so on)
-
-
-### Ignoring Restrictions
-
-```python
-# will ignore the don't like if the description contains
-# one of the given words
-
-session.set_ignore_if_contains(['glutenfree', 'french', 'tasty'])
-```
-
-
-### Ignoring Users
-
-```python
-# completely ignore liking images from certain users
-
-session.set_ignore_users(['random_user', 'another_username'])
-```
-
-
-### Excluding friends
-
-```python
-# will prevent commenting on and unfollowing your good friends (the images will
-# still be liked)
-
-session.set_dont_include(['friend1', 'friend2', 'friend3'])
-```
-
-
-### Mandatory Words
-
-```python
-session.set_mandatory_words(['#food', '#instafood'])
-```
-
-`.set_mandatory_words` searches the description, location and owner comments for words and
-will like the image if the mandatory words condition is met.
-The mandatory words list can be a simple list of words or a nested structure of lists within lists.
-* When using a simple word list the condition between the words is "OR" so if any of the words from the list exists in
-the image text it will be matched.
-* When using a nested list of lists the top level list condition is "OR" and the condition alternates between "AND"
-and "OR" with every nesting level.
-
-For example:
-~~~
- # either "icecave" or "ice_cave" will satisfy this:
- ["icecave", "ice_cave"]
-
- # either "high_mountain" OR ("high" AND "mountain") will satisfy this:
- ["high_mountain", ["high", "mountain"]]
-
- # Only ("high" AND "tide" together) will satisfy this:
- [["high", "tide"]]
-
- # Only "summer" AND ("lake" OR "occean") will satisfy this:
- [["summer", ["lake", "occean"]]
-~~~
-
-### Mandatory Language
-
-```python
-session.set_mandatory_language(enabled=True, character_set=['LATIN'])
-session.set_mandatory_language(enabled=True, character_set=['LATIN', 'CYRILLIC'])
-```
-
-`.set_mandatory_language` restrict the interactions, liking and following if any character of the description is outside of the character sets you selected (the location is not included and non-alphabetic characters are ignored). For example if you choose `LATIN`, any character in Cyrillic will flag the post as inappropriate. If you choose 'LATIN' and 'CYRILLIC', any other character sets will flag the post as inappropriate as well.
-
-* Available character sets: `LATIN`, `GREEK`, `CYRILLIC`, `ARABIC`, `HEBREW`, `CJK`, `HANGUL`, `HIRAGANA`, `KATAKANA` and `THAI`
-
-
-### Don't unfollow active users
-
-```python
-# Prevents unfollow followers who have liked one of your latest 5 posts
-
-session.set_dont_unfollow_active_users(enabled=True, posts=5)
-```
-
-
-### Blacklist Campaign
-```python
-# Controls your interactions by campaigns.
-# ex. this week InstaPy will like and comment interacting by campaign called
-# 'soccer', next time InstaPy runs, it will not interact again with users in
-# blacklist
-# In general, this means that once we turn off the soccer_campaign again, InstaPy
-# will have no track of the people it interacted with about soccer.
-# This will help you target people only once but several times for different campaigns
-
-session.set_blacklist(enabled=True, campaign='soccer_campaign')
-session.set_do_comment(True, percentage=50)
-session.set_comments(['Neymar is better than CR7', 'Soccer is cool'])
-session.like_by_tags(['soccer', 'cr7', 'neymar'], amount=100, media='Photo')
-
-```
-
-
-
-
-### Simulation
-##### During indirect data retrieval, **simulation** happens to provide a _genuine_ activity flow triggered by a wise algorithm.
-To **turn off** simulation or to **decrease** its occurrence frequency, use `set_simulation` setting:
-```python
-#use the value of `False` to permanently turn it off
-session.set_simulation(enabled=False)
-
-#use a desired occurrence percentage
-session.set_simulation(enabled=True, percentage=66)
-```
-
-
-### Skipping user for private account, public account, no profile picture, business account, bio keywords
-
-#### This is used to skip users with certain condition
-```python
-session.set_skip_users(skip_private=True,
- private_percentage=100,
- skip_no_profile_pic=False,
- no_profile_pic_percentage=100,
- skip_business=False,
- skip_non_business=False,
- business_percentage=100,
- skip_business_categories=[],
- dont_skip_business_categories=[],
- skip_bio_keyword=[],
- mandatory_bio_keywords=[],
- skip_public=False,
- public_percentage=0)
-```
-##### Skip private account
-**This is done by default**
-```python
-session.set_skip_users(skip_private=True,
- private_percentage=100)
-```
-Will skip users that have private account, even if are followed by running account.
-You can set a percentage of skipping:
- _private_percentage_= 100 always skip private users
- _private_percentage_= 0 never skip private users (so set skip_private=False)
-
-##### Skip public account
-```python
-session.set_skip_users(skip_private=False,
- skip_public=True,
- public_percentage=100)
-```
-Will skip users that have public account.
-You can set a percentage of skipping:
- _private_percentage_= 100 always skip public users
- _private_percentage_= 0 never skip public users (so set skip_public=False)
-
-##### Skip users that don't have profile picture
-
-```python
-session.set_skip_users(skip_private=True,
- skip_no_profile_pic=True,
- no_profile_pic_percentage=100)
-```
-Will skip users that haven't uploaded yet a profile picture
-You can set a percentage of skipping:
- _no_profile_pic_percentage_= 100 always skip users without profile picture
- _no_profile_pic_percentage_= 0 never skip users without profile picture (so set _skip_no_profile_pic_=False)
-
-##### Skip users that have business account
-
-```python
-session.set_skip_users(skip_private=True,
- skip_no_profile_pic=True,
- skip_business=True,
- business_percentage=100)
-```
-This will skip all users that have business account activated.
-You can set a percentage of skipping:
- _business_percentage_= 100 always skip business users
- _business_percentage_= 0 never skip business users (so set _skip_business_=False)
-
-**N.B.:** This _business_percentage_ parameter works only if no _skip_business_categories_ or _dont_skip_business_categories_ are provided!
-
-###### Skip only users that have certain business account
-```python
-session.set_skip_users(skip_private=True,
- skip_no_profile_pic=True,
- skip_business=True,
- skip_business_categories=['Creators & Celebrities'])
-```
-This will skip all business accounts that have category in given list
-**N.B.** In _skip_business_categories_ you can add more than one category
-
-###### Skip all business accounts, except from list given
-```python
-session.set_skip_users(skip_private=True,
- skip_no_profile_pic=True,
- skip_business=True,
- dont_skip_business_categories=['Creators & Celebrities'])
-```
-This will skip all business accounts except the ones that have a category that matches one item in the list of _dont_skip_business_categories_
-**N.B.** If both _dont_skip_business_categories_ and _skip_business_categories_, InstaPy will skip only business accounts in the list given from _skip_business_categories_.
-
-> [A list of all available business categories can be found here](https://github.com/InstaPy/instapy-docs/blob/master/BUSINESS_CATEGORIES.md)
-
-###### Skip all non business and bussines accounts, except from list given
- ```python
- session.set_skip_users(skip_private=True,
- skip_no_profile_pic=True,
- skip_business=True,
- skip_non_business=True,
- dont_skip_business_categories=['Creators & Celebrities'])
- ```
- This will skip all non business and business accounts except categories in _dont_skip_business_categories_.
-
-###### Skip based on bio keywords
-```python
-session.set_skip_users(skip_bio_keyword=["lifestyle"],
- mandatory_bio_keywords=["art", "photography"])
-```
-This will skip users that have "lifestyle" and users that don't have "art" or "photography" in their bio or username.
-See the [Mandatory Words](#mandatory-words) section for details on how to define complex mandatory words conditions.
-
-
-
-
-### Liking based on the number of existing likes a post has
-##### This is used to check the number of existing likes a post has and if it _either_ **exceed** the _maximum_ value set OR **does not pass** the _minimum_ value set then it will not like that post
-```python
-session.set_delimit_liking(enabled=True, max_likes=1005, min_likes=20)
-```
-Use `enabled=True` to **activate** and `enabled=False` to **deactivate** it, _any time_
-`max` is the maximum number of likes to compare
-`min` is the minimum number of likes to compare
-> You can use **both** _max_ & _min_ values OR **one of them** _as you desire_, just **put** the value of `None` _to the one_ you **don't want to** check for., _e.g._,
-```python
-session.set_delimit_liking(enabled=True, max_likes=242, min_likes=None)
-```
-_at this configuration above, it **will not** check number of the existing likes against **minimum** value_
-
-* **_Example_**:
-```python
-session.set_delimit_liking(enabled=True, max_likes=500, min_likes=7)
-```
-_**Now**, if a post has more existing likes than maximum value of `500`, then it will not like that post,
-**similarly**, if that post has less existing likes than the minimum value of `7`, then it will not like that post..._
-
-
-### Commenting based on the number of existing comments a post has
-##### This is used to check the number of existing comments a post has and if it _either_ **exceed** the _maximum_ value set OR **does not pass** the _minimum_ value set then it will not comment on that post
-```python
-session.set_delimit_commenting(enabled=True, max_comments=32, min_comments=0)
-```
-Use `enabled=True` to **activate** and `enabled=False` to **deactivate** it, _any time_
-`max` is the maximum number of comments to compare
-`min` is the minimum number of comments to compare
-> You can use **both** _max_ & _min_ values OR **one of them** _as you desire_, just **leave** it out or **put** it to `None` _to the one_ you **don't want to** check for., _e.g._,
-```python
-session.set_delimit_commenting(enabled=True, min_comments=4)
-# or
-session.set_delimit_commenting(enabled=True, max_comments=None, min_comments=4)
-```
-_at this configuration above, it **will not** check number of the existing comments against **maximum** value_
-
-* **_Example_**:
-```python
-session.set_delimit_commenting(enabled=True, max_comments=70, min_comments=5)
-```
-_**Now**, if a post has more comments than the maximum value of `70`, then it will not comment on that post,
-**similarly**, if that post has less comments than the minimum value of `5`, then it will not comment on that post..._
-
-
-### Commenting based on mandatory words in the description or first comment
-
-##### This is used to check the description of the post and the first comment of the post (some users only put tags in the comments instead of the post description) for the occurrence of mandatory words before commenting. If none of the mandatory words is present, the post will not be commented.
-
-This feature is helpful when you want to comment only on specific tags.
-
-```python
-session.set_delimit_commenting(enabled=True, comments_mandatory_words=['cat', 'dog'])
-```
-> This will only comment on posts that contain **either** cat or dog in the post description or first comment.
-> You can also require sets of words. See the [Commenting](#commenting) section for detains on how to do that
-
-
-### Interactions based on the number of followers and/or following a user has
-##### This is used to check the number of _followers_ and/or _following_ a user has and if these numbers _either_ **exceed** the number set OR **does not pass** the number set OR if **their ratio does not reach** desired potency ratio then no further interaction happens
-```python
-session.set_relationship_bounds(enabled=True,
- potency_ratio=1.34,
- delimit_by_numbers=True,
- max_followers=8500,
- max_following=4490,
- min_followers=100,
- min_following=56,
- min_posts=10,
- max_posts=1000)
-```
-Use `enabled=True` to **activate** this feature, and `enabled=False` to **deactivate** it, _any time_
-`delimit_by_numbers` is used to **activate** & **deactivate** the usage of max & min values
-`potency_ratio` accepts values in **2 format**s _according to your_ **style**: _positive_ & _negative_
-* `potency_ratio` with **POSITIVE** values can be used to _route_ interactions to _only_ **potential** (_real_) **users** _WHOSE_ **followers count** is higher than **following count** (**e.g.**, `potency_ratio = 1.39`)
-_**find** desired_ `potency_ratio` _with this formula_: `potency_ratio` == **followers count** / **following count** (_use desired counts_)
->_**e.g.**_, target user has _`5000` followers_ & _`4000` following_ and you set `potency_ratio=1.35`.
-**Now** it _will **not** interact_ with this user, **cos** the user's **relationship ratio** is `5000/4000==1.25` and `1.25` is **below** _desired_ `potency_ratio` _of `1.35`_
-
-* `potency_ratio` with **NEGATIVE** values can be used to _route_ interactions to _only_ **massive followers** _WHOSE_ **following count** is higher than **followers count** (**e.g.**, `potency_ratio = -1.42`)
-_**find** desired_ `potency_ratio` _with this formula_: `potency_ratio` == **following count** / **followers count** (_use desired counts_)
->_**e.g.**_, target user has _`2000` followers_ & _`3000` following_ and you set `potency_ratio = -1.7`.
-**Now** it _will **not** interact_ with this user, **cos** the user's **relationship ratio** is `3000/2000==1.5` and `1.5` is **below** _desired_ `potency_ratio` _of `1.7`_ (_**note that**, negative `-` sign is only used to determine your style, nothing more_)
-
-###### There are **3** **COMBINATIONS** _available_ to use:
-* **1**. You can use `potency_ratio` **or not** (**e.g.**, `potency_ratio=None`, `delimit_by_numbers=True`) - _will decide only by your **pre-defined** max & min values regardless of the_ `potency_ratio`
-```python
-session.set_relationship_bounds(enabled=True, potency_ratio=None, delimit_by_numbers=True, max_followers=22668, max_following=10200, min_followers=400, min_following=240)
-```
-* **2**. You can use **only** `potency_ratio` (**e.g.**, `potency_ratio=-1.5`, `delimit_by_numbers=False`) - _will decide per_ `potency_ratio` _regardless of the **pre-defined** max & min values_
-```python
-session.set_relationship_bounds(enabled=True, potency_ratio=-1.5, delimit_by_numbers=False, max_followers=400701, max_following=90004, min_followers=963, min_following=2310)
-```
-> apparently, _once_ `delimit_by_numbers` gets `False` value, max & min values _do not matter_
-* **3**. You can use both `potency_ratio` and **pre-defined** max & min values **together** (**e.g.**, `potency_ratio=2.35`, `delimit_by_numbers=True`) - _will decide per_ `potency_ratio` _& your **pre-defined** max & min values_
-```python
-session.set_relationship_bounds(enabled=True, potency_ratio=2.35, delimit_by_numbers=True, max_followers=10005, max_following=24200, min_followers=77, min_following=500)
-```
-
-> **All** of the **4** max & min values are _able to **freely** operate_, **e.g.**, you may want to _**only** delimit_ `max_followers` and `min_following` (**e.g.**, `max_followers=52639`, `max_following=None`, `min_followers=None`, `min_following=2240`)
-```python
-session.set_relationship_bounds(enabled=True, potency_ratio=-1.44, delimit_by_numbers=True, max_followers=52639, max_following=None, min_followers=None, min_following=2240)
-```
-
-
-### Interactions based on the number of posts a user has
-#### This is used to check number of posts of a user and skip if they aren't in the boundaries provided
-```python
-session.set_relationship_bounds(min_posts=10,
- max_posts=1000)
-```
-Users that have more than 1000 posts or less than 10 will be discarded
-
-**N.B.:** It is up to the user to check that `min_posts < max_posts`
-
-You can also set only one parameter at a time:
-```python
-session.set_relationship_bounds(max_posts=1000)
-```
-
-Will skip only users that have more than 1000 posts in their feed
-
-
-### Custom action delays
-###### _After doing each action- like, comment, follow, unfollow or story, there is a sleep delay to provide smooth activity flow_.
-##### But you can set a _custom_ sleep delay for each action yourself by using the `set_action_delays` setting!
-```python
-session.set_action_delays(enabled=True,
- like=3,
- comment=5,
- follow=4.17,
- unfollow=28,
- story=10)
-```
-_Now it will sleep `3` seconds **after putting every single like**, `5` seconds for every single comment and similarly for the others.._
-
-
-You can also customize the sleep delay of _e.g._ **only the likes**:
-```python
-session.set_action_delays(enabled=True, like=3)
-```
-
-##### Wanna go smarter? - use `random_range_from` and `random_range_to`
-By just enabling `randomize` parameter, you can **enjoy** having random sleep delays at desired range, e.g.,
-```python
-session.set_action_delays(enabled=True, like=5.2, randomize=True, random_range_from=70, random_range_to=140)
-```
-_There, it will have a **random sleep delay between** `3.64` (_`70`% of `5.2`_) and `7.28`(_`140`% of `5.2`_) seconds _each time_ **after putting a like**._
-+ You can also put **only the max range** as- `random_range_from=None, random_range_to=200`
-Then, the _min range will automatically be_ `100`%- the same time delay itself.
-And the random sleep delays will be between `5.2` and `10.4` seconds.
-+ If you put **only the min range** as- `random_range_from=70, random_range_to=None`
-Then, the _max range will automatically be_ `100`%- the same time delay itself.
-And the random sleep delays will be between `3.64` and `5.2` seconds.
-+ But if you **put `None` to both** min & max ranges as- `random_range_from=None, random_range_to=None`
-Then no randomization will occur and the sleep delay will always be `5.2` seconds.
-+ Heh! You **mistakenly put** min range instead of max range as- `random_range_from=100, random_range_to=70`?
-No worries. It will automatically take the smaller number as min and the bigger one as max.
-+ Make sure to use the values **bigger than `0`** for the `random_rage` percentages.
-E.g. `random_range_from=-10, random_range_to=140` is an invalid range and no randomization will happen.
-+ You can provide **floating point numbers** as percentages, too!
-`random_range_from=70.7, random_range_to=200.45` will work greatly.
-
-###### Note: There is a _minimum_ **default** delay for each action and if you enter a smaller time of delay than the default value, then it will **pick the default value**. You can turn that behaviour off with `safety_match` parameter.
-```python
-session.set_action_delays(enabled=True, like=0.15, safety_match=False)
-```
-_It has been held due to safety considerations. Cos sleeping a respective time after doing actions- for example ~`10` seconds after an unfollow, is very important to avoid possible temporary blocks and if you might enter e.g. `3` seconds for that without realizing the outcome..._
-
-
-### Target Lists
-#### This is used to parse text files containing target lists of users, hashtags, comments etc
-For example:
-```python
-# Like posts based on hashtags
-hashtags = session.target_list("C:\\Users\\......\\hashtags.txt")
-session.like_by_tags(hashtags, amount=10)
-
-# Follow the followers of each given user
-users = session.target_list("C:\\Users\\......\\users.txt")
-session.follow_user_followers(users, amount=10, randomize=False)
-```
-Note that your text file should look like this:
-```
-hashtag1
-hashtag2
-hashtag3
-```
-or
-```
-user1
-user2
-user3
-```
-Functions you can use ```target_list``` with:
-
-```story_by_user```, ```story_by_tag```, ```like_by_tags```, ```follow_by_tags```, ```follow_user_followers```, ```follow_user_following```, ```follow_likers```, ```follow_commenters```, ```follow_by_list```, ```set_skip_users```, ```set_ignore_users```, ```set_dont_include```, ```interact_by_users```, ```interact_by_users_tagged_posts```, ```interact_user_followers```, ```interact_user_following```, ```interact_by_comments```, ```set_comments```, ```set_comment_replies```, ```set_mandatory_words```, ```unfollow_users```
diff --git a/docs/third-party-features.md b/docs/third-party-features.md
deleted file mode 100644
index d8b80fe33..000000000
--- a/docs/third-party-features.md
+++ /dev/null
@@ -1,480 +0,0 @@
----
-title: Third Party Features
----
-
-### Clarifai ImageAPI
-
-
-
-###### Note: Head over to [https://developer.clarifai.com/signup/](https://developer.clarifai.com/signup/) and create a free account, once you're logged in go to [https://developer.clarifai.com/account/applications/](https://developer.clarifai.com/account/applications/) and create a new application. You can find the client ID and Secret there. You get 5000 API-calls free/month.
-
-If you want the script to get your CLARIFAI_API_KEY for your environment, you can do:
-
-```
-export CLARIFAI_API_KEY=""
-```
-#### Example with Imagecontent handling
-
-```python
-session.set_do_comment(True, percentage=10)
-session.set_comments(['Cool!', 'Awesome!', 'Nice!'])
-session.set_use_clarifai(enabled=True)
-session.clarifai_check_img_for(['nsfw'])
-session.clarifai_check_img_for(['food', 'lunch', 'dinner'], comment=True, comments=['Tasty!', 'Nice!', 'Yum!'])
-
-session.end()
-```
-#### Enabling Imagechecking
-
-```python
-# default enabled=False , enables the checking with the Clarifai API (image
-# tagging) if secret and proj_id are not set, it will get the environment
-# variables 'CLARIFAI_API_KEY'.
-
-session.set_use_clarifai(enabled=True, api_key='xxx')
-```
-
-#### Using Clarifai Public Models and Custom Models
-If not specified by setting the `models=['model_name1']` in `session.set_use_clarifai`, `models` will be set to `general` by default.
-
-If you wish to check against a specific model or multiple models (see Support for Compound Model Queries below), you can specify the models to be checked as shown below.
-
-To get a better understanding of the models and their associated concepts, see the Clarifai [Model Gallery](https://clarifai.com/models) and [Developer Guide](https://clarifai.com/developer/guide/)
-
-**NOTE ON MODEL SUPPORT**: At this time, the support for the`Focus`, `Face Detection`, `Face Embedding`, and `General Embedding` has not been added.
-
-```python
-# Check image using the NSFW model
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['nsfw'])
-
-# Check image using the Apparel model
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['apparel'])
-
-# Check image using the Celebrity model
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['celebrity'])
-
-# Check image using the Color model
-session.set_use_clarifai(enabled=True, api_key=‘xxx’, models=[‘model’])
-
-# Check image using the Demographics model
-session.set_use_clarifai(enabled=True, api_key=‘xxx’, models=[‘demographics’])
-
-# Check image using the Food model
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['food'])
-
-# Check image using the Landscape Quality model
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['landscape quality'])
-
-# Check image using the Logo model
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['logo'])
-
-# Check image using the Moderation model
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['moderation'])
-
-# Check image using the Portrait Quality model
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['portrait quality'])
-
-# Check image using the Textures and Patterns model
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['textures'])
-
-# Check image using the Travel model
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['travel'])
-
-# Check image using the Weddings model
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['weddings'])
-
-# Check image using a custom model where model_name is name of your choosing (see Clarifai documentation for using custom models)
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['your-model-name'])
-```
-
-#### Filtering Inappropriate Images
-
-```python
-# uses the clarifai api to check if the image contains nsfw content
-# by checking against Clarifai's NSFW model
-# -> won't comment if image is nsfw
-
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['nsfw'])
-session.clarifai_check_img_for(['nsfw'])
-```
-
-```python
-# uses the clarifai api to check if the image contains inappropriate content
-# by checking against Clarifai's Moderation model
-# -> won't comment if image is suggestive or explicit
-
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['moderation'])
-session.clarifai_check_img_for(['suggestive', 'explicit'])
-
-# To adjust the threshold for accepted concept predictions and their
-# respective score (degree of confidence) you can set the default probability
-# parameter for Clarifai (default 50%). For example, you could set probability to 15%.
-# -> any image with a nsfw score of 0.15 of higher will not be commented on
-
-session.set_use_clarifai(enabled=True, api_key='xxx', probability= 0.15, models=['nsfw'])
-session.clarifai_check_img_for(['nsfw'])
-```
-
-#### Filtering by Keyword
-
-```python
-# uses the clarifai api to check if the image concepts contain the keyword(s)
-# -> won't comment if image contains the keyword
-
-session.clarifai_check_img_for(['building'])
-```
-#### Specialized Comments for Images with Specific Content
-
-```python
-# checks the image for keywords food and lunch. To check for both, set full_match in
-# in session.set_use_clarifia to True, and if both keywords are found,
-# InstaPy will comment with the given comments. If full_match is False (default), it only
-# requires a single tag to match Clarifai results.
-
-session.set_use_clarifai(enabled=True, api_key='xxx', full_match=True)
-session.clarifai_check_img_for(['food', 'lunch'], comment=True, comments=['Tasty!', 'Yum!'])
-
-# If you only want to accept results with a high degree of confidence, you could
-# set a probability to a higher value, like 90%.
-
-session.set_use_clarifai(enabled=True, api_key='xxx', probability=0.90, full_match=True)
-session.clarifai_check_img_for(['food', 'lunch'], comment=True, comments=['Tasty!', 'Yum!'])
-```
-
-
-
-
-#### Querying Multiple Models with Workflow (Single API Call)
-You can query multiple Clarifai models with a single API call by setting up a custom workflow. Using a `workflow` is the recommended way to query multiple models. Alternatively, it is possible to query multiple models separately (see Querying Multiple Models (Multiple API Calls) below).
-
-To setup a workflow, see the [Workflow Documentation](https://www.clarifai.com/developer/guide/workflow#workflow).
-
-**NOTE** :As mentioned above, the `Focus`, `Face Detection`, `Face Embedding`, and `General Embedding` models are not current supported.
-
-Once you have a workflow setup, you can use InstaPy to check images with the Clarifai Image API by setting the `workflow` parameter in `session.set_use_clarifai` to the name of your custom workflow.
-
-Let's say you want to comment 'Great shot!' on images of men or women with the hashtag `#selfie`, but you want to make sure not to comment on images which might contain inappropriate content. To get general concepts, e.g. `woman`, you would setup your workflow using `General` and to check the image for the concepts `nsfw` and `explicit` you would also want to add NSFW and Moderation models to your workflow.
-
-For example:
-```python
-session.set_use_clarifai(enabled=True, api_key='xxx', workflow=['your-workflow'], proxy='123.123.123.123:5555')
-session.clarifai_check_img_for(['woman', 'man'], ['nsfw', 'explicit', 'suggestive'], comment=True, comments=['Great shot!'])
-```
-If Clarifai's response includes the concepts of either `woman` or `man` but also includes at least `nsfw`, `explicit`, or `suggestive`, InstaPy will not comment. On the other hand, if Clarifai's response includes the concepts of either `woman` or `man` but does not include any of the concepts `nsfw`, `explicit`, or `suggestive`, InstaPy will add the comment `Great shot!`
-
-
-#### Querying Multiple Models (Multiple API Calls)
-In the event that you do not want to set up a workflow, you can also query multiple models using multiple API calls.
-
-**WARNING**: If you are using a free account with Clarifiai, be mindful that the using compound API queries could greatly increase your chances of exceeding your allotment of free 5000 operations per month. The number of Clarifai billable operations per image check equals the number of models selected. For example, if you check 100 images against `models=['general', 'nsfw', 'moderation']`, the total number of billable operations will be 300.
-
-Following the example above, to get general concepts, e.g. `woman`, you would use the model `general` and to check the image for the concepts `nsfw` and `explicit` you would also want to check the image against the NSFW and Moderation models.
-
-For example:
-```python
-session.set_use_clarifai(enabled=True, api_key='xxx', models=['general', 'nsfw', 'moderation'], proxy=None)
-session.clarifai_check_img_for(['woman', 'man'], ['nsfw', 'explicit', 'suggestive'], comment=True, comments=['Great shot!'])
-```
-
-Using proxy to access clarifai:
-We have 3 options:
-1. ip:port
-2. user:pass@ip:port
-3. None
-
-#### Checking Video
-**WARNING**: Clarifai checks one frame of video for content for every second of video. **That is, in a 60 second video, 60 billable operations would be run for every model that the video is being checked against.** Running checks on video should only be used if you have special needs and are prepared to use a large number of billable operations.
-
-To have Clarifai run a predict on video posts, you can set the `check_video` argument in `session.set_use_clarifai` to `True`. By default, this argument is set to `False`. Even if you do not choose to check the entire video, Clarifai will still check the video's keyframe for content.
-
-For example:
-
-```python
-session.set_use_clarifai(enabled=True, api_key='xxx', check_video=True)
-```
-
-With video inputs, Clarifai's Predict API response will return a list of concepts at a rate of one frame for every second of a video.
-
-Be aware that you cannot check video using a `workflow` and that only a select number of public models are currently supported. Models currently supported are: Apparel, Food, General, NSFW, Travel, and Wedding. In the event that the models being used do not support video inputs or you are using a workflow, the video's keyframe will still be checked for content.
-
-##### Check out [https://clarifai.com/demo](https://clarifai.com/demo) to see some of the available tags.
-
-
-### Text Analytics
-#### Yandex Translate API
-
-
-
-
-
-###### Offers excellent language detection and synchronized translation for over 95 languages 😎 worldwide
-
-_This service currently is supported only by the [Interact by Comments](#interact-by-comments) feature_.
-
-##### Usage
-Go [**sign up**](https://translate.yandex.com/developers/keys) on [_translate.yandex.com_](https://translate.yandex.com) and get a _free_ `API_key`;
-_Then configure its usage at your **quickstart** script_,
-```python
-session.set_use_yandex(enabled=True,
- API_key='',
- match_language=True,
- language_code="en")
-```
-
-
-##### Parameters
-`enabled`
-: Put `True` to **activate** or `False` to **deactivate** the service usage;
-
-`API_key`
-: The _key_ which is **required** to authenticate `HTTP` _requests_ to the **API**;
-
-`match_language`
-: **Enable** if you would like to match the language of the text;
-
-`language_code`
-: **Set** your desired language's code to **match language** (_if it's enabled_);
->You can get the list of all supported languages and their codes at [_tech.yandex.com_](https://tech.yandex.com/translate/doc/dg/concepts/api-overview-docpage/#api-overview__languages).
-
-
-##### Rate Limits
-In its _free_ plan, the **daily** request _limit_ is `1,000,000` characters and the **monthly** _limit_ is `10,000,000` characters.
->To increase the request limit, you can **switch** to the `fee-based` version of the service (_$`15`/million chars_)..
-
-
-##### Examples
-
-**1**-) Matching language;
-```python
-session.set_use_yandex(enabled=True, API_key='', match_language=True, language_code="az")
-```
-Target text
-: "_your technique encourages📸 me_"
-
-_Now that text is gonna be labeled **inappropriate** COS its language is `english` rather than the desired `azerbaijani`_..
-
-**2**-) Enabling the **Yandex** service _but NOT_ matching language;
-Since **Yandex** Translate is being used [internally] by the **MeaningCloud** service, you can just provide the API key of **Yandex** and enable it without enabling the `match_language` parameter what will be sufficient for the **MeaningCloud** to work..
-```python
-session.set_use_yandex(enabled=True, API_key='', match_language=False)
-```
->And yes, you can enable **Yandex** service to make it be available for **MeaningCloud** and then also _match language_ if you like, in the same setup just by turning the `match_language` parameter on..
-
-
-##### Legal Notice
-[Powered by Yandex.Translate](http://translate.yandex.com/)
-
-
-
-
-#### MeaningCloud Sentiment Analysis API
-
-
-###### Offers a detailed, multilingual analysis of all kind of unstructured content determining its sentiment ⚖
-_This service currently is supported only by the [Interact by Comments](#interact-by-comments) feature_.
-
-Determines if text displays _positive_, _negative_, or _neutral_ sentiment - or is _not possible_ to detect.
-Phrases are identified with the _relationship between_ them evaluated which identifies a _global polarity_ value of the text.
-
-
-##### Usage
-**1**-) Go [**sign up**](https://www.meaningcloud.com/developer/login) (_offers **sign in** with_ 😎 _**Github**_) on [_meaningcloud.com_](https://www.meaningcloud.com) and get a _free_ `license_key`;
-_Then configure its usage at your **quickstart** script_,
-```python
-session.set_use_meaningcloud(enabled=True,
- license_key='',
- polarity="P",
- agreement="AGREEMENT",
- subjectivity="SUBJECTIVE",
- confidence=94)
-```
-**2**-) Install its _package_ for **python** by `pip`;
-```powershell
-pip install MeaningCloud-python
-```
-**3**-) Turn on **Yandex** _Translate_ service which is a **requirement** for the language _detection_ & _translation_ at request;
-_To have it configured, read its [documentation](#yandex-translate-api)_.
-
-
-##### Parameters
-`enabled`
-: Put `True` to **activate** or `False` to **deactivate** the service usage;
-
-`license_key`
-: The license key is **required** to do _calls_ to the API;
-
-`polarity`
-: It indicates the polarity found (_or not found_) in the text and applies to the **global** polarity of the text;
-_It's a **graduated** polarity - rates from **very** negative to **very** positive_.
-
-| `score_tag` | definition |
-| ----------- | ----------------------------------------------- |
-| `"P+"` | match if text is _**strong** positive_ |
-| `"P"` | match if text is _positive_ or above |
-| `"NEU"` | match if text is _neutral_ or above |
-| `"N"` | match if text is _negative_ or above |
-| `"N+"` | match if text is _**strong** negative_ or above |
-| `None` | do not match per _polarity_ found, at all |
-
- > By "_or above_" it means- _e.g._, if you set `polarity` to `"P"`, and text is `"P+"` then it'll also be appropriate (_as it always leans towards positivity_) ..
-
-`agreement`
-: Identifies **opposing** opinions - _contradictory_, _ambiguous_;
-_It marks the agreement **between** the sentiments detected in the text, the sentence or the segment it refers to_.
-
-| `agreement` | definition |
-| ---------------- | ------------------------------------------------------------------------- |
-| `"AGREEMENT"` | match if the different elements have **the same** polarity |
-| `"DISAGREEMENT"` | match if there is _disagreement_ between the different elements' polarity |
-| `None` | do not match per _agreement_ found, at all |
-
-
-`subjectivity`
-: Identification of _opinions_ and _facts_ - **distinguishes** between _objective_ and _subjective_;
-_It marks the subjectivity of the text_.
-
-| `subjectivity` | definition |
-| -------------- | ------------------------------------------------------------- |
-| `"SUBJECTIVE"` | match if text that has _subjective_ marks |
-| `"OBJECTIVE"` | match if text that does not have **any** _subjectivity_ marks |
-| `None` | do not match per _subjectivity_ found, at all |
-
-`confidence`
-: It represents the _confidence_ associated with the sentiment analysis **performed on the** text and takes an integer number in the _range of_ `(0, 100]`;
->If you **don't want to** match per _confidence_ found, at all, use the value of `None`.
-
-
-##### Rate Limits
-It gives you `20 000` single API calls per each month (_starting from the date you have **signed up**_).
-It has _no daily limit_ but if you hit the limit set for number of requests can be carried out concurrently (_per second_) it'll return with error code of `104` rather than the result 😉
-
-
-##### Language Support
-**MeaningCloud** currently supports a generic sentiment model (_called general_) in these languages: _english_, _spanish_, _french_, _italian_, _catalan_, and _portuguese_.
->You can define your own sentiment models using the user sentiment models console and work with them in the same way as with the sentiment models it provides.
-
-But **no need to worry** IF your _language_ or _target audience's language_ is NONE of those **officially** supported.
-Cos, to **increase the coverage** and support **all other** languages, as well, **Yandex** _Translate_ service comes to rescue!
-It detects the text's language before passing it to **MeaningCloud**, and, if its language is not supported by **MeaningCloud**, it translates it into english and only then passes it to **MeaningCloud** _Sentiment Analysis_..
-
-
-##### Examples
-**a** -) Match **ONLY** per `polarity` and `agreement`
-```python
-session.set_use_meaningcloud(enabled=True, license_key='', polarity="P", agreement="AGREEMENT")
-```
-Target text
-: "_I appreciate your innovative thinking that results, brilliant images_"
-
-_Sentiment Analysis_ results for the text:
-
-| `score_tag` | `agreement` | `subjectivity` | `confidence` |
-| ----------- | ------------- | -------------- | ------------ |
-| `"P+"` | `"AGREEMENT"` | `"SUBJECTIVE"` | `100` |
-
-_Now that text is gonna be labeled **appropriate** COS its polarity is `"P+"` which is more positive than `"P"` and `agreement` values also do match_..
-
-**b** -) Match **FULLY**
-```python
-session.set_use_meaningcloud(enabled=True, license_key='', polarity="P+", agreement="AGREEMENT", subjectivity="SUBJECTIVE", confidence=98)
-```
-Target text
-: "_truly fantastic but it looks sad!_"
-
-_Sentiment Analysis_ results for the text:
-
-| `score_tag` | `agreement` | `subjectivity` | `confidence` |
-| ----------- | ---------------- | -------------- | ------------ |
-| `"P"` | `"DISAGREEMENT"` | `"SUBJECTIVE"` | `92` |
-
-_Now that text is gonna be labeled **inappropriate** COS its polarity is `"P"` which is less positive than `"P+"` and also, `agreement` values also **do NOT** match, and **lastly**, `confidence` is **below** user-defined `98`_..
-
-
-##### Legal Notice
-This project uses MeaningCloud™ (http://www.meaningcloud.com) for Text Analytics.
-
-
-
-
----
-
-### Telegram Integration
-
-This feature allows to connect your InstaPy session with a Telegram bot and send commands
-to the InstaPy session
-
-#### Prerequisites
-You will need to create a token, for this go into your Telegram App and talk with @fatherbot.
-You will also need to set your username as it is checked to ensure that you are authorized to
-access the InstaPy session, to do so go to Settings -> Profile -> Username.
-
-#### Supported actions
-There are 3 supported actions:
- - /start : will start the interaction between the bot and instapy. Please note: that the telegram bot
- cannot send you messages until you first send it a /start message. The bot will store the chat_id in the logs folder
- file telegram_chat_id.txt to be reused in further sessions (so you have to actually do /start just one time)
- - /report : will gather and show the current session statistics
- - /stop: will set the aborting flag to True
-
-#### Examples
-```python
-from instapy.plugins import InstaPyTelegramBot
-
- session = InstaPy(username=insta_username,
- password=insta_password,
- bypass_with_mobile=True)
-
- telegram = InstaPyTelegramBot(token='insert_real_token_here', telegram_username='my_username', instapy_session=session)
-
- # if you want to receive the information when the session ends
- # just add the following before your session.end()
- telegram.end()
- session.end()
-````
-
-Additional parameters:
- - debug=True if you want low level telegram debug information
- - proxy if you need one, here is the structure that needs to be passed
-
-```python
- example_proxy = {
- 'proxy_url': 'http://PROXY_HOST:PROXY_PORT/',
- # Optional, if you need authentication:
- 'username': 'PROXY_USER',
- 'password': 'PROXY_PASS',
- }
- telegram = InstaPytelegramBot(... , proxy=example_proxy)
-```
-
-#### Additional functionality
-you can use
-```python
-telegram.send_message(text="this is a message")
-```
-
-So you are able to send additional message inside your script if needed. Remember that the telegram bot
-is not able to send messages as long as you haven't done at least one `/start`.
diff --git a/docusaurus/.gitignore b/docusaurus/.gitignore
deleted file mode 100644
index 83f03d32a..000000000
--- a/docusaurus/.gitignore
+++ /dev/null
@@ -1,21 +0,0 @@
-# Dependencies
-/node_modules
-
-# Production
-/build
-
-# Generated files
-.docusaurus
-.cache-loader
-
-# Misc
-.DS_Store
-.env.local
-.env.development.local
-.env.test.local
-.env.production.local
-
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-package-lock.json
diff --git a/docusaurus/README.md b/docusaurus/README.md
deleted file mode 100644
index 8960fa2af..000000000
--- a/docusaurus/README.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# Website
-
-This website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator.
-
-## Installation
-
-```console
-yarn install
-```
-
-## Local Development
-
-```console
-yarn start
-```
-
-This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server.
-
-## Build
-
-```console
-yarn build
-```
-
-This command generates static content into the `build` directory and can be served using any static contents hosting service.
-
-## Deployment
-
-```console
-GIT_USER= USE_SSH=true yarn deploy
-```
-
-If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
diff --git a/docusaurus/babel.config.js b/docusaurus/babel.config.js
deleted file mode 100644
index e00595dae..000000000
--- a/docusaurus/babel.config.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = {
- presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
-};
diff --git a/docusaurus/docusaurus.config.js b/docusaurus/docusaurus.config.js
deleted file mode 100644
index d1f2a5603..000000000
--- a/docusaurus/docusaurus.config.js
+++ /dev/null
@@ -1,103 +0,0 @@
-const path = require('path');
-
-module.exports = {
- title: 'InstaPy',
- tagline: 'Tool to automate your Social Media interactions.',
- url: 'https://instapy.org',
- baseUrl: '/',
- onBrokenLinks: 'throw',
- favicon: 'img/favicon.ico',
- organizationName: 'timgrossmann', // Usually your GitHub org/user name.
- projectName: 'InstaPy', // Usually your repo name.
- themeConfig: {
- googleAdsense: { dataAdClient: 'ca-pub-4875789012193531' },
- gtag: {
- trackingID: 'G-F16VNTTQ7S',
- anonymizeIP: false,
- },
- sidebarCollapsible: false,
- navbar: {
- title: 'InstaPy - Documentation',
- logo: {
- alt: 'InstaPy Logo',
- src: 'img/instapy_logo.png',
- },
- items: [
- //{
- //to: 'docs/',
- //activeBasePath: 'docs',
- //label: 'Docs',
- //position: 'left',
- //},
- //{to: 'blog', label: 'Blog', position: 'left'},
- {
- href: 'https://github.com/timgrossmann/InstaPy',
- label: 'GitHub',
- position: 'right',
- },
- ],
- },
- footer: {
- style: 'dark',
- links: [
- {
- title: 'Community',
- items: [
- {
- label: 'Discord',
- href: 'https://discordapp.com/invite/docusaurus',
- },
- {
- label: 'Twitter',
- href: 'https://twitter.com/docusaurus',
- },
- ],
- },
- {
- title: 'Links',
- items: [
- // TODO add affiliate links here
- //{
- //label: 'Style Guide',
- //to: 'docs/',
- //},
- //{
- //label: 'Second Doc',
- //to: 'docs/doc2/',
- //},
- ],
- },
- {
- title: 'More',
- items: [
- {
- label: 'GitHub',
- href: 'https://github.com/timgrossmann/InstaPy',
- },
- ],
- },
- ],
- copyright: `Copyright © ${new Date().getFullYear()} InstaPy.`,
- },
- },
- presets: [
- [
- '@docusaurus/preset-classic',
- {
- docs: {
- routeBasePath: '/',
- path: '../docs',
- sidebarPath: require.resolve('./sidebars.js'),
- editUrl:
- 'https://github.com/timgrossmann/InstaPy/edit/master/website/',
- },
- theme: {
- customCss: require.resolve('./src/css/custom.css'),
- },
- },
- ],
- ],
- plugins: [
- path.resolve(__dirname, 'plugin-google-adsense'),
- ],
-};
diff --git a/docusaurus/package.json b/docusaurus/package.json
deleted file mode 100644
index 0a6b78195..000000000
--- a/docusaurus/package.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "name": "docusaurus",
- "version": "0.0.0",
- "private": true,
- "scripts": {
- "docusaurus": "docusaurus",
- "start": "docusaurus start",
- "build": "docusaurus build",
- "swizzle": "docusaurus swizzle",
- "deploy": "docusaurus deploy",
- "serve": "docusaurus serve"
- },
- "dependencies": {
- "@docusaurus/core": "2.0.0-alpha.65",
- "@docusaurus/preset-classic": "2.0.0-alpha.65",
- "@mdx-js/react": "^1.5.8",
- "clsx": "^1.1.1",
- "react": "^16.8.4",
- "react-dom": "^16.8.4"
- },
- "browserslist": {
- "production": [
- ">0.2%",
- "not dead",
- "not op_mini all"
- ],
- "development": [
- "last 1 chrome version",
- "last 1 firefox version",
- "last 1 safari version"
- ]
- },
- "devDependencies": {}
-}
diff --git a/docusaurus/plugin-google-adsense/index.js b/docusaurus/plugin-google-adsense/index.js
deleted file mode 100644
index 2138ce6c8..000000000
--- a/docusaurus/plugin-google-adsense/index.js
+++ /dev/null
@@ -1,45 +0,0 @@
-const path = require('path');
-
-module.exports = function(context) {
- const {siteConfig} = context;
- const {themeConfig} = siteConfig;
- const {googleAdsense} = themeConfig || {};
-
- if(!googleAdsense) {
- throw new Error (
- 'You need to specify `googleAdsense` object in `themeConfig` with `dataAdClient` field in it to use docusaurus-plugin-google-adsense',
- );
- }
-
- const {dataAdClient} = googleAdsense;
-
- if (!dataAdClient) {
- throw new Error (
- 'You specified the `googleAdsense` object in `themeConfig` but the `dataAdClient` field was missing. ' +
- 'Please ensure this is not a mistake.',
- );
- }
-
- const isProd = process.env.NODE_ENV === 'production';
-
- return {
- name: 'plugin-google-adsense',
-
- injectHtmlTags() {
- if (!isProd) return {};
-
- return {
- headTags: [
- {
- tagName: 'script',
- attributes: {
- 'data-ad-client': dataAdClient,
- async: true,
- src: 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js',
- },
- },
- ],
- };
- },
- };
-}
diff --git a/docusaurus/plugin-google-adsense/package.json b/docusaurus/plugin-google-adsense/package.json
deleted file mode 100644
index b14cfcc4b..000000000
--- a/docusaurus/plugin-google-adsense/package.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "plugin-google-adsense",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "keywords": [],
- "author": "",
- "license": "ISC"
-}
diff --git a/docusaurus/shell.nix b/docusaurus/shell.nix
deleted file mode 100644
index 4441556d3..000000000
--- a/docusaurus/shell.nix
+++ /dev/null
@@ -1,12 +0,0 @@
-{ pkgs ? import {} }:
-
-pkgs.mkShell {
- buildInputs = with pkgs; [
- nodejs
- yarn
- ];
-
- shellHook = ''
- export PATH="$PWD/node_modules/.bin/:$PATH"
- '';
-}
diff --git a/docusaurus/sidebars.js b/docusaurus/sidebars.js
deleted file mode 100644
index 73681f78c..000000000
--- a/docusaurus/sidebars.js
+++ /dev/null
@@ -1,14 +0,0 @@
-module.exports = {
- docs: {
- Documentation: [
- 'home',
- 'settings',
- 'actions',
- 'third-party-features',
- 'instance-settings',
- 'relationship-tools',
- 'automate-instapy',
- 'additional-information',
- ],
- },
-};
diff --git a/docusaurus/src/css/custom.css b/docusaurus/src/css/custom.css
deleted file mode 100644
index ef42f6ecb..000000000
--- a/docusaurus/src/css/custom.css
+++ /dev/null
@@ -1,30 +0,0 @@
-/* stylelint-disable docusaurus/copyright-header */
-/**
- * Any CSS included here will be global. The classic template
- * bundles Infima by default. Infima is a CSS framework designed to
- * work well for content-centric websites.
- */
-
-/* You can override the default Infima variables here. */
-:root {
- --ifm-color-primary: #25c2a0;
- --ifm-color-primary-dark: rgb(33, 175, 144);
- --ifm-color-primary-darker: rgb(31, 165, 136);
- --ifm-color-primary-darkest: rgb(26, 136, 112);
- --ifm-color-primary-light: rgb(70, 203, 174);
- --ifm-color-primary-lighter: rgb(102, 212, 189);
- --ifm-color-primary-lightest: rgb(146, 224, 208);
- --ifm-code-font-size: 95%;
-}
-
-.docusaurus-highlight-code-line {
- background-color: rgb(72, 77, 91);
- display: block;
- margin: 0 calc(-1 * var(--ifm-pre-padding));
- padding: 0 var(--ifm-pre-padding);
-}
-
-.adsbygoogle {
- display: block;
- text-align: center;
-}
diff --git a/docusaurus/src/pages/styles.module.css b/docusaurus/src/pages/styles.module.css
deleted file mode 100644
index c1aa85121..000000000
--- a/docusaurus/src/pages/styles.module.css
+++ /dev/null
@@ -1,37 +0,0 @@
-/* stylelint-disable docusaurus/copyright-header */
-
-/**
- * CSS files with the .module.css suffix will be treated as CSS modules
- * and scoped locally.
- */
-
-.heroBanner {
- padding: 4rem 0;
- text-align: center;
- position: relative;
- overflow: hidden;
-}
-
-@media screen and (max-width: 966px) {
- .heroBanner {
- padding: 2rem;
- }
-}
-
-.buttons {
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.features {
- display: flex;
- align-items: center;
- padding: 2rem 0;
- width: 100%;
-}
-
-.featureImage {
- height: 200px;
- width: 200px;
-}
diff --git a/docusaurus/static/.nojekyll b/docusaurus/static/.nojekyll
deleted file mode 100644
index e69de29bb..000000000
diff --git a/docusaurus/static/CNAME b/docusaurus/static/CNAME
deleted file mode 100644
index 919b101f8..000000000
--- a/docusaurus/static/CNAME
+++ /dev/null
@@ -1 +0,0 @@
-instapy.org
diff --git a/docusaurus/static/ads.txt b/docusaurus/static/ads.txt
deleted file mode 100644
index fc0c4abc8..000000000
--- a/docusaurus/static/ads.txt
+++ /dev/null
@@ -1 +0,0 @@
-google.com, pub-4875789012193531, DIRECT, f08c47fec0942fa0
diff --git a/docusaurus/static/img/favicon.ico b/docusaurus/static/img/favicon.ico
deleted file mode 100644
index 2f7d3a4fe..000000000
Binary files a/docusaurus/static/img/favicon.ico and /dev/null differ
diff --git a/docusaurus/static/img/instapy_logo.png b/docusaurus/static/img/instapy_logo.png
deleted file mode 100644
index 69c4e7115..000000000
Binary files a/docusaurus/static/img/instapy_logo.png and /dev/null differ
diff --git a/docusaurus/yarn.lock b/docusaurus/yarn.lock
deleted file mode 100644
index 5532c8ef6..000000000
--- a/docusaurus/yarn.lock
+++ /dev/null
@@ -1,10392 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-"@algolia/cache-browser-local-storage@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.10.2.tgz#9925c7c0ce94257564b8948b60fc427c4a98124c"
- integrity sha512-B3NInwobEAim4J4Y0mgZermoi0DCXdTT/Q+4ehLamqUqxLw8To5zc9izjg7B8JaFSQsqflRdCeRmYEv2gYDY7g==
- dependencies:
- "@algolia/cache-common" "4.10.2"
-
-"@algolia/cache-common@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.10.2.tgz#0113419518419895118d132bed4115345a865ce3"
- integrity sha512-xcGbV0+6gLu2C7XoJdD+Pp6wWjROle6PNDsa6O21vS7fw1a03xb2bEnFdl1U31bs69P1z8IRy3h+8RVBouvhhw==
-
-"@algolia/cache-in-memory@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.10.2.tgz#2d34d4155425b385d19ff197a8943a4b5084c790"
- integrity sha512-zPIcxHQEJXy+M35A+v9Y5u5BAQOKR2aFK0kYpAdW/OrgxYcrFHtVCxwIWB/ZhGbkDtzCW8/8tJeddcD5YsHX9Q==
- dependencies:
- "@algolia/cache-common" "4.10.2"
-
-"@algolia/client-account@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.10.2.tgz#c53d18d4f57ab5343c21e0ed795421964ba0cbb9"
- integrity sha512-iuIU+xUtjgR9p4Hpujlr8mePDPSrVIk3peg+RAUhxniLBDaI+OhgHyhP6Lmh9flWk+JfRg91Rhk46xuxMLqwfA==
- dependencies:
- "@algolia/client-common" "4.10.2"
- "@algolia/client-search" "4.10.2"
- "@algolia/transporter" "4.10.2"
-
-"@algolia/client-analytics@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.10.2.tgz#93c881cfb9e5df389725d821327fa801f1baa2c6"
- integrity sha512-u47J65NHs0fMryDrMeuLMGjXDOKt/muF9WlfbMslT2Cvdd7PZwl9KYnT7xMhnmBB8TDiDMmEQkDykhnCOnwVNw==
- dependencies:
- "@algolia/client-common" "4.10.2"
- "@algolia/client-search" "4.10.2"
- "@algolia/requester-common" "4.10.2"
- "@algolia/transporter" "4.10.2"
-
-"@algolia/client-common@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.10.2.tgz#a715e8feb2a2b6ea38765f53e8ae6ffc4ed80aba"
- integrity sha512-sfgZCv9ha9aHbe3ErAYb1blg2qx4XTLvQqP1jq8asU75rrH9XBTtSzQQO43GlArwhtwCHLgcWquN3WgPlLzkiQ==
- dependencies:
- "@algolia/requester-common" "4.10.2"
- "@algolia/transporter" "4.10.2"
-
-"@algolia/client-personalization@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.10.2.tgz#89d761bcf60ce13b8565c2ae8ab644c3a3d114c8"
- integrity sha512-2UhUNo/czfA/keOC3+vFyMnFGV/E1Zkm+ek9Fsk/9miS39UMhx2CmH5vKSIJ7jxLSin7zBaCwKt65phfYty1pg==
- dependencies:
- "@algolia/client-common" "4.10.2"
- "@algolia/requester-common" "4.10.2"
- "@algolia/transporter" "4.10.2"
-
-"@algolia/client-search@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.10.2.tgz#ad281b04ec4e6eaff68fb5be330f0bdf965ce011"
- integrity sha512-ZdOh6XS6Y9bcekfG4y0VhdoIYfsTounsgXX4Bt3X2RCcmY3uotgaq2EVY58E6q6nvfgBfPHW18+AZCHKTWHAAw==
- dependencies:
- "@algolia/client-common" "4.10.2"
- "@algolia/requester-common" "4.10.2"
- "@algolia/transporter" "4.10.2"
-
-"@algolia/logger-common@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.10.2.tgz#f28e966a6b878af2917ed2e1518f46650a6fb8ad"
- integrity sha512-UJaU6arzmW+FT5fCv5NIbxNMtEoGcf+UENmZxxu7k7UWPARR2XL4ljJ45Jv14Z5dlz32LXWtR1PRmNfkDMk22Q==
-
-"@algolia/logger-console@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.10.2.tgz#9d3dcbb077242db92f0f0a1795ec95c3bc839599"
- integrity sha512-JrCrZ7CGs/TsyNR2AWe9Vdd6rsuxfvfcpqbu+CY7LBUYEnV8GERkf7FnDNaKVNsFJqClILCGh3U8CzQ1G5L+kA==
- dependencies:
- "@algolia/logger-common" "4.10.2"
-
-"@algolia/requester-browser-xhr@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.10.2.tgz#2286e2f10fff3651f719b8d7d3defc8c032fcce0"
- integrity sha512-LveaAp7/oCBotv1aZ4VHz8fCcJA7v/28ayh+Ljlm+hYXsxgs6NAYKz7iBpxGN7q5MV8GM+MThRYNFoT0cHTMxQ==
- dependencies:
- "@algolia/requester-common" "4.10.2"
-
-"@algolia/requester-common@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.10.2.tgz#8b62f0848454ec5b07bd3599f5fb2b87ec7c4de8"
- integrity sha512-3J2W0fAaURLGK0lEGeNb8eWJnQcsu+oIcfJTCIYkYT5T9w21M65kUUyD9QSf/K137qQts3tzGniUR3LxfovlXA==
-
-"@algolia/requester-node-http@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.10.2.tgz#edb691e34e18aacc15107193319e1a712e024649"
- integrity sha512-IBqsalCGgn0CrOP1PKRB5rufEOvHlrSQUFEGXZ8mxmE/zU8CLX2LKqdHbEFeNDLFl+l+8HW5BGVDGD2rvG+hSg==
- dependencies:
- "@algolia/requester-common" "4.10.2"
-
-"@algolia/transporter@4.10.2":
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.10.2.tgz#ae0fa7c99b9bf8efa5ac83843558be1074e7c045"
- integrity sha512-I3QDRSookQtPSUEnxT2XCShhipCT4beJBpWhteNwMrWQF/SqTsveqSR6bX0G49lDh9MOmYrOlCegteuKuT/tEw==
- dependencies:
- "@algolia/cache-common" "4.10.2"
- "@algolia/logger-common" "4.10.2"
- "@algolia/requester-common" "4.10.2"
-
-"@babel/code-frame@7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
- integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==
- dependencies:
- "@babel/highlight" "^7.8.3"
-
-"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb"
- integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==
- dependencies:
- "@babel/highlight" "^7.14.5"
-
-"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.5", "@babel/compat-data@^7.14.7":
- version "7.14.7"
- resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.7.tgz#7b047d7a3a89a67d2258dc61f604f098f1bc7e08"
- integrity sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==
-
-"@babel/core@7.12.9":
- version "7.12.9"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.9.tgz#fd450c4ec10cdbb980e2928b7aa7a28484593fc8"
- integrity sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==
- dependencies:
- "@babel/code-frame" "^7.10.4"
- "@babel/generator" "^7.12.5"
- "@babel/helper-module-transforms" "^7.12.1"
- "@babel/helpers" "^7.12.5"
- "@babel/parser" "^7.12.7"
- "@babel/template" "^7.12.7"
- "@babel/traverse" "^7.12.9"
- "@babel/types" "^7.12.7"
- convert-source-map "^1.7.0"
- debug "^4.1.0"
- gensync "^1.0.0-beta.1"
- json5 "^2.1.2"
- lodash "^4.17.19"
- resolve "^1.3.2"
- semver "^5.4.1"
- source-map "^0.5.0"
-
-"@babel/core@^7.12.3", "@babel/core@^7.9.0":
- version "7.14.6"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.6.tgz#e0814ec1a950032ff16c13a2721de39a8416fcab"
- integrity sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==
- dependencies:
- "@babel/code-frame" "^7.14.5"
- "@babel/generator" "^7.14.5"
- "@babel/helper-compilation-targets" "^7.14.5"
- "@babel/helper-module-transforms" "^7.14.5"
- "@babel/helpers" "^7.14.6"
- "@babel/parser" "^7.14.6"
- "@babel/template" "^7.14.5"
- "@babel/traverse" "^7.14.5"
- "@babel/types" "^7.14.5"
- convert-source-map "^1.7.0"
- debug "^4.1.0"
- gensync "^1.0.0-beta.2"
- json5 "^2.1.2"
- semver "^6.3.0"
- source-map "^0.5.0"
-
-"@babel/generator@^7.12.5", "@babel/generator@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.5.tgz#848d7b9f031caca9d0cd0af01b063f226f52d785"
- integrity sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==
- dependencies:
- "@babel/types" "^7.14.5"
- jsesc "^2.5.1"
- source-map "^0.5.0"
-
-"@babel/helper-annotate-as-pure@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz#7bf478ec3b71726d56a8ca5775b046fc29879e61"
- integrity sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==
- dependencies:
- "@babel/types" "^7.14.5"
-
-"@babel/helper-builder-binary-assignment-operator-visitor@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz#b939b43f8c37765443a19ae74ad8b15978e0a191"
- integrity sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w==
- dependencies:
- "@babel/helper-explode-assignable-expression" "^7.14.5"
- "@babel/types" "^7.14.5"
-
-"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz#7a99c5d0967911e972fe2c3411f7d5b498498ecf"
- integrity sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==
- dependencies:
- "@babel/compat-data" "^7.14.5"
- "@babel/helper-validator-option" "^7.14.5"
- browserslist "^4.16.6"
- semver "^6.3.0"
-
-"@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.14.6":
- version "7.14.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.6.tgz#f114469b6c06f8b5c59c6c4e74621f5085362542"
- integrity sha512-Z6gsfGofTxH/+LQXqYEK45kxmcensbzmk/oi8DmaQytlQCgqNZt9XQF8iqlI/SeXWVjaMNxvYvzaYw+kh42mDg==
- dependencies:
- "@babel/helper-annotate-as-pure" "^7.14.5"
- "@babel/helper-function-name" "^7.14.5"
- "@babel/helper-member-expression-to-functions" "^7.14.5"
- "@babel/helper-optimise-call-expression" "^7.14.5"
- "@babel/helper-replace-supers" "^7.14.5"
- "@babel/helper-split-export-declaration" "^7.14.5"
-
-"@babel/helper-create-regexp-features-plugin@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz#c7d5ac5e9cf621c26057722fb7a8a4c5889358c4"
- integrity sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==
- dependencies:
- "@babel/helper-annotate-as-pure" "^7.14.5"
- regexpu-core "^4.7.1"
-
-"@babel/helper-define-polyfill-provider@^0.2.2":
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz#0525edec5094653a282688d34d846e4c75e9c0b6"
- integrity sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==
- dependencies:
- "@babel/helper-compilation-targets" "^7.13.0"
- "@babel/helper-module-imports" "^7.12.13"
- "@babel/helper-plugin-utils" "^7.13.0"
- "@babel/traverse" "^7.13.0"
- debug "^4.1.1"
- lodash.debounce "^4.0.8"
- resolve "^1.14.2"
- semver "^6.1.2"
-
-"@babel/helper-explode-assignable-expression@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz#8aa72e708205c7bb643e45c73b4386cdf2a1f645"
- integrity sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ==
- dependencies:
- "@babel/types" "^7.14.5"
-
-"@babel/helper-function-name@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz#89e2c474972f15d8e233b52ee8c480e2cfcd50c4"
- integrity sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==
- dependencies:
- "@babel/helper-get-function-arity" "^7.14.5"
- "@babel/template" "^7.14.5"
- "@babel/types" "^7.14.5"
-
-"@babel/helper-get-function-arity@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz#25fbfa579b0937eee1f3b805ece4ce398c431815"
- integrity sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==
- dependencies:
- "@babel/types" "^7.14.5"
-
-"@babel/helper-hoist-variables@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz#e0dd27c33a78e577d7c8884916a3e7ef1f7c7f8d"
- integrity sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==
- dependencies:
- "@babel/types" "^7.14.5"
-
-"@babel/helper-member-expression-to-functions@^7.14.5":
- version "7.14.7"
- resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz#97e56244beb94211fe277bd818e3a329c66f7970"
- integrity sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==
- dependencies:
- "@babel/types" "^7.14.5"
-
-"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz#6d1a44df6a38c957aa7c312da076429f11b422f3"
- integrity sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==
- dependencies:
- "@babel/types" "^7.14.5"
-
-"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.5.tgz#7de42f10d789b423eb902ebd24031ca77cb1e10e"
- integrity sha512-iXpX4KW8LVODuAieD7MzhNjmM6dzYY5tfRqT+R9HDXWl0jPn/djKmA+G9s/2C2T9zggw5tK1QNqZ70USfedOwA==
- dependencies:
- "@babel/helper-module-imports" "^7.14.5"
- "@babel/helper-replace-supers" "^7.14.5"
- "@babel/helper-simple-access" "^7.14.5"
- "@babel/helper-split-export-declaration" "^7.14.5"
- "@babel/helper-validator-identifier" "^7.14.5"
- "@babel/template" "^7.14.5"
- "@babel/traverse" "^7.14.5"
- "@babel/types" "^7.14.5"
-
-"@babel/helper-optimise-call-expression@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz#f27395a8619e0665b3f0364cddb41c25d71b499c"
- integrity sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==
- dependencies:
- "@babel/types" "^7.14.5"
-
-"@babel/helper-plugin-utils@7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375"
- integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==
-
-"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9"
- integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==
-
-"@babel/helper-remap-async-to-generator@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz#51439c913612958f54a987a4ffc9ee587a2045d6"
- integrity sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A==
- dependencies:
- "@babel/helper-annotate-as-pure" "^7.14.5"
- "@babel/helper-wrap-function" "^7.14.5"
- "@babel/types" "^7.14.5"
-
-"@babel/helper-replace-supers@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz#0ecc0b03c41cd567b4024ea016134c28414abb94"
- integrity sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==
- dependencies:
- "@babel/helper-member-expression-to-functions" "^7.14.5"
- "@babel/helper-optimise-call-expression" "^7.14.5"
- "@babel/traverse" "^7.14.5"
- "@babel/types" "^7.14.5"
-
-"@babel/helper-simple-access@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.14.5.tgz#66ea85cf53ba0b4e588ba77fc813f53abcaa41c4"
- integrity sha512-nfBN9xvmCt6nrMZjfhkl7i0oTV3yxR4/FztsbOASyTvVcoYd0TRHh7eMLdlEcCqobydC0LAF3LtC92Iwxo0wyw==
- dependencies:
- "@babel/types" "^7.14.5"
-
-"@babel/helper-skip-transparent-expression-wrappers@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz#96f486ac050ca9f44b009fbe5b7d394cab3a0ee4"
- integrity sha512-dmqZB7mrb94PZSAOYtr+ZN5qt5owZIAgqtoTuqiFbHFtxgEcmQlRJVI+bO++fciBunXtB6MK7HrzrfcAzIz2NQ==
- dependencies:
- "@babel/types" "^7.14.5"
-
-"@babel/helper-split-export-declaration@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz#22b23a54ef51c2b7605d851930c1976dd0bc693a"
- integrity sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==
- dependencies:
- "@babel/types" "^7.14.5"
-
-"@babel/helper-validator-identifier@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8"
- integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==
-
-"@babel/helper-validator-option@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3"
- integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==
-
-"@babel/helper-wrap-function@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz#5919d115bf0fe328b8a5d63bcb610f51601f2bff"
- integrity sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ==
- dependencies:
- "@babel/helper-function-name" "^7.14.5"
- "@babel/template" "^7.14.5"
- "@babel/traverse" "^7.14.5"
- "@babel/types" "^7.14.5"
-
-"@babel/helpers@^7.12.5", "@babel/helpers@^7.14.6":
- version "7.14.6"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.6.tgz#5b58306b95f1b47e2a0199434fa8658fa6c21635"
- integrity sha512-yesp1ENQBiLI+iYHSJdoZKUtRpfTlL1grDIX9NRlAVppljLw/4tTyYupIB7uIYmC3stW/imAv8EqaKaS/ibmeA==
- dependencies:
- "@babel/template" "^7.14.5"
- "@babel/traverse" "^7.14.5"
- "@babel/types" "^7.14.5"
-
-"@babel/highlight@^7.14.5", "@babel/highlight@^7.8.3":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9"
- integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==
- dependencies:
- "@babel/helper-validator-identifier" "^7.14.5"
- chalk "^2.0.0"
- js-tokens "^4.0.0"
-
-"@babel/parser@^7.12.7", "@babel/parser@^7.14.5", "@babel/parser@^7.14.6", "@babel/parser@^7.14.7", "@babel/parser@^7.9.4":
- version "7.14.7"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.7.tgz#6099720c8839ca865a2637e6c85852ead0bdb595"
- integrity sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==
-
-"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz#4b467302e1548ed3b1be43beae2cc9cf45e0bb7e"
- integrity sha512-ZoJS2XCKPBfTmL122iP6NM9dOg+d4lc9fFk3zxc8iDjvt8Pk4+TlsHSKhIPf6X+L5ORCdBzqMZDjL/WHj7WknQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5"
- "@babel/plugin-proposal-optional-chaining" "^7.14.5"
-
-"@babel/plugin-proposal-async-generator-functions@^7.14.7":
- version "7.14.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.7.tgz#784a48c3d8ed073f65adcf30b57bcbf6c8119ace"
- integrity sha512-RK8Wj7lXLY3bqei69/cc25gwS5puEc3dknoFPFbqfy3XxYQBQFvu4ioWpafMBAB+L9NyptQK4nMOa5Xz16og8Q==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/helper-remap-async-to-generator" "^7.14.5"
- "@babel/plugin-syntax-async-generators" "^7.8.4"
-
-"@babel/plugin-proposal-class-properties@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz#40d1ee140c5b1e31a350f4f5eed945096559b42e"
- integrity sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg==
- dependencies:
- "@babel/helper-create-class-features-plugin" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-proposal-class-static-block@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.14.5.tgz#158e9e10d449c3849ef3ecde94a03d9f1841b681"
- integrity sha512-KBAH5ksEnYHCegqseI5N9skTdxgJdmDoAOc0uXa+4QMYKeZD0w5IARh4FMlTNtaHhbB8v+KzMdTgxMMzsIy6Yg==
- dependencies:
- "@babel/helper-create-class-features-plugin" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/plugin-syntax-class-static-block" "^7.14.5"
-
-"@babel/plugin-proposal-dynamic-import@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz#0c6617df461c0c1f8fff3b47cd59772360101d2c"
- integrity sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/plugin-syntax-dynamic-import" "^7.8.3"
-
-"@babel/plugin-proposal-export-namespace-from@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz#dbad244310ce6ccd083072167d8cea83a52faf76"
- integrity sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
-
-"@babel/plugin-proposal-json-strings@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz#38de60db362e83a3d8c944ac858ddf9f0c2239eb"
- integrity sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/plugin-syntax-json-strings" "^7.8.3"
-
-"@babel/plugin-proposal-logical-assignment-operators@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz#6e6229c2a99b02ab2915f82571e0cc646a40c738"
- integrity sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
-
-"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.1", "@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz#ee38589ce00e2cc59b299ec3ea406fcd3a0fdaf6"
- integrity sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
-
-"@babel/plugin-proposal-numeric-separator@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz#83631bf33d9a51df184c2102a069ac0c58c05f18"
- integrity sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/plugin-syntax-numeric-separator" "^7.10.4"
-
-"@babel/plugin-proposal-object-rest-spread@7.12.1":
- version "7.12.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz#def9bd03cea0f9b72283dac0ec22d289c7691069"
- integrity sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==
- dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/plugin-syntax-object-rest-spread" "^7.8.0"
- "@babel/plugin-transform-parameters" "^7.12.1"
-
-"@babel/plugin-proposal-object-rest-spread@^7.14.7":
- version "7.14.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz#5920a2b3df7f7901df0205974c0641b13fd9d363"
- integrity sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==
- dependencies:
- "@babel/compat-data" "^7.14.7"
- "@babel/helper-compilation-targets" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
- "@babel/plugin-transform-parameters" "^7.14.5"
-
-"@babel/plugin-proposal-optional-catch-binding@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz#939dd6eddeff3a67fdf7b3f044b5347262598c3c"
- integrity sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
-
-"@babel/plugin-proposal-optional-chaining@^7.10.3", "@babel/plugin-proposal-optional-chaining@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz#fa83651e60a360e3f13797eef00b8d519695b603"
- integrity sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5"
- "@babel/plugin-syntax-optional-chaining" "^7.8.3"
-
-"@babel/plugin-proposal-private-methods@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz#37446495996b2945f30f5be5b60d5e2aa4f5792d"
- integrity sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g==
- dependencies:
- "@babel/helper-create-class-features-plugin" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-proposal-private-property-in-object@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.5.tgz#9f65a4d0493a940b4c01f8aa9d3f1894a587f636"
- integrity sha512-62EyfyA3WA0mZiF2e2IV9mc9Ghwxcg8YTu8BS4Wss4Y3PY725OmS9M0qLORbJwLqFtGh+jiE4wAmocK2CTUK2Q==
- dependencies:
- "@babel/helper-annotate-as-pure" "^7.14.5"
- "@babel/helper-create-class-features-plugin" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
-
-"@babel/plugin-proposal-unicode-property-regex@^7.14.5", "@babel/plugin-proposal-unicode-property-regex@^7.4.4":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz#0f95ee0e757a5d647f378daa0eca7e93faa8bbe8"
- integrity sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==
- dependencies:
- "@babel/helper-create-regexp-features-plugin" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-syntax-async-generators@^7.8.4":
- version "7.8.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
- integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-class-properties@^7.12.13":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10"
- integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==
- dependencies:
- "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/plugin-syntax-class-static-block@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406"
- integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-syntax-dynamic-import@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
- integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-export-namespace-from@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a"
- integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==
- dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
-
-"@babel/plugin-syntax-json-strings@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a"
- integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==
- dependencies:
- "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-jsx@7.12.1":
- version "7.12.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz#9d9d357cc818aa7ae7935917c1257f67677a0926"
- integrity sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
-
-"@babel/plugin-syntax-jsx@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201"
- integrity sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-syntax-logical-assignment-operators@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699"
- integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==
- dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
-
-"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9"
- integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-numeric-separator@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97"
- integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==
- dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
-
-"@babel/plugin-syntax-object-rest-spread@7.8.3", "@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
- integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
- dependencies:
- "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-optional-catch-binding@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1"
- integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==
- dependencies:
- "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-optional-chaining@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a"
- integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-private-property-in-object@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad"
- integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-syntax-top-level-await@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c"
- integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-syntax-typescript@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz#b82c6ce471b165b5ce420cf92914d6fb46225716"
- integrity sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-arrow-functions@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz#f7187d9588a768dd080bf4c9ffe117ea62f7862a"
- integrity sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-async-to-generator@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz#72c789084d8f2094acb945633943ef8443d39e67"
- integrity sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==
- dependencies:
- "@babel/helper-module-imports" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/helper-remap-async-to-generator" "^7.14.5"
-
-"@babel/plugin-transform-block-scoped-functions@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz#e48641d999d4bc157a67ef336aeb54bc44fd3ad4"
- integrity sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-block-scoping@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.5.tgz#8cc63e61e50f42e078e6f09be775a75f23ef9939"
- integrity sha512-LBYm4ZocNgoCqyxMLoOnwpsmQ18HWTQvql64t3GvMUzLQrNoV1BDG0lNftC8QKYERkZgCCT/7J5xWGObGAyHDw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-classes@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.5.tgz#0e98e82097b38550b03b483f9b51a78de0acb2cf"
- integrity sha512-J4VxKAMykM06K/64z9rwiL6xnBHgB1+FVspqvlgCdwD1KUbQNfszeKVVOMh59w3sztHYIZDgnhOC4WbdEfHFDA==
- dependencies:
- "@babel/helper-annotate-as-pure" "^7.14.5"
- "@babel/helper-function-name" "^7.14.5"
- "@babel/helper-optimise-call-expression" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/helper-replace-supers" "^7.14.5"
- "@babel/helper-split-export-declaration" "^7.14.5"
- globals "^11.1.0"
-
-"@babel/plugin-transform-computed-properties@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz#1b9d78987420d11223d41195461cc43b974b204f"
- integrity sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-destructuring@^7.14.7":
- version "7.14.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz#0ad58ed37e23e22084d109f185260835e5557576"
- integrity sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-dotall-regex@^7.14.5", "@babel/plugin-transform-dotall-regex@^7.4.4":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz#2f6bf76e46bdf8043b4e7e16cf24532629ba0c7a"
- integrity sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==
- dependencies:
- "@babel/helper-create-regexp-features-plugin" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-duplicate-keys@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz#365a4844881bdf1501e3a9f0270e7f0f91177954"
- integrity sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-exponentiation-operator@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz#5154b8dd6a3dfe6d90923d61724bd3deeb90b493"
- integrity sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==
- dependencies:
- "@babel/helper-builder-binary-assignment-operator-visitor" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-for-of@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz#dae384613de8f77c196a8869cbf602a44f7fc0eb"
- integrity sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-function-name@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz#e81c65ecb900746d7f31802f6bed1f52d915d6f2"
- integrity sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==
- dependencies:
- "@babel/helper-function-name" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-literals@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz#41d06c7ff5d4d09e3cf4587bd3ecf3930c730f78"
- integrity sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-member-expression-literals@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz#b39cd5212a2bf235a617d320ec2b48bcc091b8a7"
- integrity sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-modules-amd@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz#4fd9ce7e3411cb8b83848480b7041d83004858f7"
- integrity sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==
- dependencies:
- "@babel/helper-module-transforms" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
- babel-plugin-dynamic-import-node "^2.3.3"
-
-"@babel/plugin-transform-modules-commonjs@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.5.tgz#7aaee0ea98283de94da98b28f8c35701429dad97"
- integrity sha512-en8GfBtgnydoao2PS+87mKyw62k02k7kJ9ltbKe0fXTHrQmG6QZZflYuGI1VVG7sVpx4E1n7KBpNlPb8m78J+A==
- dependencies:
- "@babel/helper-module-transforms" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/helper-simple-access" "^7.14.5"
- babel-plugin-dynamic-import-node "^2.3.3"
-
-"@babel/plugin-transform-modules-systemjs@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.14.5.tgz#c75342ef8b30dcde4295d3401aae24e65638ed29"
- integrity sha512-mNMQdvBEE5DcMQaL5LbzXFMANrQjd2W7FPzg34Y4yEz7dBgdaC+9B84dSO+/1Wba98zoDbInctCDo4JGxz1VYA==
- dependencies:
- "@babel/helper-hoist-variables" "^7.14.5"
- "@babel/helper-module-transforms" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/helper-validator-identifier" "^7.14.5"
- babel-plugin-dynamic-import-node "^2.3.3"
-
-"@babel/plugin-transform-modules-umd@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz#fb662dfee697cce274a7cda525190a79096aa6e0"
- integrity sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==
- dependencies:
- "@babel/helper-module-transforms" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-named-capturing-groups-regex@^7.14.7":
- version "7.14.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.7.tgz#60c06892acf9df231e256c24464bfecb0908fd4e"
- integrity sha512-DTNOTaS7TkW97xsDMrp7nycUVh6sn/eq22VaxWfEdzuEbRsiaOU0pqU7DlyUGHVsbQbSghvjKRpEl+nUCKGQSg==
- dependencies:
- "@babel/helper-create-regexp-features-plugin" "^7.14.5"
-
-"@babel/plugin-transform-new-target@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz#31bdae8b925dc84076ebfcd2a9940143aed7dbf8"
- integrity sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-object-super@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz#d0b5faeac9e98597a161a9cf78c527ed934cdc45"
- integrity sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/helper-replace-supers" "^7.14.5"
-
-"@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz#49662e86a1f3ddccac6363a7dfb1ff0a158afeb3"
- integrity sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-property-literals@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz#0ddbaa1f83db3606f1cdf4846fa1dfb473458b34"
- integrity sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-react-constant-elements@^7.12.1":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.14.5.tgz#41790d856f7c5cec82d2bcf5d0e5064d682522ed"
- integrity sha512-NBqLEx1GxllIOXJInJAQbrnwwYJsV3WaMHIcOwD8rhYS0AabTWn7kHdHgPgu5RmHLU0q4DMxhAMu8ue/KampgQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-react-display-name@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.14.5.tgz#baa92d15c4570411301a85a74c13534873885b65"
- integrity sha512-07aqY1ChoPgIxsuDviptRpVkWCSbXWmzQqcgy65C6YSFOfPFvb/DX3bBRHh7pCd/PMEEYHYWUTSVkCbkVainYQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-react-jsx-development@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.14.5.tgz#1a6c73e2f7ed2c42eebc3d2ad60b0c7494fcb9af"
- integrity sha512-rdwG/9jC6QybWxVe2UVOa7q6cnTpw8JRRHOxntG/h6g/guAOe6AhtQHJuJh5FwmnXIT1bdm5vC2/5huV8ZOorQ==
- dependencies:
- "@babel/plugin-transform-react-jsx" "^7.14.5"
-
-"@babel/plugin-transform-react-jsx@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.14.5.tgz#39749f0ee1efd8a1bd729152cf5f78f1d247a44a"
- integrity sha512-7RylxNeDnxc1OleDm0F5Q/BSL+whYRbOAR+bwgCxIr0L32v7UFh/pz1DLMZideAUxKT6eMoS2zQH6fyODLEi8Q==
- dependencies:
- "@babel/helper-annotate-as-pure" "^7.14.5"
- "@babel/helper-module-imports" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/plugin-syntax-jsx" "^7.14.5"
- "@babel/types" "^7.14.5"
-
-"@babel/plugin-transform-react-pure-annotations@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.14.5.tgz#18de612b84021e3a9802cbc212c9d9f46d0d11fc"
- integrity sha512-3X4HpBJimNxW4rhUy/SONPyNQHp5YRr0HhJdT2OH1BRp0of7u3Dkirc7x9FRJMKMqTBI079VZ1hzv7Ouuz///g==
- dependencies:
- "@babel/helper-annotate-as-pure" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-regenerator@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz#9676fd5707ed28f522727c5b3c0aa8544440b04f"
- integrity sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==
- dependencies:
- regenerator-transform "^0.14.2"
-
-"@babel/plugin-transform-reserved-words@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz#c44589b661cfdbef8d4300dcc7469dffa92f8304"
- integrity sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-runtime@^7.9.0":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.14.5.tgz#30491dad49c6059f8f8fa5ee8896a0089e987523"
- integrity sha512-fPMBhh1AV8ZyneiCIA+wYYUH1arzlXR1UMcApjvchDhfKxhy2r2lReJv8uHEyihi4IFIGlr1Pdx7S5fkESDQsg==
- dependencies:
- "@babel/helper-module-imports" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
- babel-plugin-polyfill-corejs2 "^0.2.2"
- babel-plugin-polyfill-corejs3 "^0.2.2"
- babel-plugin-polyfill-regenerator "^0.2.2"
- semver "^6.3.0"
-
-"@babel/plugin-transform-shorthand-properties@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz#97f13855f1409338d8cadcbaca670ad79e091a58"
- integrity sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-spread@^7.14.6":
- version "7.14.6"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz#6bd40e57fe7de94aa904851963b5616652f73144"
- integrity sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5"
-
-"@babel/plugin-transform-sticky-regex@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz#5b617542675e8b7761294381f3c28c633f40aeb9"
- integrity sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-template-literals@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz#a5f2bc233937d8453885dc736bdd8d9ffabf3d93"
- integrity sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-typeof-symbol@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz#39af2739e989a2bd291bf6b53f16981423d457d4"
- integrity sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-typescript@^7.14.5":
- version "7.14.6"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.14.6.tgz#6e9c2d98da2507ebe0a883b100cde3c7279df36c"
- integrity sha512-XlTdBq7Awr4FYIzqhmYY80WN0V0azF74DMPyFqVHBvf81ZUgc4X7ZOpx6O8eLDK6iM5cCQzeyJw0ynTaefixRA==
- dependencies:
- "@babel/helper-create-class-features-plugin" "^7.14.6"
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/plugin-syntax-typescript" "^7.14.5"
-
-"@babel/plugin-transform-unicode-escapes@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz#9d4bd2a681e3c5d7acf4f57fa9e51175d91d0c6b"
- integrity sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-unicode-regex@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz#4cd09b6c8425dd81255c7ceb3fb1836e7414382e"
- integrity sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==
- dependencies:
- "@babel/helper-create-regexp-features-plugin" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.9.0":
- version "7.14.7"
- resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.7.tgz#5c70b22d4c2d893b03d8c886a5c17422502b932a"
- integrity sha512-itOGqCKLsSUl0Y+1nSfhbuuOlTs0MJk2Iv7iSH+XT/mR8U1zRLO7NjWlYXB47yhK4J/7j+HYty/EhFZDYKa/VA==
- dependencies:
- "@babel/compat-data" "^7.14.7"
- "@babel/helper-compilation-targets" "^7.14.5"
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/helper-validator-option" "^7.14.5"
- "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.14.5"
- "@babel/plugin-proposal-async-generator-functions" "^7.14.7"
- "@babel/plugin-proposal-class-properties" "^7.14.5"
- "@babel/plugin-proposal-class-static-block" "^7.14.5"
- "@babel/plugin-proposal-dynamic-import" "^7.14.5"
- "@babel/plugin-proposal-export-namespace-from" "^7.14.5"
- "@babel/plugin-proposal-json-strings" "^7.14.5"
- "@babel/plugin-proposal-logical-assignment-operators" "^7.14.5"
- "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5"
- "@babel/plugin-proposal-numeric-separator" "^7.14.5"
- "@babel/plugin-proposal-object-rest-spread" "^7.14.7"
- "@babel/plugin-proposal-optional-catch-binding" "^7.14.5"
- "@babel/plugin-proposal-optional-chaining" "^7.14.5"
- "@babel/plugin-proposal-private-methods" "^7.14.5"
- "@babel/plugin-proposal-private-property-in-object" "^7.14.5"
- "@babel/plugin-proposal-unicode-property-regex" "^7.14.5"
- "@babel/plugin-syntax-async-generators" "^7.8.4"
- "@babel/plugin-syntax-class-properties" "^7.12.13"
- "@babel/plugin-syntax-class-static-block" "^7.14.5"
- "@babel/plugin-syntax-dynamic-import" "^7.8.3"
- "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
- "@babel/plugin-syntax-json-strings" "^7.8.3"
- "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
- "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
- "@babel/plugin-syntax-numeric-separator" "^7.10.4"
- "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
- "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
- "@babel/plugin-syntax-optional-chaining" "^7.8.3"
- "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
- "@babel/plugin-syntax-top-level-await" "^7.14.5"
- "@babel/plugin-transform-arrow-functions" "^7.14.5"
- "@babel/plugin-transform-async-to-generator" "^7.14.5"
- "@babel/plugin-transform-block-scoped-functions" "^7.14.5"
- "@babel/plugin-transform-block-scoping" "^7.14.5"
- "@babel/plugin-transform-classes" "^7.14.5"
- "@babel/plugin-transform-computed-properties" "^7.14.5"
- "@babel/plugin-transform-destructuring" "^7.14.7"
- "@babel/plugin-transform-dotall-regex" "^7.14.5"
- "@babel/plugin-transform-duplicate-keys" "^7.14.5"
- "@babel/plugin-transform-exponentiation-operator" "^7.14.5"
- "@babel/plugin-transform-for-of" "^7.14.5"
- "@babel/plugin-transform-function-name" "^7.14.5"
- "@babel/plugin-transform-literals" "^7.14.5"
- "@babel/plugin-transform-member-expression-literals" "^7.14.5"
- "@babel/plugin-transform-modules-amd" "^7.14.5"
- "@babel/plugin-transform-modules-commonjs" "^7.14.5"
- "@babel/plugin-transform-modules-systemjs" "^7.14.5"
- "@babel/plugin-transform-modules-umd" "^7.14.5"
- "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.7"
- "@babel/plugin-transform-new-target" "^7.14.5"
- "@babel/plugin-transform-object-super" "^7.14.5"
- "@babel/plugin-transform-parameters" "^7.14.5"
- "@babel/plugin-transform-property-literals" "^7.14.5"
- "@babel/plugin-transform-regenerator" "^7.14.5"
- "@babel/plugin-transform-reserved-words" "^7.14.5"
- "@babel/plugin-transform-shorthand-properties" "^7.14.5"
- "@babel/plugin-transform-spread" "^7.14.6"
- "@babel/plugin-transform-sticky-regex" "^7.14.5"
- "@babel/plugin-transform-template-literals" "^7.14.5"
- "@babel/plugin-transform-typeof-symbol" "^7.14.5"
- "@babel/plugin-transform-unicode-escapes" "^7.14.5"
- "@babel/plugin-transform-unicode-regex" "^7.14.5"
- "@babel/preset-modules" "^0.1.4"
- "@babel/types" "^7.14.5"
- babel-plugin-polyfill-corejs2 "^0.2.2"
- babel-plugin-polyfill-corejs3 "^0.2.2"
- babel-plugin-polyfill-regenerator "^0.2.2"
- core-js-compat "^3.15.0"
- semver "^6.3.0"
-
-"@babel/preset-modules@^0.1.4":
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e"
- integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
- "@babel/plugin-proposal-unicode-property-regex" "^7.4.4"
- "@babel/plugin-transform-dotall-regex" "^7.4.4"
- "@babel/types" "^7.4.4"
- esutils "^2.0.2"
-
-"@babel/preset-react@^7.12.5", "@babel/preset-react@^7.9.4":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.14.5.tgz#0fbb769513f899c2c56f3a882fa79673c2d4ab3c"
- integrity sha512-XFxBkjyObLvBaAvkx1Ie95Iaq4S/GUEIrejyrntQ/VCMKUYvKLoyKxOBzJ2kjA3b6rC9/KL6KXfDC2GqvLiNqQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/helper-validator-option" "^7.14.5"
- "@babel/plugin-transform-react-display-name" "^7.14.5"
- "@babel/plugin-transform-react-jsx" "^7.14.5"
- "@babel/plugin-transform-react-jsx-development" "^7.14.5"
- "@babel/plugin-transform-react-pure-annotations" "^7.14.5"
-
-"@babel/preset-typescript@^7.9.0":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.14.5.tgz#aa98de119cf9852b79511f19e7f44a2d379bcce0"
- integrity sha512-u4zO6CdbRKbS9TypMqrlGH7sd2TAJppZwn3c/ZRLeO/wGsbddxgbPDUZVNrie3JWYLQ9vpineKlsrWFvO6Pwkw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/helper-validator-option" "^7.14.5"
- "@babel/plugin-transform-typescript" "^7.14.5"
-
-"@babel/runtime-corejs3@^7.10.4":
- version "7.14.7"
- resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.14.7.tgz#0ef292bbce40ca00f874c9724ef175a12476465c"
- integrity sha512-Wvzcw4mBYbTagyBVZpAJWI06auSIj033T/yNE0Zn1xcup83MieCddZA7ls3kme17L4NOGBrQ09Q+nKB41RLWBA==
- dependencies:
- core-js-pure "^3.15.0"
- regenerator-runtime "^0.13.4"
-
-"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
- version "7.14.6"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.6.tgz#535203bc0892efc7dec60bdc27b2ecf6e409062d"
- integrity sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==
- dependencies:
- regenerator-runtime "^0.13.4"
-
-"@babel/template@^7.12.7", "@babel/template@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4"
- integrity sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==
- dependencies:
- "@babel/code-frame" "^7.14.5"
- "@babel/parser" "^7.14.5"
- "@babel/types" "^7.14.5"
-
-"@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.5", "@babel/traverse@^7.9.0":
- version "7.14.7"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.7.tgz#64007c9774cfdc3abd23b0780bc18a3ce3631753"
- integrity sha512-9vDr5NzHu27wgwejuKL7kIOm4bwEtaPQ4Z6cpCmjSuaRqpH/7xc4qcGEscwMqlkwgcXl6MvqoAjZkQ24uSdIZQ==
- dependencies:
- "@babel/code-frame" "^7.14.5"
- "@babel/generator" "^7.14.5"
- "@babel/helper-function-name" "^7.14.5"
- "@babel/helper-hoist-variables" "^7.14.5"
- "@babel/helper-split-export-declaration" "^7.14.5"
- "@babel/parser" "^7.14.7"
- "@babel/types" "^7.14.5"
- debug "^4.1.0"
- globals "^11.1.0"
-
-"@babel/types@^7.12.6", "@babel/types@^7.12.7", "@babel/types@^7.14.5", "@babel/types@^7.4.4":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.5.tgz#3bb997ba829a2104cedb20689c4a5b8121d383ff"
- integrity sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==
- dependencies:
- "@babel/helper-validator-identifier" "^7.14.5"
- to-fast-properties "^2.0.0"
-
-"@csstools/convert-colors@^1.4.0":
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
- integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==
-
-"@docsearch/css@^1.0.0-alpha.28":
- version "1.0.0-alpha.28"
- resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-1.0.0-alpha.28.tgz#c8a2cd8c1bb3a6855c51892e9dbdab5d42fe6e23"
- integrity sha512-1AhRzVdAkrWwhaxTX6/R7SnFHz8yLz1W8I/AldlTrfbNvZs9INk1FZiEFTJdgHaP68nhgQNWSGlQiDiI3y2RYg==
-
-"@docsearch/react@^1.0.0-alpha.27":
- version "1.0.0-alpha.28"
- resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-1.0.0-alpha.28.tgz#4f039ed79f8b3332b19a57677b219aebc5010e9d"
- integrity sha512-XjJOnCBXn+UZmtuDmgzlVIHnnvh6yHVwG4aFq8AXN6xJEIX3f180FvGaowFWAxgdtHplJxFGux0Xx4piHqBzIw==
- dependencies:
- "@docsearch/css" "^1.0.0-alpha.28"
- "@francoischalifour/autocomplete-core" "^1.0.0-alpha.28"
- "@francoischalifour/autocomplete-preset-algolia" "^1.0.0-alpha.28"
- algoliasearch "^4.0.0"
-
-"@docusaurus/core@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.0.0-alpha.65.tgz#e99f19d602c6505febe3de68029fb7ca1225df4d"
- integrity sha512-9kfgPugosRq5byuBC/tz3ZShPFT8xh8t08r5tsx8QujfH2ZpDXSQpLF0x/isbCY1O2NQsRZZCKGXQf5dE6NZfQ==
- dependencies:
- "@babel/core" "^7.9.0"
- "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.1"
- "@babel/plugin-proposal-optional-chaining" "^7.10.3"
- "@babel/plugin-syntax-dynamic-import" "^7.8.3"
- "@babel/plugin-transform-runtime" "^7.9.0"
- "@babel/preset-env" "^7.9.0"
- "@babel/preset-react" "^7.9.4"
- "@babel/preset-typescript" "^7.9.0"
- "@babel/runtime" "^7.9.2"
- "@babel/runtime-corejs3" "^7.10.4"
- "@docusaurus/types" "2.0.0-alpha.65"
- "@docusaurus/utils" "2.0.0-alpha.65"
- "@docusaurus/utils-validation" "2.0.0-alpha.65"
- "@endiliey/static-site-generator-webpack-plugin" "^4.0.0"
- "@hapi/joi" "^17.1.1"
- "@svgr/webpack" "^5.4.0"
- babel-loader "^8.1.0"
- babel-plugin-dynamic-import-node "^2.3.0"
- boxen "^4.2.0"
- cache-loader "^4.1.0"
- chalk "^3.0.0"
- chokidar "^3.3.0"
- commander "^4.0.1"
- copy-webpack-plugin "^6.0.3"
- core-js "^2.6.5"
- css-loader "^3.4.2"
- del "^5.1.0"
- detect-port "^1.3.0"
- eta "^1.1.1"
- express "^4.17.1"
- file-loader "^6.0.0"
- fs-extra "^8.1.0"
- globby "^10.0.1"
- html-minifier-terser "^5.0.5"
- html-tags "^3.1.0"
- html-webpack-plugin "^4.0.4"
- import-fresh "^3.2.1"
- inquirer "^7.2.0"
- is-root "^2.1.0"
- leven "^3.1.0"
- lodash "^4.5.2"
- lodash.flatmap "^4.5.0"
- lodash.has "^4.5.2"
- lodash.isplainobject "^4.0.6"
- lodash.isstring "^4.0.1"
- mini-css-extract-plugin "^0.8.0"
- nprogress "^0.2.0"
- null-loader "^3.0.0"
- optimize-css-assets-webpack-plugin "^5.0.3"
- pnp-webpack-plugin "^1.6.4"
- postcss-loader "^3.0.0"
- postcss-preset-env "^6.7.0"
- react-dev-utils "^10.2.1"
- react-helmet "^6.0.0-beta"
- react-loadable "^5.5.0"
- react-loadable-ssr-addon "^0.3.0"
- react-router "^5.1.2"
- react-router-config "^5.1.1"
- react-router-dom "^5.1.2"
- resolve-pathname "^3.0.0"
- semver "^6.3.0"
- serve-handler "^6.1.3"
- shelljs "^0.8.4"
- std-env "^2.2.1"
- terser-webpack-plugin "^4.1.0"
- update-notifier "^4.1.0"
- url-loader "^4.1.0"
- wait-file "^1.0.5"
- webpack "^4.44.1"
- webpack-bundle-analyzer "^3.6.1"
- webpack-dev-server "^3.11.0"
- webpack-merge "^4.2.2"
- webpackbar "^4.0.0"
-
-"@docusaurus/mdx-loader@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-alpha.65.tgz#389133ea0bc937be935b01e0002cde7ad16429db"
- integrity sha512-E+8f9dNML4CMDeLVcJi7qfJisPGJY45iGGkjGTdaxPPzP6xEnqA/Y/ghnKMiBY/GYCxKqteQFg52ZDAGNm4Bkg==
- dependencies:
- "@babel/parser" "^7.9.4"
- "@babel/traverse" "^7.9.0"
- "@docusaurus/core" "2.0.0-alpha.65"
- "@docusaurus/utils" "2.0.0-alpha.65"
- "@mdx-js/mdx" "^1.5.8"
- "@mdx-js/react" "^1.5.8"
- escape-html "^1.0.3"
- file-loader "^6.0.0"
- fs-extra "^8.1.0"
- github-slugger "^1.3.0"
- gray-matter "^4.0.2"
- loader-utils "^1.2.3"
- mdast-util-to-string "^1.1.0"
- remark-emoji "^2.1.0"
- stringify-object "^3.3.0"
- unist-util-visit "^2.0.2"
- url-loader "^4.1.0"
-
-"@docusaurus/plugin-content-blog@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-alpha.65.tgz#00478b9862f6524d8f2d504213b9b45cb0ec70dc"
- integrity sha512-cVt6bmGxsSW/t8DXoS79j1Y/ZwK9KQQFBLT6PK90IK+0Zfa1fRl8T6+aAYEzdADVwoVNIt3976OJ2Z5XT4Xyag==
- dependencies:
- "@docusaurus/core" "2.0.0-alpha.65"
- "@docusaurus/mdx-loader" "2.0.0-alpha.65"
- "@docusaurus/types" "2.0.0-alpha.65"
- "@docusaurus/utils" "2.0.0-alpha.65"
- "@docusaurus/utils-validation" "2.0.0-alpha.65"
- "@hapi/joi" "^17.1.1"
- chalk "^3.0.0"
- feed "^4.1.0"
- fs-extra "^8.1.0"
- globby "^10.0.1"
- loader-utils "^1.2.3"
- lodash.kebabcase "^4.1.1"
- reading-time "^1.2.0"
- remark-admonitions "^1.2.1"
- webpack "^4.44.1"
-
-"@docusaurus/plugin-content-docs@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-alpha.65.tgz#c384a91f02c050e2c4e8d96591ff187792287d94"
- integrity sha512-AMROMNE8p7CPw+szGyBbhHsmCCL5nbm0ljRIEZ/XkDlSXx8s/CDdu9LEbGIYLvoGDjUjnq9Mmi3hNLBYwU2Kow==
- dependencies:
- "@docusaurus/core" "2.0.0-alpha.65"
- "@docusaurus/mdx-loader" "2.0.0-alpha.65"
- "@docusaurus/types" "2.0.0-alpha.65"
- "@docusaurus/utils" "2.0.0-alpha.65"
- "@docusaurus/utils-validation" "2.0.0-alpha.65"
- "@hapi/joi" "17.1.1"
- chalk "^3.0.0"
- execa "^3.4.0"
- fs-extra "^8.1.0"
- globby "^10.0.1"
- import-fresh "^3.2.1"
- loader-utils "^1.2.3"
- lodash "^4.17.19"
- lodash.flatmap "^4.5.0"
- lodash.groupby "^4.6.0"
- lodash.pick "^4.4.0"
- lodash.pickby "^4.6.0"
- lodash.sortby "^4.6.0"
- remark-admonitions "^1.2.1"
- shelljs "^0.8.4"
- utility-types "^3.10.0"
- webpack "^4.44.1"
-
-"@docusaurus/plugin-content-pages@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-alpha.65.tgz#d266f80485c4355564ce4864ecf84b112e0dba2f"
- integrity sha512-dpdzrGuq2xSIP2SkOtEpQggP+f0WOZcVI+WNON4YpfwftBYoLIf4/S6ISBFdld+AjA/VCJ/nc46/ord4oC6rOQ==
- dependencies:
- "@docusaurus/core" "2.0.0-alpha.65"
- "@docusaurus/mdx-loader" "2.0.0-alpha.65"
- "@docusaurus/types" "2.0.0-alpha.65"
- "@docusaurus/utils" "2.0.0-alpha.65"
- "@docusaurus/utils-validation" "2.0.0-alpha.65"
- "@hapi/joi" "17.1.1"
- globby "^10.0.1"
- loader-utils "^1.2.3"
- minimatch "^3.0.4"
- remark-admonitions "^1.2.1"
- slash "^3.0.0"
- webpack "^4.44.1"
-
-"@docusaurus/plugin-debug@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-alpha.65.tgz#6c39be2be7d39a5c5e09a9213885d49fdc59451c"
- integrity sha512-+xzDbr1N8pC/LwJyKZDYCZB4VbFnbQwtJ62pRuyt5MSofKDBkXhRJ2r8piud6dpUI4SpcgkL4IbxRXukRCDtkQ==
- dependencies:
- "@docusaurus/core" "2.0.0-alpha.65"
- "@docusaurus/types" "2.0.0-alpha.65"
- "@docusaurus/utils" "2.0.0-alpha.65"
- react-json-view "^1.19.1"
-
-"@docusaurus/plugin-google-analytics@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-alpha.65.tgz#ba39a905cdb254d08804dace835f45f5cfc3a5cd"
- integrity sha512-LK/21sKJlR9Al7upHcxXFT4iMAksuTMYQIC+Xhdte79R1aNZrBhXypWNO0OTbz1hRIK0AAVmpwAiFC5c3RJZgQ==
- dependencies:
- "@docusaurus/core" "2.0.0-alpha.65"
-
-"@docusaurus/plugin-google-gtag@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-alpha.65.tgz#91ca78b23d7d752a2998a20b1773574616ee55b2"
- integrity sha512-tAtqfvmnr1X3UoG1Wh88K1ZIrvJlH6PEVptNgE8QYRDe/Wsykp1mpAm1ppS58kfC1/ofrQ1mNwZplceI5hbukw==
- dependencies:
- "@docusaurus/core" "2.0.0-alpha.65"
-
-"@docusaurus/plugin-sitemap@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-alpha.65.tgz#b214b6e2501f82acfd7c13bd26b8935b3d9b78c0"
- integrity sha512-h9adEzq3V8vHQxCM5/cM/rskN1G4blH/NHTo1Ng8HqMK6VO8CVX0WgBL9pxpmOo3dVFK9dAB3Pf+zNkJY18Rfw==
- dependencies:
- "@docusaurus/core" "2.0.0-alpha.65"
- "@docusaurus/types" "2.0.0-alpha.65"
- "@hapi/joi" "17.1.1"
- fs-extra "^8.1.0"
- sitemap "^3.2.2"
-
-"@docusaurus/preset-classic@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.0.0-alpha.65.tgz#6021fce4e0db703961096c577551e6b05e9b6cbc"
- integrity sha512-0wJEB1BvS0Wx0XuWwm+XNfVdVUcZ4Va2nXmK45ZvSYx+DbZ73wL/K4ahIp7R6A5JYv7kPRz6tlm0vusRMmKUVA==
- dependencies:
- "@docusaurus/core" "2.0.0-alpha.65"
- "@docusaurus/plugin-content-blog" "2.0.0-alpha.65"
- "@docusaurus/plugin-content-docs" "2.0.0-alpha.65"
- "@docusaurus/plugin-content-pages" "2.0.0-alpha.65"
- "@docusaurus/plugin-debug" "2.0.0-alpha.65"
- "@docusaurus/plugin-google-analytics" "2.0.0-alpha.65"
- "@docusaurus/plugin-google-gtag" "2.0.0-alpha.65"
- "@docusaurus/plugin-sitemap" "2.0.0-alpha.65"
- "@docusaurus/theme-classic" "2.0.0-alpha.65"
- "@docusaurus/theme-search-algolia" "2.0.0-alpha.65"
-
-"@docusaurus/theme-classic@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.0.0-alpha.65.tgz#8db2a658b12fd74dae63627d0ecb00a76d4df403"
- integrity sha512-i8Uu1bkah7qEbJ7JhNU8TkylkFIh66Tzv3yP8sl9Zcmo3K4/9SAuT1Ux7gb0hd7xsrJy4NalhxvMP0oE1ElEDw==
- dependencies:
- "@docusaurus/core" "2.0.0-alpha.65"
- "@docusaurus/plugin-content-blog" "2.0.0-alpha.65"
- "@docusaurus/plugin-content-docs" "2.0.0-alpha.65"
- "@docusaurus/plugin-content-pages" "2.0.0-alpha.65"
- "@docusaurus/types" "2.0.0-alpha.65"
- "@docusaurus/utils-validation" "2.0.0-alpha.65"
- "@hapi/joi" "^17.1.1"
- "@mdx-js/mdx" "^1.5.8"
- "@mdx-js/react" "^1.5.8"
- "@types/react-toggle" "^4.0.2"
- clsx "^1.1.1"
- copy-text-to-clipboard "^2.2.0"
- infima "0.2.0-alpha.13"
- lodash "^4.17.19"
- parse-numeric-range "^0.0.2"
- prism-react-renderer "^1.1.0"
- prismjs "^1.20.0"
- prop-types "^15.7.2"
- react-router-dom "^5.1.2"
- react-toggle "^4.1.1"
- use-onclickoutside "^0.3.1"
-
-"@docusaurus/theme-search-algolia@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-alpha.65.tgz#083d3ead1338cc3a501e80a64ac5495fdacafdb9"
- integrity sha512-Ois8F9Y5S4eyk2fT7GGFMnLZdtsWDuQi9hAntiMG7ClqcXE3Z3J126RYXqsZV0/Lr3Qaedwe7mED6r0C7Uc+Lg==
- dependencies:
- "@docsearch/react" "^1.0.0-alpha.27"
- "@docusaurus/core" "2.0.0-alpha.65"
- "@docusaurus/utils" "2.0.0-alpha.65"
- "@hapi/joi" "^17.1.1"
- algoliasearch "^4.0.0"
- algoliasearch-helper "^3.1.1"
- clsx "^1.1.1"
- eta "^1.1.1"
- lodash "^4.17.19"
-
-"@docusaurus/types@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.0.0-alpha.65.tgz#e47104e7198ee3708d4f0d82c9fcb1aa2c118ab5"
- integrity sha512-a4pcWUfS4I4B6O9zi2yJ7JJvjo8lHqwC6+EdwW/XiJ9B40CkD9LGKYGR2EKIUFM2qrRCgSBrDukIK1oAROrkSQ==
- dependencies:
- "@types/webpack" "^4.41.0"
- commander "^4.0.1"
- querystring "0.2.0"
- webpack-merge "^4.2.2"
-
-"@docusaurus/utils-validation@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.0.0-alpha.65.tgz#3d2b5b365938cacd35c224f4a661802978b5d6ff"
- integrity sha512-BcWQx8zb+bbQEDzzUerl31Lehuv4axdoty2vSDqt4rhKiAn1lh/XyWYxxPN98r+roailHsl3WRYK0L+KJjTcKA==
- dependencies:
- "@docusaurus/utils" "2.0.0-alpha.65"
- "@hapi/joi" "17.1.1"
- chalk "^3.0.0"
-
-"@docusaurus/utils@2.0.0-alpha.65":
- version "2.0.0-alpha.65"
- resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.0.0-alpha.65.tgz#2dfc82da1be31d9632cca85d3b70628ef17dc149"
- integrity sha512-Fz0rF/eMuzgMOJITF3R62H7fC2fDfTNtJ9wq5DBR050647OMEJnimKSilS1Rsckd7c72mfBdhg3Hdb9rrSrk8Q==
- dependencies:
- escape-string-regexp "^2.0.0"
- fs-extra "^8.1.0"
- gray-matter "^4.0.2"
- lodash.camelcase "^4.3.0"
- lodash.kebabcase "^4.1.1"
- resolve-pathname "^3.0.0"
-
-"@endiliey/static-site-generator-webpack-plugin@^4.0.0":
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/@endiliey/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.0.tgz#94bfe58fd83aeda355de797fcb5112adaca3a6b1"
- integrity sha512-3MBqYCs30qk1OBRC697NqhGouYbs71D1B8hrk/AFJC6GwF2QaJOQZtA1JYAaGSe650sZ8r5ppRTtCRXepDWlng==
- dependencies:
- bluebird "^3.7.1"
- cheerio "^0.22.0"
- eval "^0.1.4"
- url "^0.11.0"
- webpack-sources "^1.4.3"
-
-"@francoischalifour/autocomplete-core@^1.0.0-alpha.28":
- version "1.0.0-alpha.28"
- resolved "https://registry.yarnpkg.com/@francoischalifour/autocomplete-core/-/autocomplete-core-1.0.0-alpha.28.tgz#6b9d8491288e77f831e9b345d461623b0d3f5005"
- integrity sha512-rL9x+72btViw+9icfBKUJjZj87FgjFrD2esuTUqtj4RAX3s4AuVZiN8XEsfjQBSc6qJk31cxlvqZHC/BIyYXgg==
-
-"@francoischalifour/autocomplete-preset-algolia@^1.0.0-alpha.28":
- version "1.0.0-alpha.28"
- resolved "https://registry.yarnpkg.com/@francoischalifour/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.0.0-alpha.28.tgz#a5ad7996f42e43e4acbb4e0010d663746d0e9997"
- integrity sha512-bprfNmYt1opFUFEtD2XfY/kEsm13bzHQgU80uMjhuK0DJ914IjolT1GytpkdM6tJ4MBvyiJPP+bTtWO+BZ7c7w==
-
-"@hapi/address@2.x.x":
- version "2.1.4"
- resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
- integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==
-
-"@hapi/address@^4.0.1":
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/@hapi/address/-/address-4.1.0.tgz#d60c5c0d930e77456fdcde2598e77302e2955e1d"
- integrity sha512-SkszZf13HVgGmChdHo/PxchnSaCJ6cetVqLzyciudzZRT0jcOouIF/Q93mgjw8cce+D+4F4C1Z/WrfFN+O3VHQ==
- dependencies:
- "@hapi/hoek" "^9.0.0"
-
-"@hapi/bourne@1.x.x":
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a"
- integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==
-
-"@hapi/formula@^2.0.0":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/@hapi/formula/-/formula-2.0.0.tgz#edade0619ed58c8e4f164f233cda70211e787128"
- integrity sha512-V87P8fv7PI0LH7LiVi8Lkf3x+KCO7pQozXRssAHNXXL9L1K+uyu4XypLXwxqVDKgyQai6qj3/KteNlrqDx4W5A==
-
-"@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.0":
- version "8.5.1"
- resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06"
- integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==
-
-"@hapi/hoek@^9.0.0":
- version "9.2.0"
- resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.0.tgz#f3933a44e365864f4dad5db94158106d511e8131"
- integrity sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug==
-
-"@hapi/joi@17.1.1", "@hapi/joi@^17.1.1":
- version "17.1.1"
- resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-17.1.1.tgz#9cc8d7e2c2213d1e46708c6260184b447c661350"
- integrity sha512-p4DKeZAoeZW4g3u7ZeRo+vCDuSDgSvtsB/NpfjXEHTUjSeINAi/RrVOWiVQ1isaoLzMvFEhe8n5065mQq1AdQg==
- dependencies:
- "@hapi/address" "^4.0.1"
- "@hapi/formula" "^2.0.0"
- "@hapi/hoek" "^9.0.0"
- "@hapi/pinpoint" "^2.0.0"
- "@hapi/topo" "^5.0.0"
-
-"@hapi/joi@^15.1.0":
- version "15.1.1"
- resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7"
- integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==
- dependencies:
- "@hapi/address" "2.x.x"
- "@hapi/bourne" "1.x.x"
- "@hapi/hoek" "8.x.x"
- "@hapi/topo" "3.x.x"
-
-"@hapi/pinpoint@^2.0.0":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/@hapi/pinpoint/-/pinpoint-2.0.0.tgz#805b40d4dbec04fc116a73089494e00f073de8df"
- integrity sha512-vzXR5MY7n4XeIvLpfl3HtE3coZYO4raKXW766R6DZw/6aLqR26iuZ109K7a0NtF2Db0jxqh7xz2AxkUwpUFybw==
-
-"@hapi/topo@3.x.x":
- version "3.1.6"
- resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.6.tgz#68d935fa3eae7fdd5ab0d7f953f3205d8b2bfc29"
- integrity sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==
- dependencies:
- "@hapi/hoek" "^8.3.0"
-
-"@hapi/topo@^5.0.0":
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012"
- integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==
- dependencies:
- "@hapi/hoek" "^9.0.0"
-
-"@mdx-js/mdx@^1.5.8":
- version "1.6.22"
- resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-1.6.22.tgz#8a723157bf90e78f17dc0f27995398e6c731f1ba"
- integrity sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==
- dependencies:
- "@babel/core" "7.12.9"
- "@babel/plugin-syntax-jsx" "7.12.1"
- "@babel/plugin-syntax-object-rest-spread" "7.8.3"
- "@mdx-js/util" "1.6.22"
- babel-plugin-apply-mdx-type-prop "1.6.22"
- babel-plugin-extract-import-names "1.6.22"
- camelcase-css "2.0.1"
- detab "2.0.4"
- hast-util-raw "6.0.1"
- lodash.uniq "4.5.0"
- mdast-util-to-hast "10.0.1"
- remark-footnotes "2.0.0"
- remark-mdx "1.6.22"
- remark-parse "8.0.3"
- remark-squeeze-paragraphs "4.0.0"
- style-to-object "0.3.0"
- unified "9.2.0"
- unist-builder "2.0.3"
- unist-util-visit "2.0.3"
-
-"@mdx-js/react@^1.5.8":
- version "1.6.22"
- resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-1.6.22.tgz#ae09b4744fddc74714ee9f9d6f17a66e77c43573"
- integrity sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==
-
-"@mdx-js/util@1.6.22":
- version "1.6.22"
- resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b"
- integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==
-
-"@mrmlnc/readdir-enhanced@^2.2.1":
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
- integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==
- dependencies:
- call-me-maybe "^1.0.1"
- glob-to-regexp "^0.3.0"
-
-"@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.stat@^1.1.2":
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
- integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
-
-"@nodelib/fs.walk@^1.2.3":
- version "1.2.7"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz#94c23db18ee4653e129abd26fb06f870ac9e1ee2"
- integrity sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==
- dependencies:
- "@nodelib/fs.scandir" "2.1.5"
- fastq "^1.6.0"
-
-"@npmcli/move-file@^1.0.1":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674"
- integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==
- dependencies:
- mkdirp "^1.0.4"
- rimraf "^3.0.2"
-
-"@sindresorhus/is@^0.14.0":
- version "0.14.0"
- resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
- integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
-
-"@svgr/babel-plugin-add-jsx-attribute@^5.4.0":
- version "5.4.0"
- resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz#81ef61947bb268eb9d50523446f9c638fb355906"
- integrity sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==
-
-"@svgr/babel-plugin-remove-jsx-attribute@^5.4.0":
- version "5.4.0"
- resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz#6b2c770c95c874654fd5e1d5ef475b78a0a962ef"
- integrity sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==
-
-"@svgr/babel-plugin-remove-jsx-empty-expression@^5.0.1":
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz#25621a8915ed7ad70da6cea3d0a6dbc2ea933efd"
- integrity sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==
-
-"@svgr/babel-plugin-replace-jsx-attribute-value@^5.0.1":
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz#0b221fc57f9fcd10e91fe219e2cd0dd03145a897"
- integrity sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==
-
-"@svgr/babel-plugin-svg-dynamic-title@^5.4.0":
- version "5.4.0"
- resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz#139b546dd0c3186b6e5db4fefc26cb0baea729d7"
- integrity sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==
-
-"@svgr/babel-plugin-svg-em-dimensions@^5.4.0":
- version "5.4.0"
- resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz#6543f69526632a133ce5cabab965deeaea2234a0"
- integrity sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==
-
-"@svgr/babel-plugin-transform-react-native-svg@^5.4.0":
- version "5.4.0"
- resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz#00bf9a7a73f1cad3948cdab1f8dfb774750f8c80"
- integrity sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==
-
-"@svgr/babel-plugin-transform-svg-component@^5.5.0":
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz#583a5e2a193e214da2f3afeb0b9e8d3250126b4a"
- integrity sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==
-
-"@svgr/babel-preset@^5.5.0":
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-5.5.0.tgz#8af54f3e0a8add7b1e2b0fcd5a882c55393df327"
- integrity sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==
- dependencies:
- "@svgr/babel-plugin-add-jsx-attribute" "^5.4.0"
- "@svgr/babel-plugin-remove-jsx-attribute" "^5.4.0"
- "@svgr/babel-plugin-remove-jsx-empty-expression" "^5.0.1"
- "@svgr/babel-plugin-replace-jsx-attribute-value" "^5.0.1"
- "@svgr/babel-plugin-svg-dynamic-title" "^5.4.0"
- "@svgr/babel-plugin-svg-em-dimensions" "^5.4.0"
- "@svgr/babel-plugin-transform-react-native-svg" "^5.4.0"
- "@svgr/babel-plugin-transform-svg-component" "^5.5.0"
-
-"@svgr/core@^5.5.0":
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/@svgr/core/-/core-5.5.0.tgz#82e826b8715d71083120fe8f2492ec7d7874a579"
- integrity sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==
- dependencies:
- "@svgr/plugin-jsx" "^5.5.0"
- camelcase "^6.2.0"
- cosmiconfig "^7.0.0"
-
-"@svgr/hast-util-to-babel-ast@^5.5.0":
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz#5ee52a9c2533f73e63f8f22b779f93cd432a5461"
- integrity sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==
- dependencies:
- "@babel/types" "^7.12.6"
-
-"@svgr/plugin-jsx@^5.5.0":
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz#1aa8cd798a1db7173ac043466d7b52236b369000"
- integrity sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==
- dependencies:
- "@babel/core" "^7.12.3"
- "@svgr/babel-preset" "^5.5.0"
- "@svgr/hast-util-to-babel-ast" "^5.5.0"
- svg-parser "^2.0.2"
-
-"@svgr/plugin-svgo@^5.5.0":
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz#02da55d85320549324e201c7b2e53bf431fcc246"
- integrity sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==
- dependencies:
- cosmiconfig "^7.0.0"
- deepmerge "^4.2.2"
- svgo "^1.2.2"
-
-"@svgr/webpack@^5.4.0":
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-5.5.0.tgz#aae858ee579f5fa8ce6c3166ef56c6a1b381b640"
- integrity sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==
- dependencies:
- "@babel/core" "^7.12.3"
- "@babel/plugin-transform-react-constant-elements" "^7.12.1"
- "@babel/preset-env" "^7.12.1"
- "@babel/preset-react" "^7.12.5"
- "@svgr/core" "^5.5.0"
- "@svgr/plugin-jsx" "^5.5.0"
- "@svgr/plugin-svgo" "^5.5.0"
- loader-utils "^2.0.0"
-
-"@szmarczak/http-timer@^1.1.2":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
- integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==
- dependencies:
- defer-to-connect "^1.0.1"
-
-"@types/glob@^7.1.1":
- version "7.1.3"
- resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
- integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==
- dependencies:
- "@types/minimatch" "*"
- "@types/node" "*"
-
-"@types/hast@^2.0.0":
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.1.tgz#b16872f2a6144c7025f296fb9636a667ebb79cd9"
- integrity sha512-viwwrB+6xGzw+G1eWpF9geV3fnsDgXqHG+cqgiHrvQfDUW5hzhCyV7Sy3UJxhfRFBsgky2SSW33qi/YrIkjX5Q==
- dependencies:
- "@types/unist" "*"
-
-"@types/html-minifier-terser@^5.0.0":
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#3c9ee980f1a10d6021ae6632ca3e79ca2ec4fb50"
- integrity sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==
-
-"@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6":
- version "7.0.7"
- resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
- integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
-
-"@types/mdast@^3.0.0":
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.3.tgz#2d7d671b1cd1ea3deb306ea75036c2a0407d2deb"
- integrity sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==
- dependencies:
- "@types/unist" "*"
-
-"@types/minimatch@*":
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21"
- integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==
-
-"@types/node@*":
- version "15.12.5"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-15.12.5.tgz#9a78318a45d75c9523d2396131bd3cca54b2d185"
- integrity sha512-se3yX7UHv5Bscf8f1ERKvQOD6sTyycH3hdaoozvaLxgUiY5lIGEeH37AD0G0Qi9kPqihPn0HOfd2yaIEN9VwEg==
-
-"@types/parse-json@^4.0.0":
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
- integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
-
-"@types/parse5@^5.0.0":
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109"
- integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==
-
-"@types/prop-types@*":
- version "15.7.3"
- resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
- integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
-
-"@types/q@^1.5.1":
- version "1.5.4"
- resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24"
- integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
-
-"@types/react-toggle@^4.0.2":
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/@types/react-toggle/-/react-toggle-4.0.2.tgz#46ffa5af1a55de5f25d0aa78ef0b557b5c8bf276"
- integrity sha512-sHqfoKFnL0YU2+OC4meNEC8Ptx9FE8/+nFeFvNcdBa6ANA8KpAzj3R9JN8GtrvlLgjKDoYgI7iILgXYcTPo2IA==
- dependencies:
- "@types/react" "*"
-
-"@types/react@*":
- version "17.0.11"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.11.tgz#67fcd0ddbf5a0b083a0f94e926c7d63f3b836451"
- integrity sha512-yFRQbD+whVonItSk7ZzP/L+gPTJVBkL/7shLEF+i9GC/1cV3JmUxEQz6+9ylhUpWSDuqo1N9qEvqS6vTj4USUA==
- dependencies:
- "@types/prop-types" "*"
- "@types/scheduler" "*"
- csstype "^3.0.2"
-
-"@types/scheduler@*":
- version "0.16.1"
- resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275"
- integrity sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==
-
-"@types/source-list-map@*":
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
- integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==
-
-"@types/tapable@^1", "@types/tapable@^1.0.5":
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.7.tgz#545158342f949e8fd3bfd813224971ecddc3fac4"
- integrity sha512-0VBprVqfgFD7Ehb2vd8Lh9TG3jP98gvr8rgehQqzztZNI7o8zS8Ad4jyZneKELphpuE212D8J70LnSNQSyO6bQ==
-
-"@types/uglify-js@*":
- version "3.13.0"
- resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.13.0.tgz#1cad8df1fb0b143c5aba08de5712ea9d1ff71124"
- integrity sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q==
- dependencies:
- source-map "^0.6.1"
-
-"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3":
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"
- integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==
-
-"@types/webpack-sources@*":
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-2.1.0.tgz#8882b0bd62d1e0ce62f183d0d01b72e6e82e8c10"
- integrity sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==
- dependencies:
- "@types/node" "*"
- "@types/source-list-map" "*"
- source-map "^0.7.3"
-
-"@types/webpack@^4.41.0", "@types/webpack@^4.41.8":
- version "4.41.29"
- resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.29.tgz#2e66c1de8223c440366469415c50a47d97625773"
- integrity sha512-6pLaORaVNZxiB3FSHbyBiWM7QdazAWda1zvAq4SbZObZqHSDbWLi62iFdblVea6SK9eyBIVp5yHhKt/yNQdR7Q==
- dependencies:
- "@types/node" "*"
- "@types/tapable" "^1"
- "@types/uglify-js" "*"
- "@types/webpack-sources" "*"
- anymatch "^3.0.0"
- source-map "^0.6.0"
-
-"@webassemblyjs/ast@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"
- integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==
- dependencies:
- "@webassemblyjs/helper-module-context" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/wast-parser" "1.9.0"
-
-"@webassemblyjs/floating-point-hex-parser@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4"
- integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==
-
-"@webassemblyjs/helper-api-error@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2"
- integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==
-
-"@webassemblyjs/helper-buffer@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00"
- integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==
-
-"@webassemblyjs/helper-code-frame@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27"
- integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==
- dependencies:
- "@webassemblyjs/wast-printer" "1.9.0"
-
-"@webassemblyjs/helper-fsm@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8"
- integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==
-
-"@webassemblyjs/helper-module-context@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07"
- integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
-
-"@webassemblyjs/helper-wasm-bytecode@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790"
- integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==
-
-"@webassemblyjs/helper-wasm-section@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346"
- integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-buffer" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/wasm-gen" "1.9.0"
-
-"@webassemblyjs/ieee754@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4"
- integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==
- dependencies:
- "@xtuc/ieee754" "^1.2.0"
-
-"@webassemblyjs/leb128@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95"
- integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==
- dependencies:
- "@xtuc/long" "4.2.2"
-
-"@webassemblyjs/utf8@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab"
- integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==
-
-"@webassemblyjs/wasm-edit@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf"
- integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-buffer" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/helper-wasm-section" "1.9.0"
- "@webassemblyjs/wasm-gen" "1.9.0"
- "@webassemblyjs/wasm-opt" "1.9.0"
- "@webassemblyjs/wasm-parser" "1.9.0"
- "@webassemblyjs/wast-printer" "1.9.0"
-
-"@webassemblyjs/wasm-gen@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c"
- integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/ieee754" "1.9.0"
- "@webassemblyjs/leb128" "1.9.0"
- "@webassemblyjs/utf8" "1.9.0"
-
-"@webassemblyjs/wasm-opt@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61"
- integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-buffer" "1.9.0"
- "@webassemblyjs/wasm-gen" "1.9.0"
- "@webassemblyjs/wasm-parser" "1.9.0"
-
-"@webassemblyjs/wasm-parser@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e"
- integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-api-error" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/ieee754" "1.9.0"
- "@webassemblyjs/leb128" "1.9.0"
- "@webassemblyjs/utf8" "1.9.0"
-
-"@webassemblyjs/wast-parser@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914"
- integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/floating-point-hex-parser" "1.9.0"
- "@webassemblyjs/helper-api-error" "1.9.0"
- "@webassemblyjs/helper-code-frame" "1.9.0"
- "@webassemblyjs/helper-fsm" "1.9.0"
- "@xtuc/long" "4.2.2"
-
-"@webassemblyjs/wast-printer@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899"
- integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/wast-parser" "1.9.0"
- "@xtuc/long" "4.2.2"
-
-"@xtuc/ieee754@^1.2.0":
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
- integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
-
-"@xtuc/long@4.2.2":
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
- integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
-
-accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
- version "1.3.7"
- resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
- integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
- dependencies:
- mime-types "~2.1.24"
- negotiator "0.6.2"
-
-acorn-walk@^7.1.1:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
- integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
-
-acorn@^6.4.1:
- version "6.4.2"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6"
- integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==
-
-acorn@^7.1.1:
- version "7.4.1"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
- integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
-
-address@1.1.2, address@^1.0.1:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6"
- integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==
-
-aggregate-error@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
- integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
- dependencies:
- clean-stack "^2.0.0"
- indent-string "^4.0.0"
-
-ajv-errors@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d"
- integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==
-
-ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2:
- version "3.5.2"
- resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
- integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
-
-ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.4, ajv@^6.12.5:
- version "6.12.6"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
- integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
- dependencies:
- fast-deep-equal "^3.1.1"
- fast-json-stable-stringify "^2.0.0"
- json-schema-traverse "^0.4.1"
- uri-js "^4.2.2"
-
-algoliasearch-helper@^3.1.1:
- version "3.6.2"
- resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.6.2.tgz#45e19b12589cfa0c611b573287f65266ea2cc14a"
- integrity sha512-Xx0NOA6k4ySn+R2l3UMSONAaMkyfmrZ3AP1geEMo32MxDJQJesZABZYsldO9fa6FKQxH91afhi4hO1G0Zc2opg==
- dependencies:
- events "^1.1.1"
-
-algoliasearch@^4.0.0:
- version "4.10.2"
- resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.10.2.tgz#23e88c71cb381d5b59430baa5d417186cc8ff683"
- integrity sha512-BAYCe97XRfO15irJKBRjBnrp9tSqN0jppklLIXKdtUcXlibcPQtuAeGUP2cPiz6bJd3ISuoYzLFNt4/fQYtLMw==
- dependencies:
- "@algolia/cache-browser-local-storage" "4.10.2"
- "@algolia/cache-common" "4.10.2"
- "@algolia/cache-in-memory" "4.10.2"
- "@algolia/client-account" "4.10.2"
- "@algolia/client-analytics" "4.10.2"
- "@algolia/client-common" "4.10.2"
- "@algolia/client-personalization" "4.10.2"
- "@algolia/client-search" "4.10.2"
- "@algolia/logger-common" "4.10.2"
- "@algolia/logger-console" "4.10.2"
- "@algolia/requester-browser-xhr" "4.10.2"
- "@algolia/requester-common" "4.10.2"
- "@algolia/requester-node-http" "4.10.2"
- "@algolia/transporter" "4.10.2"
-
-alphanum-sort@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
- integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=
-
-ansi-align@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb"
- integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==
- dependencies:
- string-width "^3.0.0"
-
-ansi-colors@^3.0.0:
- version "3.2.4"
- resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
- integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==
-
-ansi-escapes@^4.2.1:
- version "4.3.2"
- resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
- integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
- dependencies:
- type-fest "^0.21.3"
-
-ansi-html@0.0.7:
- version "0.0.7"
- resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e"
- integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4=
-
-ansi-regex@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
- integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
-
-ansi-regex@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
- integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
-
-ansi-regex@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
- integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
-
-ansi-styles@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
- integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
-
-ansi-styles@^3.2.0, ansi-styles@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
- integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
- dependencies:
- color-convert "^1.9.0"
-
-ansi-styles@^4.0.0, ansi-styles@^4.1.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
- integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
- dependencies:
- color-convert "^2.0.1"
-
-anymatch@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
- integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==
- dependencies:
- micromatch "^3.1.4"
- normalize-path "^2.1.1"
-
-anymatch@^3.0.0, anymatch@~3.1.2:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
- integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
- dependencies:
- normalize-path "^3.0.0"
- picomatch "^2.0.4"
-
-aproba@^1.1.1:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
- integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
-
-are-passive-events-supported@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/are-passive-events-supported/-/are-passive-events-supported-1.1.1.tgz#3db180a1753a2186a2de50a32cded3ac0979f5dc"
- integrity sha512-5wnvlvB/dTbfrCvJ027Y4L4gW/6Mwoy1uFSavney0YO++GU+0e/flnjiBBwH+1kh7xNCgCOGvmJC3s32joYbww==
-
-argparse@^1.0.7:
- version "1.0.10"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
- integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
- dependencies:
- sprintf-js "~1.0.2"
-
-arr-diff@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
- integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
-
-arr-flatten@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
- integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
-
-arr-union@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
- integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
-
-array-flatten@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
- integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
-
-array-flatten@^2.1.0:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099"
- integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==
-
-array-union@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
- integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=
- dependencies:
- array-uniq "^1.0.1"
-
-array-union@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
- integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
-
-array-uniq@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
- integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=
-
-array-unique@^0.3.2:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
- integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
-
-arrify@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
- integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
-
-asap@~2.0.3:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
- integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
-
-asn1.js@^5.2.0:
- version "5.4.1"
- resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07"
- integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==
- dependencies:
- bn.js "^4.0.0"
- inherits "^2.0.1"
- minimalistic-assert "^1.0.0"
- safer-buffer "^2.1.0"
-
-assert@^1.1.1:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb"
- integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==
- dependencies:
- object-assign "^4.1.1"
- util "0.10.3"
-
-assign-symbols@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
- integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
-
-async-each@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
- integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
-
-async-limiter@~1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
- integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
-
-async@^2.6.2:
- version "2.6.3"
- resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
- integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
- dependencies:
- lodash "^4.17.14"
-
-atob@^2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
- integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
-
-autoprefixer@^9.6.1:
- version "9.8.6"
- resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f"
- integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==
- dependencies:
- browserslist "^4.12.0"
- caniuse-lite "^1.0.30001109"
- colorette "^1.2.1"
- normalize-range "^0.1.2"
- num2fraction "^1.2.2"
- postcss "^7.0.32"
- postcss-value-parser "^4.1.0"
-
-babel-code-frame@^6.22.0:
- version "6.26.0"
- resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
- integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=
- dependencies:
- chalk "^1.1.3"
- esutils "^2.0.2"
- js-tokens "^3.0.2"
-
-babel-loader@^8.1.0:
- version "8.2.2"
- resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.2.tgz#9363ce84c10c9a40e6c753748e1441b60c8a0b81"
- integrity sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g==
- dependencies:
- find-cache-dir "^3.3.1"
- loader-utils "^1.4.0"
- make-dir "^3.1.0"
- schema-utils "^2.6.5"
-
-babel-plugin-apply-mdx-type-prop@1.6.22:
- version "1.6.22"
- resolved "https://registry.yarnpkg.com/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz#d216e8fd0de91de3f1478ef3231e05446bc8705b"
- integrity sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==
- dependencies:
- "@babel/helper-plugin-utils" "7.10.4"
- "@mdx-js/util" "1.6.22"
-
-babel-plugin-dynamic-import-node@^2.3.0, babel-plugin-dynamic-import-node@^2.3.3:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3"
- integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==
- dependencies:
- object.assign "^4.1.0"
-
-babel-plugin-extract-import-names@1.6.22:
- version "1.6.22"
- resolved "https://registry.yarnpkg.com/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz#de5f9a28eb12f3eb2578bf74472204e66d1a13dc"
- integrity sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==
- dependencies:
- "@babel/helper-plugin-utils" "7.10.4"
-
-babel-plugin-polyfill-corejs2@^0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz#e9124785e6fd94f94b618a7954e5693053bf5327"
- integrity sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==
- dependencies:
- "@babel/compat-data" "^7.13.11"
- "@babel/helper-define-polyfill-provider" "^0.2.2"
- semver "^6.1.1"
-
-babel-plugin-polyfill-corejs3@^0.2.2:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.3.tgz#72add68cf08a8bf139ba6e6dfc0b1d504098e57b"
- integrity sha512-rCOFzEIJpJEAU14XCcV/erIf/wZQMmMT5l5vXOpL5uoznyOGfDIjPj6FVytMvtzaKSTSVKouOCTPJ5OMUZH30g==
- dependencies:
- "@babel/helper-define-polyfill-provider" "^0.2.2"
- core-js-compat "^3.14.0"
-
-babel-plugin-polyfill-regenerator@^0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz#b310c8d642acada348c1fa3b3e6ce0e851bee077"
- integrity sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==
- dependencies:
- "@babel/helper-define-polyfill-provider" "^0.2.2"
-
-bail@^1.0.0:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776"
- integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==
-
-balanced-match@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
- integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
-
-base16@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70"
- integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=
-
-base64-js@^1.0.2:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
- integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
-
-base@^0.11.1:
- version "0.11.2"
- resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
- integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
- dependencies:
- cache-base "^1.0.1"
- class-utils "^0.3.5"
- component-emitter "^1.2.1"
- define-property "^1.0.0"
- isobject "^3.0.1"
- mixin-deep "^1.2.0"
- pascalcase "^0.1.1"
-
-batch@0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
- integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=
-
-bfj@^6.1.1:
- version "6.1.2"
- resolved "https://registry.yarnpkg.com/bfj/-/bfj-6.1.2.tgz#325c861a822bcb358a41c78a33b8e6e2086dde7f"
- integrity sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw==
- dependencies:
- bluebird "^3.5.5"
- check-types "^8.0.3"
- hoopy "^0.1.4"
- tryer "^1.0.1"
-
-big.js@^5.2.2:
- version "5.2.2"
- resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
- integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
-
-binary-extensions@^1.0.0:
- version "1.13.1"
- resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
- integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
-
-binary-extensions@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
- integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
-
-bindings@^1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
- integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
- dependencies:
- file-uri-to-path "1.0.0"
-
-bluebird@^3.5.5, bluebird@^3.7.1:
- version "3.7.2"
- resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
- integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
-
-bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9:
- version "4.12.0"
- resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
- integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
-
-bn.js@^5.0.0, bn.js@^5.1.1:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002"
- integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==
-
-body-parser@1.19.0:
- version "1.19.0"
- resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
- integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
- dependencies:
- bytes "3.1.0"
- content-type "~1.0.4"
- debug "2.6.9"
- depd "~1.1.2"
- http-errors "1.7.2"
- iconv-lite "0.4.24"
- on-finished "~2.3.0"
- qs "6.7.0"
- raw-body "2.4.0"
- type-is "~1.6.17"
-
-bonjour@^3.5.0:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5"
- integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU=
- dependencies:
- array-flatten "^2.1.0"
- deep-equal "^1.0.1"
- dns-equal "^1.0.0"
- dns-txt "^2.0.2"
- multicast-dns "^6.0.1"
- multicast-dns-service-types "^1.1.0"
-
-boolbase@^1.0.0, boolbase@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
- integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
-
-boxen@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
- integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==
- dependencies:
- ansi-align "^3.0.0"
- camelcase "^5.3.1"
- chalk "^3.0.0"
- cli-boxes "^2.2.0"
- string-width "^4.1.0"
- term-size "^2.1.0"
- type-fest "^0.8.1"
- widest-line "^3.1.0"
-
-brace-expansion@^1.1.7:
- version "1.1.11"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
- integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
- dependencies:
- balanced-match "^1.0.0"
- concat-map "0.0.1"
-
-braces@^2.3.1, braces@^2.3.2:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
- integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
- dependencies:
- arr-flatten "^1.1.0"
- array-unique "^0.3.2"
- extend-shallow "^2.0.1"
- fill-range "^4.0.0"
- isobject "^3.0.1"
- repeat-element "^1.1.2"
- snapdragon "^0.8.1"
- snapdragon-node "^2.0.1"
- split-string "^3.0.2"
- to-regex "^3.0.1"
-
-braces@^3.0.1, braces@~3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
- integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
- dependencies:
- fill-range "^7.0.1"
-
-brorand@^1.0.1, brorand@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
- integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
-
-browserify-aes@^1.0.0, browserify-aes@^1.0.4:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
- integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==
- dependencies:
- buffer-xor "^1.0.3"
- cipher-base "^1.0.0"
- create-hash "^1.1.0"
- evp_bytestokey "^1.0.3"
- inherits "^2.0.1"
- safe-buffer "^5.0.1"
-
-browserify-cipher@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0"
- integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==
- dependencies:
- browserify-aes "^1.0.4"
- browserify-des "^1.0.0"
- evp_bytestokey "^1.0.0"
-
-browserify-des@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c"
- integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==
- dependencies:
- cipher-base "^1.0.1"
- des.js "^1.0.0"
- inherits "^2.0.1"
- safe-buffer "^5.1.2"
-
-browserify-rsa@^4.0.0, browserify-rsa@^4.0.1:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d"
- integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==
- dependencies:
- bn.js "^5.0.0"
- randombytes "^2.0.1"
-
-browserify-sign@^4.0.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3"
- integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==
- dependencies:
- bn.js "^5.1.1"
- browserify-rsa "^4.0.1"
- create-hash "^1.2.0"
- create-hmac "^1.1.7"
- elliptic "^6.5.3"
- inherits "^2.0.4"
- parse-asn1 "^5.1.5"
- readable-stream "^3.6.0"
- safe-buffer "^5.2.0"
-
-browserify-zlib@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f"
- integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==
- dependencies:
- pako "~1.0.5"
-
-browserslist@4.10.0:
- version "4.10.0"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.10.0.tgz#f179737913eaf0d2b98e4926ac1ca6a15cbcc6a9"
- integrity sha512-TpfK0TDgv71dzuTsEAlQiHeWQ/tiPqgNZVdv046fvNtBZrjbv2O3TsWCDU0AWGJJKCF/KsjNdLzR9hXOsh/CfA==
- dependencies:
- caniuse-lite "^1.0.30001035"
- electron-to-chromium "^1.3.378"
- node-releases "^1.1.52"
- pkg-up "^3.1.0"
-
-browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.16.6, browserslist@^4.6.4:
- version "4.16.6"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2"
- integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==
- dependencies:
- caniuse-lite "^1.0.30001219"
- colorette "^1.2.2"
- electron-to-chromium "^1.3.723"
- escalade "^3.1.1"
- node-releases "^1.1.71"
-
-buffer-from@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
- integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
-
-buffer-indexof@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c"
- integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==
-
-buffer-json@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/buffer-json/-/buffer-json-2.0.0.tgz#f73e13b1e42f196fe2fd67d001c7d7107edd7c23"
- integrity sha512-+jjPFVqyfF1esi9fvfUs3NqM0pH1ziZ36VP4hmA/y/Ssfo/5w5xHKfTw9BwQjoJ1w/oVtpLomqwUHKdefGyuHw==
-
-buffer-xor@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
- integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=
-
-buffer@^4.3.0:
- version "4.9.2"
- resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8"
- integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==
- dependencies:
- base64-js "^1.0.2"
- ieee754 "^1.1.4"
- isarray "^1.0.0"
-
-builtin-status-codes@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
- integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
-
-bytes@3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
- integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
-
-bytes@3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
- integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
-
-cacache@^12.0.2:
- version "12.0.4"
- resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c"
- integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==
- dependencies:
- bluebird "^3.5.5"
- chownr "^1.1.1"
- figgy-pudding "^3.5.1"
- glob "^7.1.4"
- graceful-fs "^4.1.15"
- infer-owner "^1.0.3"
- lru-cache "^5.1.1"
- mississippi "^3.0.0"
- mkdirp "^0.5.1"
- move-concurrently "^1.0.1"
- promise-inflight "^1.0.1"
- rimraf "^2.6.3"
- ssri "^6.0.1"
- unique-filename "^1.1.1"
- y18n "^4.0.0"
-
-cacache@^15.0.5:
- version "15.2.0"
- resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.2.0.tgz#73af75f77c58e72d8c630a7a2858cb18ef523389"
- integrity sha512-uKoJSHmnrqXgthDFx/IU6ED/5xd+NNGe+Bb+kLZy7Ku4P+BaiWEUflAKPZ7eAzsYGcsAGASJZsybXp+quEcHTw==
- dependencies:
- "@npmcli/move-file" "^1.0.1"
- chownr "^2.0.0"
- fs-minipass "^2.0.0"
- glob "^7.1.4"
- infer-owner "^1.0.4"
- lru-cache "^6.0.0"
- minipass "^3.1.1"
- minipass-collect "^1.0.2"
- minipass-flush "^1.0.5"
- minipass-pipeline "^1.2.2"
- mkdirp "^1.0.3"
- p-map "^4.0.0"
- promise-inflight "^1.0.1"
- rimraf "^3.0.2"
- ssri "^8.0.1"
- tar "^6.0.2"
- unique-filename "^1.1.1"
-
-cache-base@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
- integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
- dependencies:
- collection-visit "^1.0.0"
- component-emitter "^1.2.1"
- get-value "^2.0.6"
- has-value "^1.0.0"
- isobject "^3.0.1"
- set-value "^2.0.0"
- to-object-path "^0.3.0"
- union-value "^1.0.0"
- unset-value "^1.0.0"
-
-cache-loader@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/cache-loader/-/cache-loader-4.1.0.tgz#9948cae353aec0a1fcb1eafda2300816ec85387e"
- integrity sha512-ftOayxve0PwKzBF/GLsZNC9fJBXl8lkZE3TOsjkboHfVHVkL39iUEs1FO07A33mizmci5Dudt38UZrrYXDtbhw==
- dependencies:
- buffer-json "^2.0.0"
- find-cache-dir "^3.0.0"
- loader-utils "^1.2.3"
- mkdirp "^0.5.1"
- neo-async "^2.6.1"
- schema-utils "^2.0.0"
-
-cacheable-request@^6.0.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912"
- integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==
- dependencies:
- clone-response "^1.0.2"
- get-stream "^5.1.0"
- http-cache-semantics "^4.0.0"
- keyv "^3.0.0"
- lowercase-keys "^2.0.0"
- normalize-url "^4.1.0"
- responselike "^1.0.2"
-
-call-bind@^1.0.0, call-bind@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
- integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
- dependencies:
- function-bind "^1.1.1"
- get-intrinsic "^1.0.2"
-
-call-me-maybe@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
- integrity sha1-JtII6onje1y95gJQoV8DHBak1ms=
-
-caller-callsite@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134"
- integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=
- dependencies:
- callsites "^2.0.0"
-
-caller-path@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4"
- integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=
- dependencies:
- caller-callsite "^2.0.0"
-
-callsites@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
- integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=
-
-callsites@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
- integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-
-camel-case@^4.1.1:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a"
- integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==
- dependencies:
- pascal-case "^3.1.2"
- tslib "^2.0.3"
-
-camelcase-css@2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
- integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
-
-camelcase@^5.0.0, camelcase@^5.3.1:
- version "5.3.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
- integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
-
-camelcase@^6.2.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809"
- integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
-
-caniuse-api@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
- integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==
- dependencies:
- browserslist "^4.0.0"
- caniuse-lite "^1.0.0"
- lodash.memoize "^4.1.2"
- lodash.uniq "^4.5.0"
-
-caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001219:
- version "1.0.30001241"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001241.tgz#cd3fae47eb3d7691692b406568d7a3e5b23c7598"
- integrity sha512-1uoSZ1Pq1VpH0WerIMqwptXHNNGfdl7d1cJUFs80CwQ/lVzdhTvsFZCeNFslze7AjsQnb4C85tzclPa1VShbeQ==
-
-ccount@^1.0.0, ccount@^1.0.3:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043"
- integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==
-
-chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
- integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
- dependencies:
- ansi-styles "^3.2.1"
- escape-string-regexp "^1.0.5"
- supports-color "^5.3.0"
-
-chalk@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
- integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
- dependencies:
- ansi-styles "^2.2.1"
- escape-string-regexp "^1.0.2"
- has-ansi "^2.0.0"
- strip-ansi "^3.0.0"
- supports-color "^2.0.0"
-
-chalk@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
- integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
-chalk@^4.1.0:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad"
- integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
-character-entities-legacy@^1.0.0:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1"
- integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==
-
-character-entities@^1.0.0:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b"
- integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==
-
-character-reference-invalid@^1.0.0:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560"
- integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==
-
-chardet@^0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
- integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
-
-check-types@^8.0.3:
- version "8.0.3"
- resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552"
- integrity sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ==
-
-cheerio@^0.22.0:
- version "0.22.0"
- resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e"
- integrity sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=
- dependencies:
- css-select "~1.2.0"
- dom-serializer "~0.1.0"
- entities "~1.1.1"
- htmlparser2 "^3.9.1"
- lodash.assignin "^4.0.9"
- lodash.bind "^4.1.4"
- lodash.defaults "^4.0.1"
- lodash.filter "^4.4.0"
- lodash.flatten "^4.2.0"
- lodash.foreach "^4.3.0"
- lodash.map "^4.4.0"
- lodash.merge "^4.4.0"
- lodash.pick "^4.2.1"
- lodash.reduce "^4.4.0"
- lodash.reject "^4.4.0"
- lodash.some "^4.4.0"
-
-chokidar@^2.1.8:
- version "2.1.8"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
- integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==
- dependencies:
- anymatch "^2.0.0"
- async-each "^1.0.1"
- braces "^2.3.2"
- glob-parent "^3.1.0"
- inherits "^2.0.3"
- is-binary-path "^1.0.0"
- is-glob "^4.0.0"
- normalize-path "^3.0.0"
- path-is-absolute "^1.0.0"
- readdirp "^2.2.1"
- upath "^1.1.1"
- optionalDependencies:
- fsevents "^1.2.7"
-
-chokidar@^3.3.0, chokidar@^3.4.1:
- version "3.5.2"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
- integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==
- dependencies:
- anymatch "~3.1.2"
- braces "~3.0.2"
- glob-parent "~5.1.2"
- is-binary-path "~2.1.0"
- is-glob "~4.0.1"
- normalize-path "~3.0.0"
- readdirp "~3.6.0"
- optionalDependencies:
- fsevents "~2.3.2"
-
-chownr@^1.1.1:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
- integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
-
-chownr@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
- integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
-
-chrome-trace-event@^1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
- integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
-
-ci-info@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
- integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
-
-ci-info@^3.0.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.2.0.tgz#2876cb948a498797b5236f0095bc057d0dca38b6"
- integrity sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==
-
-cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
- integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==
- dependencies:
- inherits "^2.0.1"
- safe-buffer "^5.0.1"
-
-class-utils@^0.3.5:
- version "0.3.6"
- resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
- integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
- dependencies:
- arr-union "^3.1.0"
- define-property "^0.2.5"
- isobject "^3.0.0"
- static-extend "^0.1.1"
-
-classnames@^2.2.5:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
- integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
-
-clean-css@^4.2.3:
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78"
- integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==
- dependencies:
- source-map "~0.6.0"
-
-clean-stack@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
- integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
-
-cli-boxes@^2.2.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f"
- integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==
-
-cli-cursor@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
- integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
- dependencies:
- restore-cursor "^3.1.0"
-
-cli-width@^2.0.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48"
- integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==
-
-cli-width@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
- integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
-
-cliui@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
- integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==
- dependencies:
- string-width "^3.1.0"
- strip-ansi "^5.2.0"
- wrap-ansi "^5.1.0"
-
-clone-response@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
- integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
- dependencies:
- mimic-response "^1.0.0"
-
-clsx@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
- integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
-
-coa@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3"
- integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==
- dependencies:
- "@types/q" "^1.5.1"
- chalk "^2.4.1"
- q "^1.1.2"
-
-collapse-white-space@^1.0.2:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287"
- integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==
-
-collection-visit@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
- integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=
- dependencies:
- map-visit "^1.0.0"
- object-visit "^1.0.0"
-
-color-convert@^1.9.0, color-convert@^1.9.1:
- version "1.9.3"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
- integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
- dependencies:
- color-name "1.1.3"
-
-color-convert@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
- integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
- dependencies:
- color-name "~1.1.4"
-
-color-name@1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
- integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
-
-color-name@^1.0.0, color-name@~1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
- integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-
-color-string@^1.5.4:
- version "1.5.5"
- resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.5.tgz#65474a8f0e7439625f3d27a6a19d89fc45223014"
- integrity sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==
- dependencies:
- color-name "^1.0.0"
- simple-swizzle "^0.2.2"
-
-color@^3.0.0:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/color/-/color-3.1.3.tgz#ca67fb4e7b97d611dcde39eceed422067d91596e"
- integrity sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==
- dependencies:
- color-convert "^1.9.1"
- color-string "^1.5.4"
-
-colorette@^1.2.1, colorette@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
- integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
-
-comma-separated-tokens@^1.0.0:
- version "1.0.8"
- resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea"
- integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==
-
-commander@^2.18.0, commander@^2.20.0:
- version "2.20.3"
- resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
- integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
-
-commander@^4.0.1, commander@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
- integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
-
-commondir@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
- integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
-
-component-emitter@^1.2.1:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
- integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
-
-compressible@~2.0.16:
- version "2.0.18"
- resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
- integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
- dependencies:
- mime-db ">= 1.43.0 < 2"
-
-compression@^1.7.4:
- version "1.7.4"
- resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
- integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==
- dependencies:
- accepts "~1.3.5"
- bytes "3.0.0"
- compressible "~2.0.16"
- debug "2.6.9"
- on-headers "~1.0.2"
- safe-buffer "5.1.2"
- vary "~1.1.2"
-
-concat-map@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
- integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
-
-concat-stream@^1.5.0:
- version "1.6.2"
- resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
- integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
- dependencies:
- buffer-from "^1.0.0"
- inherits "^2.0.3"
- readable-stream "^2.2.2"
- typedarray "^0.0.6"
-
-configstore@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96"
- integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==
- dependencies:
- dot-prop "^5.2.0"
- graceful-fs "^4.1.2"
- make-dir "^3.0.0"
- unique-string "^2.0.0"
- write-file-atomic "^3.0.0"
- xdg-basedir "^4.0.0"
-
-connect-history-api-fallback@^1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
- integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==
-
-consola@^2.10.0:
- version "2.15.3"
- resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550"
- integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==
-
-console-browserify@^1.1.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
- integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==
-
-constants-browserify@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
- integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
-
-content-disposition@0.5.2:
- version "0.5.2"
- resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
- integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ=
-
-content-disposition@0.5.3:
- version "0.5.3"
- resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
- integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
- dependencies:
- safe-buffer "5.1.2"
-
-content-type@~1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
- integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
-
-convert-source-map@^1.7.0:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
- integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
- dependencies:
- safe-buffer "~5.1.1"
-
-cookie-signature@1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
- integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
-
-cookie@0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
- integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
-
-copy-concurrently@^1.0.0:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
- integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==
- dependencies:
- aproba "^1.1.1"
- fs-write-stream-atomic "^1.0.8"
- iferr "^0.1.5"
- mkdirp "^0.5.1"
- rimraf "^2.5.4"
- run-queue "^1.0.0"
-
-copy-descriptor@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
- integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
-
-copy-text-to-clipboard@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/copy-text-to-clipboard/-/copy-text-to-clipboard-2.2.0.tgz#329dd6daf8c42034c763ace567418401764579ae"
- integrity sha512-WRvoIdnTs1rgPMkgA2pUOa/M4Enh2uzCwdKsOMYNAJiz/4ZvEJgmbF4OmninPmlFdAWisfeh0tH+Cpf7ni3RqQ==
-
-copy-webpack-plugin@^6.0.3:
- version "6.4.1"
- resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.4.1.tgz#138cd9b436dbca0a6d071720d5414848992ec47e"
- integrity sha512-MXyPCjdPVx5iiWyl40Va3JGh27bKzOTNY3NjUTrosD2q7dR/cLD0013uqJ3BpFbUjyONINjb6qI7nDIJujrMbA==
- dependencies:
- cacache "^15.0.5"
- fast-glob "^3.2.4"
- find-cache-dir "^3.3.1"
- glob-parent "^5.1.1"
- globby "^11.0.1"
- loader-utils "^2.0.0"
- normalize-path "^3.0.0"
- p-limit "^3.0.2"
- schema-utils "^3.0.0"
- serialize-javascript "^5.0.1"
- webpack-sources "^1.4.3"
-
-core-js-compat@^3.14.0, core-js-compat@^3.15.0:
- version "3.15.2"
- resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.15.2.tgz#47272fbb479880de14b4e6081f71f3492f5bd3cb"
- integrity sha512-Wp+BJVvwopjI+A1EFqm2dwUmWYXrvucmtIB2LgXn/Rb+gWPKYxtmb4GKHGKG/KGF1eK9jfjzT38DITbTOCX/SQ==
- dependencies:
- browserslist "^4.16.6"
- semver "7.0.0"
-
-core-js-pure@^3.15.0:
- version "3.15.2"
- resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.15.2.tgz#c8e0874822705f3385d3197af9348f7c9ae2e3ce"
- integrity sha512-D42L7RYh1J2grW8ttxoY1+17Y4wXZeKe7uyplAI3FkNQyI5OgBIAjUfFiTPfL1rs0qLpxaabITNbjKl1Sp82tA==
-
-core-js@^2.6.5:
- version "2.6.12"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
- integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
-
-core-util-is@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
- integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
-
-cosmiconfig@^5.0.0:
- version "5.2.1"
- resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
- integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==
- dependencies:
- import-fresh "^2.0.0"
- is-directory "^0.3.1"
- js-yaml "^3.13.1"
- parse-json "^4.0.0"
-
-cosmiconfig@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3"
- integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==
- dependencies:
- "@types/parse-json" "^4.0.0"
- import-fresh "^3.2.1"
- parse-json "^5.0.0"
- path-type "^4.0.0"
- yaml "^1.10.0"
-
-create-ecdh@^4.0.0:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e"
- integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==
- dependencies:
- bn.js "^4.1.0"
- elliptic "^6.5.3"
-
-create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
- integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
- dependencies:
- cipher-base "^1.0.1"
- inherits "^2.0.1"
- md5.js "^1.3.4"
- ripemd160 "^2.0.1"
- sha.js "^2.4.0"
-
-create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
- version "1.1.7"
- resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
- integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
- dependencies:
- cipher-base "^1.0.3"
- create-hash "^1.1.0"
- inherits "^2.0.1"
- ripemd160 "^2.0.0"
- safe-buffer "^5.0.1"
- sha.js "^2.4.8"
-
-cross-fetch@^3.0.4:
- version "3.1.4"
- resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39"
- integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==
- dependencies:
- node-fetch "2.6.1"
-
-cross-spawn@7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14"
- integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==
- dependencies:
- path-key "^3.1.0"
- shebang-command "^2.0.0"
- which "^2.0.1"
-
-cross-spawn@^6.0.0:
- version "6.0.5"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
- integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
- dependencies:
- nice-try "^1.0.4"
- path-key "^2.0.1"
- semver "^5.5.0"
- shebang-command "^1.2.0"
- which "^1.2.9"
-
-cross-spawn@^7.0.0:
- version "7.0.3"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
- integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
- dependencies:
- path-key "^3.1.0"
- shebang-command "^2.0.0"
- which "^2.0.1"
-
-crypto-browserify@^3.11.0:
- version "3.12.0"
- resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
- integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==
- dependencies:
- browserify-cipher "^1.0.0"
- browserify-sign "^4.0.0"
- create-ecdh "^4.0.0"
- create-hash "^1.1.0"
- create-hmac "^1.1.0"
- diffie-hellman "^5.0.0"
- inherits "^2.0.1"
- pbkdf2 "^3.0.3"
- public-encrypt "^4.0.0"
- randombytes "^2.0.0"
- randomfill "^1.0.3"
-
-crypto-random-string@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
- integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
-
-css-blank-pseudo@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5"
- integrity sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==
- dependencies:
- postcss "^7.0.5"
-
-css-color-names@0.0.4, css-color-names@^0.0.4:
- version "0.0.4"
- resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
- integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=
-
-css-declaration-sorter@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22"
- integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==
- dependencies:
- postcss "^7.0.1"
- timsort "^0.3.0"
-
-css-has-pseudo@^0.10.0:
- version "0.10.0"
- resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz#3c642ab34ca242c59c41a125df9105841f6966ee"
- integrity sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ==
- dependencies:
- postcss "^7.0.6"
- postcss-selector-parser "^5.0.0-rc.4"
-
-css-loader@^3.4.2:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.6.0.tgz#2e4b2c7e6e2d27f8c8f28f61bffcd2e6c91ef645"
- integrity sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==
- dependencies:
- camelcase "^5.3.1"
- cssesc "^3.0.0"
- icss-utils "^4.1.1"
- loader-utils "^1.2.3"
- normalize-path "^3.0.0"
- postcss "^7.0.32"
- postcss-modules-extract-imports "^2.0.0"
- postcss-modules-local-by-default "^3.0.2"
- postcss-modules-scope "^2.2.0"
- postcss-modules-values "^3.0.0"
- postcss-value-parser "^4.1.0"
- schema-utils "^2.7.0"
- semver "^6.3.0"
-
-css-prefers-color-scheme@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz#6f830a2714199d4f0d0d0bb8a27916ed65cff1f4"
- integrity sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg==
- dependencies:
- postcss "^7.0.5"
-
-css-select-base-adapter@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7"
- integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==
-
-css-select@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef"
- integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==
- dependencies:
- boolbase "^1.0.0"
- css-what "^3.2.1"
- domutils "^1.7.0"
- nth-check "^1.0.2"
-
-css-select@^4.1.3:
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067"
- integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==
- dependencies:
- boolbase "^1.0.0"
- css-what "^5.0.0"
- domhandler "^4.2.0"
- domutils "^2.6.0"
- nth-check "^2.0.0"
-
-css-select@~1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
- integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=
- dependencies:
- boolbase "~1.0.0"
- css-what "2.1"
- domutils "1.5.1"
- nth-check "~1.0.1"
-
-css-tree@1.0.0-alpha.37:
- version "1.0.0-alpha.37"
- resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22"
- integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==
- dependencies:
- mdn-data "2.0.4"
- source-map "^0.6.1"
-
-css-tree@^1.1.2:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
- integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
- dependencies:
- mdn-data "2.0.14"
- source-map "^0.6.1"
-
-css-what@2.1:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
- integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
-
-css-what@^3.2.1:
- version "3.4.2"
- resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4"
- integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==
-
-css-what@^5.0.0:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad"
- integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==
-
-cssdb@^4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.4.0.tgz#3bf2f2a68c10f5c6a08abd92378331ee803cddb0"
- integrity sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ==
-
-cssesc@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703"
- integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==
-
-cssesc@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
- integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
-
-cssnano-preset-default@^4.0.8:
- version "4.0.8"
- resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz#920622b1fc1e95a34e8838203f1397a504f2d3ff"
- integrity sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==
- dependencies:
- css-declaration-sorter "^4.0.1"
- cssnano-util-raw-cache "^4.0.1"
- postcss "^7.0.0"
- postcss-calc "^7.0.1"
- postcss-colormin "^4.0.3"
- postcss-convert-values "^4.0.1"
- postcss-discard-comments "^4.0.2"
- postcss-discard-duplicates "^4.0.2"
- postcss-discard-empty "^4.0.1"
- postcss-discard-overridden "^4.0.1"
- postcss-merge-longhand "^4.0.11"
- postcss-merge-rules "^4.0.3"
- postcss-minify-font-values "^4.0.2"
- postcss-minify-gradients "^4.0.2"
- postcss-minify-params "^4.0.2"
- postcss-minify-selectors "^4.0.2"
- postcss-normalize-charset "^4.0.1"
- postcss-normalize-display-values "^4.0.2"
- postcss-normalize-positions "^4.0.2"
- postcss-normalize-repeat-style "^4.0.2"
- postcss-normalize-string "^4.0.2"
- postcss-normalize-timing-functions "^4.0.2"
- postcss-normalize-unicode "^4.0.1"
- postcss-normalize-url "^4.0.1"
- postcss-normalize-whitespace "^4.0.2"
- postcss-ordered-values "^4.1.2"
- postcss-reduce-initial "^4.0.3"
- postcss-reduce-transforms "^4.0.2"
- postcss-svgo "^4.0.3"
- postcss-unique-selectors "^4.0.1"
-
-cssnano-util-get-arguments@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f"
- integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=
-
-cssnano-util-get-match@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d"
- integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=
-
-cssnano-util-raw-cache@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282"
- integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==
- dependencies:
- postcss "^7.0.0"
-
-cssnano-util-same-parent@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3"
- integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==
-
-cssnano@^4.1.10:
- version "4.1.11"
- resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.11.tgz#c7b5f5b81da269cb1fd982cb960c1200910c9a99"
- integrity sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==
- dependencies:
- cosmiconfig "^5.0.0"
- cssnano-preset-default "^4.0.8"
- is-resolvable "^1.0.0"
- postcss "^7.0.0"
-
-csso@^4.0.2:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
- integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
- dependencies:
- css-tree "^1.1.2"
-
-csstype@^3.0.2:
- version "3.0.8"
- resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340"
- integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==
-
-cyclist@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
- integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=
-
-debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0:
- version "2.6.9"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
- integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
- dependencies:
- ms "2.0.0"
-
-debug@^3.1.1, debug@^3.2.6:
- version "3.2.7"
- resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
- integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
- dependencies:
- ms "^2.1.1"
-
-debug@^4.1.0, debug@^4.1.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
- integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
- dependencies:
- ms "2.1.2"
-
-decamelize@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
- integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
-
-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"
- integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
-
-decompress-response@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
- integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
- dependencies:
- mimic-response "^1.0.0"
-
-deep-equal@^1.0.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a"
- integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==
- dependencies:
- is-arguments "^1.0.4"
- is-date-object "^1.0.1"
- is-regex "^1.0.4"
- object-is "^1.0.1"
- object-keys "^1.1.1"
- regexp.prototype.flags "^1.2.0"
-
-deep-extend@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
- integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
-
-deepmerge@^4.2.2:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
- integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
-
-default-gateway@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
- integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==
- dependencies:
- execa "^1.0.0"
- ip-regex "^2.1.0"
-
-defer-to-connect@^1.0.1:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
- integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
-
-define-properties@^1.1.2, define-properties@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
- integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
- dependencies:
- object-keys "^1.0.12"
-
-define-property@^0.2.5:
- version "0.2.5"
- resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
- integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=
- dependencies:
- is-descriptor "^0.1.0"
-
-define-property@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
- integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY=
- dependencies:
- is-descriptor "^1.0.0"
-
-define-property@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
- integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
- dependencies:
- is-descriptor "^1.0.2"
- isobject "^3.0.1"
-
-del@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4"
- integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==
- dependencies:
- "@types/glob" "^7.1.1"
- globby "^6.1.0"
- is-path-cwd "^2.0.0"
- is-path-in-cwd "^2.0.0"
- p-map "^2.0.0"
- pify "^4.0.1"
- rimraf "^2.6.3"
-
-del@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7"
- integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==
- dependencies:
- globby "^10.0.1"
- graceful-fs "^4.2.2"
- is-glob "^4.0.1"
- is-path-cwd "^2.2.0"
- is-path-inside "^3.0.1"
- p-map "^3.0.0"
- rimraf "^3.0.0"
- slash "^3.0.0"
-
-depd@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
- integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
-
-des.js@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843"
- integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==
- dependencies:
- inherits "^2.0.1"
- minimalistic-assert "^1.0.0"
-
-destroy@~1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
- integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
-
-detab@2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/detab/-/detab-2.0.4.tgz#b927892069aff405fbb9a186fe97a44a92a94b43"
- integrity sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==
- dependencies:
- repeat-string "^1.5.4"
-
-detect-node@^2.0.4:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
- integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
-
-detect-port-alt@1.1.6:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275"
- integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==
- dependencies:
- address "^1.0.1"
- debug "^2.6.0"
-
-detect-port@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.3.0.tgz#d9c40e9accadd4df5cac6a782aefd014d573d1f1"
- integrity sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==
- dependencies:
- address "^1.0.1"
- debug "^2.6.0"
-
-diffie-hellman@^5.0.0:
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
- integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==
- dependencies:
- bn.js "^4.1.0"
- miller-rabin "^4.0.0"
- randombytes "^2.0.0"
-
-dir-glob@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034"
- integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==
- dependencies:
- arrify "^1.0.1"
- path-type "^3.0.0"
-
-dir-glob@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
- integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
- dependencies:
- path-type "^4.0.0"
-
-dns-equal@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
- integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0=
-
-dns-packet@^1.3.1:
- version "1.3.4"
- resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.4.tgz#e3455065824a2507ba886c55a89963bb107dec6f"
- integrity sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==
- dependencies:
- ip "^1.1.0"
- safe-buffer "^5.0.1"
-
-dns-txt@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6"
- integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=
- dependencies:
- buffer-indexof "^1.0.0"
-
-dom-converter@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
- integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==
- dependencies:
- utila "~0.4"
-
-dom-serializer@0:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
- integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==
- dependencies:
- domelementtype "^2.0.1"
- entities "^2.0.0"
-
-dom-serializer@^1.0.1:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91"
- integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==
- dependencies:
- domelementtype "^2.0.1"
- domhandler "^4.2.0"
- entities "^2.0.0"
-
-dom-serializer@~0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0"
- integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==
- dependencies:
- domelementtype "^1.3.0"
- entities "^1.1.1"
-
-domain-browser@^1.1.1:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
- integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
-
-domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
- integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
-
-domelementtype@^2.0.1, domelementtype@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
- integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
-
-domhandler@^2.3.0:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
- integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==
- dependencies:
- domelementtype "1"
-
-domhandler@^4.0.0, domhandler@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059"
- integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==
- dependencies:
- domelementtype "^2.2.0"
-
-domutils@1.5.1:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
- integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=
- dependencies:
- dom-serializer "0"
- domelementtype "1"
-
-domutils@^1.5.1, domutils@^1.7.0:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
- integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==
- dependencies:
- dom-serializer "0"
- domelementtype "1"
-
-domutils@^2.5.2, domutils@^2.6.0:
- version "2.7.0"
- resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.7.0.tgz#8ebaf0c41ebafcf55b0b72ec31c56323712c5442"
- integrity sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==
- dependencies:
- dom-serializer "^1.0.1"
- domelementtype "^2.2.0"
- domhandler "^4.2.0"
-
-dot-case@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
- integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
- dependencies:
- no-case "^3.0.4"
- tslib "^2.0.3"
-
-dot-prop@^5.2.0:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88"
- integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==
- dependencies:
- is-obj "^2.0.0"
-
-duplexer3@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
- integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
-
-duplexer@^0.1.1:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
- integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
-
-duplexify@^3.4.2, duplexify@^3.6.0:
- version "3.7.1"
- resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
- integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
- dependencies:
- end-of-stream "^1.0.0"
- inherits "^2.0.1"
- readable-stream "^2.0.0"
- stream-shift "^1.0.0"
-
-ee-first@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
- integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
-
-ejs@^2.6.1:
- version "2.7.4"
- resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba"
- integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==
-
-electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.723:
- version "1.3.762"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.762.tgz#3fa4e3bcbda539b50e3aa23041627063a5cffe61"
- integrity sha512-LehWjRpfPcK8F1Lf/NZoAwWLWnjJVo0SZeQ9j/tvnBWYcT99qDqgo4raAfS2oTKZjPrR/jxruh85DGgDUmywEA==
-
-elliptic@^6.5.3:
- version "6.5.4"
- resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
- integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
- dependencies:
- bn.js "^4.11.9"
- brorand "^1.1.0"
- hash.js "^1.0.0"
- hmac-drbg "^1.0.1"
- inherits "^2.0.4"
- minimalistic-assert "^1.0.1"
- minimalistic-crypto-utils "^1.0.1"
-
-"emoji-regex@>=6.0.0 <=6.1.1":
- version "6.1.1"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.1.1.tgz#c6cd0ec1b0642e2a3c67a1137efc5e796da4f88e"
- integrity sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4=
-
-emoji-regex@^7.0.1:
- version "7.0.3"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
- integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
-
-emoji-regex@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
- integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
-
-emojis-list@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
- integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
-
-emojis-list@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
- integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
-
-emoticon@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/emoticon/-/emoticon-3.2.0.tgz#c008ca7d7620fac742fe1bf4af8ff8fed154ae7f"
- integrity sha512-SNujglcLTTg+lDAcApPNgEdudaqQFiAbJCqzjNxJkvN9vAwCGi0uu8IUVvx+f16h+V44KCY6Y2yboroc9pilHg==
-
-encodeurl@~1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
- integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
-
-end-of-stream@^1.0.0, end-of-stream@^1.1.0:
- version "1.4.4"
- resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
- integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
- dependencies:
- once "^1.4.0"
-
-enhanced-resolve@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec"
- integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==
- dependencies:
- graceful-fs "^4.1.2"
- memory-fs "^0.5.0"
- tapable "^1.0.0"
-
-entities@^1.1.1, entities@~1.1.1:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
- integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
-
-entities@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
- integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
-
-errno@^0.1.3, errno@~0.1.7:
- version "0.1.8"
- resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f"
- integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==
- dependencies:
- prr "~1.0.1"
-
-error-ex@^1.3.1:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
- integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
- dependencies:
- is-arrayish "^0.2.1"
-
-es-abstract@^1.17.2, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2:
- version "1.18.3"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.3.tgz#25c4c3380a27aa203c44b2b685bba94da31b63e0"
- integrity sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==
- dependencies:
- call-bind "^1.0.2"
- es-to-primitive "^1.2.1"
- function-bind "^1.1.1"
- get-intrinsic "^1.1.1"
- has "^1.0.3"
- has-symbols "^1.0.2"
- is-callable "^1.2.3"
- is-negative-zero "^2.0.1"
- is-regex "^1.1.3"
- is-string "^1.0.6"
- object-inspect "^1.10.3"
- object-keys "^1.1.1"
- object.assign "^4.1.2"
- string.prototype.trimend "^1.0.4"
- string.prototype.trimstart "^1.0.4"
- unbox-primitive "^1.0.1"
-
-es-to-primitive@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
- integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
- dependencies:
- is-callable "^1.1.4"
- is-date-object "^1.0.1"
- is-symbol "^1.0.2"
-
-escalade@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
- integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
-
-escape-goat@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
- integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
-
-escape-html@^1.0.3, escape-html@~1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
- integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
-
-escape-string-regexp@2.0.0, escape-string-regexp@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
- integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
-
-escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
- integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
-
-eslint-scope@^4.0.3:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
- integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==
- dependencies:
- esrecurse "^4.1.0"
- estraverse "^4.1.1"
-
-esprima@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
- integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
-
-esrecurse@^4.1.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
- integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
- dependencies:
- estraverse "^5.2.0"
-
-estraverse@^4.1.1:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
- integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
-
-estraverse@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
- integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
-
-esutils@^2.0.2:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
- integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
-
-eta@^1.1.1:
- version "1.12.2"
- resolved "https://registry.yarnpkg.com/eta/-/eta-1.12.2.tgz#ac4425d4f9478a8b4110c7d02c94f6d382cac517"
- integrity sha512-Z05sK2DRWAfBhG/2cwAOWuMoQIYaVYJCQrz2g2O/ekUjzWHNBv9L1pnblVDoDkKSb/AZ5tWZ0N/v4iaIU4+HjA==
-
-etag@~1.8.1:
- version "1.8.1"
- resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
- integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
-
-eval@^0.1.4:
- version "0.1.6"
- resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.6.tgz#9620d7d8c85515e97e6b47c5814f46ae381cb3cc"
- integrity sha512-o0XUw+5OGkXw4pJZzQoXUk+H87DHuC+7ZE//oSrRGtatTmr12oTnLfg6QOq9DyTt0c/p4TwzgmkKrBzWTSizyQ==
- dependencies:
- require-like ">= 0.1.1"
-
-eventemitter3@^4.0.0:
- version "4.0.7"
- resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
- integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
-
-events@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
- integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=
-
-events@^3.0.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
- integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
-
-eventsource@^1.0.7:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf"
- integrity sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==
- dependencies:
- original "^1.0.0"
-
-evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02"
- integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==
- dependencies:
- md5.js "^1.3.4"
- safe-buffer "^5.1.1"
-
-execa@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
- integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
- dependencies:
- cross-spawn "^6.0.0"
- get-stream "^4.0.0"
- is-stream "^1.1.0"
- npm-run-path "^2.0.0"
- p-finally "^1.0.0"
- signal-exit "^3.0.0"
- strip-eof "^1.0.0"
-
-execa@^3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89"
- integrity sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==
- dependencies:
- cross-spawn "^7.0.0"
- get-stream "^5.0.0"
- human-signals "^1.1.1"
- is-stream "^2.0.0"
- merge-stream "^2.0.0"
- npm-run-path "^4.0.0"
- onetime "^5.1.0"
- p-finally "^2.0.0"
- signal-exit "^3.0.2"
- strip-final-newline "^2.0.0"
-
-expand-brackets@^2.1.4:
- version "2.1.4"
- resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
- integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI=
- dependencies:
- debug "^2.3.3"
- define-property "^0.2.5"
- extend-shallow "^2.0.1"
- posix-character-classes "^0.1.0"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.1"
-
-express@^4.16.3, express@^4.17.1:
- version "4.17.1"
- resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
- integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
- dependencies:
- accepts "~1.3.7"
- array-flatten "1.1.1"
- body-parser "1.19.0"
- content-disposition "0.5.3"
- content-type "~1.0.4"
- cookie "0.4.0"
- cookie-signature "1.0.6"
- debug "2.6.9"
- depd "~1.1.2"
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- etag "~1.8.1"
- finalhandler "~1.1.2"
- fresh "0.5.2"
- merge-descriptors "1.0.1"
- methods "~1.1.2"
- on-finished "~2.3.0"
- parseurl "~1.3.3"
- path-to-regexp "0.1.7"
- proxy-addr "~2.0.5"
- qs "6.7.0"
- range-parser "~1.2.1"
- safe-buffer "5.1.2"
- send "0.17.1"
- serve-static "1.14.1"
- setprototypeof "1.1.1"
- statuses "~1.5.0"
- type-is "~1.6.18"
- utils-merge "1.0.1"
- vary "~1.1.2"
-
-extend-shallow@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
- integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
- dependencies:
- is-extendable "^0.1.0"
-
-extend-shallow@^3.0.0, extend-shallow@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
- integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=
- dependencies:
- assign-symbols "^1.0.0"
- is-extendable "^1.0.1"
-
-extend@^3.0.0:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
- integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
-
-external-editor@^3.0.3:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
- integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
- dependencies:
- chardet "^0.7.0"
- iconv-lite "^0.4.24"
- tmp "^0.0.33"
-
-extglob@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
- integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
- dependencies:
- array-unique "^0.3.2"
- define-property "^1.0.0"
- expand-brackets "^2.1.4"
- extend-shallow "^2.0.1"
- fragment-cache "^0.2.1"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.1"
-
-fast-deep-equal@^3.1.1:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
- integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-
-fast-glob@^2.0.2:
- version "2.2.7"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
- integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==
- dependencies:
- "@mrmlnc/readdir-enhanced" "^2.2.1"
- "@nodelib/fs.stat" "^1.1.2"
- glob-parent "^3.1.0"
- is-glob "^4.0.0"
- merge2 "^1.2.3"
- micromatch "^3.1.10"
-
-fast-glob@^3.0.3, fast-glob@^3.1.1, fast-glob@^3.2.4:
- version "3.2.6"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.6.tgz#434dd9529845176ea049acc9343e8282765c6e1a"
- integrity sha512-GnLuqj/pvQ7pX8/L4J84nijv6sAnlwvSDpMkJi9i7nPmPxGtRPkBSStfvDW5l6nMdX9VWe+pkKWFTgD+vF2QSQ==
- 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-stable-stringify@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
- integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
-
-fast-url-parser@1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d"
- integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=
- dependencies:
- punycode "^1.3.2"
-
-fastq@^1.6.0:
- version "1.11.0"
- resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.0.tgz#bb9fb955a07130a918eb63c1f5161cc32a5d0858"
- integrity sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==
- dependencies:
- reusify "^1.0.4"
-
-faye-websocket@^0.11.3:
- version "0.11.4"
- resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da"
- integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==
- dependencies:
- websocket-driver ">=0.5.1"
-
-fbemitter@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-3.0.0.tgz#00b2a1af5411254aab416cd75f9e6289bee4bff3"
- integrity sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==
- dependencies:
- fbjs "^3.0.0"
-
-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"
- integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==
-
-fbjs@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.0.tgz#0907067fb3f57a78f45d95f1eacffcacd623c165"
- integrity sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg==
- dependencies:
- cross-fetch "^3.0.4"
- fbjs-css-vars "^1.0.0"
- loose-envify "^1.0.0"
- object-assign "^4.1.0"
- promise "^7.1.1"
- setimmediate "^1.0.5"
- ua-parser-js "^0.7.18"
-
-feed@^4.1.0:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/feed/-/feed-4.2.2.tgz#865783ef6ed12579e2c44bbef3c9113bc4956a7e"
- integrity sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==
- dependencies:
- xml-js "^1.6.11"
-
-figgy-pudding@^3.5.1:
- version "3.5.2"
- resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e"
- integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==
-
-figures@^3.0.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
- integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
- dependencies:
- escape-string-regexp "^1.0.5"
-
-file-loader@^6.0.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d"
- integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==
- dependencies:
- loader-utils "^2.0.0"
- schema-utils "^3.0.0"
-
-file-uri-to-path@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
- integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
-
-filesize@6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.0.1.tgz#f850b509909c7c86f7e450ea19006c31c2ed3d2f"
- integrity sha512-u4AYWPgbI5GBhs6id1KdImZWn5yfyFrrQ8OWZdN7ZMfA8Bf4HcO0BGo9bmUIEV8yrp8I1xVfJ/dn90GtFNNJcg==
-
-filesize@^3.6.1:
- version "3.6.1"
- resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317"
- integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==
-
-fill-range@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
- integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=
- dependencies:
- extend-shallow "^2.0.1"
- is-number "^3.0.0"
- repeat-string "^1.6.1"
- to-regex-range "^2.1.0"
-
-fill-range@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
- integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
- dependencies:
- to-regex-range "^5.0.1"
-
-finalhandler@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
- integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
- dependencies:
- debug "2.6.9"
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- on-finished "~2.3.0"
- parseurl "~1.3.3"
- statuses "~1.5.0"
- unpipe "~1.0.0"
-
-find-cache-dir@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7"
- integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==
- dependencies:
- commondir "^1.0.1"
- make-dir "^2.0.0"
- pkg-dir "^3.0.0"
-
-find-cache-dir@^3.0.0, find-cache-dir@^3.3.1:
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880"
- integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==
- dependencies:
- commondir "^1.0.1"
- make-dir "^3.0.2"
- pkg-dir "^4.1.0"
-
-find-up@4.1.0, find-up@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
- integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
- dependencies:
- locate-path "^5.0.0"
- path-exists "^4.0.0"
-
-find-up@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
- integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
- dependencies:
- locate-path "^3.0.0"
-
-flatten@^1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b"
- integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==
-
-flush-write-stream@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
- integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==
- dependencies:
- inherits "^2.0.3"
- readable-stream "^2.3.6"
-
-flux@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.1.tgz#7843502b02841d4aaa534af0b373034a1f75ee5c"
- integrity sha512-emk4RCvJ8RzNP2lNpphKnG7r18q8elDYNAPx7xn+bDeOIo9FFfxEfIQ2y6YbQNmnsGD3nH1noxtLE64Puz1bRQ==
- dependencies:
- fbemitter "^3.0.0"
- fbjs "^3.0.0"
-
-follow-redirects@^1.0.0:
- version "1.14.7"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
- integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
-
-for-in@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
- integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
-
-fork-ts-checker-webpack-plugin@3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz#a1642c0d3e65f50c2cc1742e9c0a80f441f86b19"
- integrity sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ==
- dependencies:
- babel-code-frame "^6.22.0"
- chalk "^2.4.1"
- chokidar "^3.3.0"
- micromatch "^3.1.10"
- minimatch "^3.0.4"
- semver "^5.6.0"
- tapable "^1.0.0"
- worker-rpc "^0.1.0"
-
-forwarded@0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
- integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
-
-fragment-cache@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
- integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=
- dependencies:
- map-cache "^0.2.2"
-
-fresh@0.5.2:
- version "0.5.2"
- resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
- integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
-
-from2@^2.1.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
- integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=
- dependencies:
- inherits "^2.0.1"
- readable-stream "^2.0.0"
-
-fs-extra@^8.1.0:
- version "8.1.0"
- resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
- integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
- dependencies:
- graceful-fs "^4.2.0"
- jsonfile "^4.0.0"
- universalify "^0.1.0"
-
-fs-minipass@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
- integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
- dependencies:
- minipass "^3.0.0"
-
-fs-write-stream-atomic@^1.0.8:
- version "1.0.10"
- resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9"
- integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=
- dependencies:
- graceful-fs "^4.1.2"
- iferr "^0.1.5"
- imurmurhash "^0.1.4"
- readable-stream "1 || 2"
-
-fs.realpath@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
- integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
-
-fsevents@^1.2.7:
- version "1.2.13"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38"
- integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==
- dependencies:
- bindings "^1.5.0"
- nan "^2.12.1"
-
-fsevents@~2.3.2:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
- integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
-
-function-bind@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
- integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
-
-gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2:
- version "1.0.0-beta.2"
- resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
- integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
-
-get-caller-file@^2.0.1:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
- integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
-
-get-intrinsic@^1.0.2, get-intrinsic@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
- integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
- dependencies:
- function-bind "^1.1.1"
- has "^1.0.3"
- has-symbols "^1.0.1"
-
-get-own-enumerable-property-symbols@^3.0.0:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
- integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==
-
-get-stream@^4.0.0, get-stream@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
- integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
- dependencies:
- pump "^3.0.0"
-
-get-stream@^5.0.0, get-stream@^5.1.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
- integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
- dependencies:
- pump "^3.0.0"
-
-get-value@^2.0.3, get-value@^2.0.6:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
- integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
-
-github-slugger@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.3.0.tgz#9bd0a95c5efdfc46005e82a906ef8e2a059124c9"
- integrity sha512-gwJScWVNhFYSRDvURk/8yhcFBee6aFjye2a7Lhb2bUyRulpIoek9p0I9Kt7PT67d/nUlZbFu8L9RLiA0woQN8Q==
- dependencies:
- emoji-regex ">=6.0.0 <=6.1.1"
-
-glob-parent@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
- integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
- dependencies:
- is-glob "^3.1.0"
- path-dirname "^1.0.0"
-
-glob-parent@^5.1.1, glob-parent@^5.1.2, 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==
- dependencies:
- is-glob "^4.0.1"
-
-glob-to-regexp@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
- integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
-
-glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
- integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.4"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-global-dirs@^2.0.1:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d"
- integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==
- dependencies:
- ini "1.3.7"
-
-global-modules@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
- integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==
- dependencies:
- global-prefix "^3.0.0"
-
-global-prefix@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97"
- integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==
- dependencies:
- ini "^1.3.5"
- kind-of "^6.0.2"
- which "^1.3.1"
-
-globals@^11.1.0:
- version "11.12.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
- integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
-
-globby@8.0.2:
- version "8.0.2"
- resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d"
- integrity sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==
- dependencies:
- array-union "^1.0.1"
- dir-glob "2.0.0"
- fast-glob "^2.0.2"
- glob "^7.1.2"
- ignore "^3.3.5"
- pify "^3.0.0"
- slash "^1.0.0"
-
-globby@^10.0.1:
- version "10.0.2"
- resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543"
- integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==
- dependencies:
- "@types/glob" "^7.1.1"
- array-union "^2.1.0"
- dir-glob "^3.0.1"
- fast-glob "^3.0.3"
- glob "^7.1.3"
- ignore "^5.1.1"
- merge2 "^1.2.3"
- slash "^3.0.0"
-
-globby@^11.0.1:
- version "11.0.4"
- resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5"
- integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==
- dependencies:
- array-union "^2.1.0"
- dir-glob "^3.0.1"
- fast-glob "^3.1.1"
- ignore "^5.1.4"
- merge2 "^1.3.0"
- slash "^3.0.0"
-
-globby@^6.1.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
- integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=
- dependencies:
- array-union "^1.0.1"
- glob "^7.0.3"
- object-assign "^4.0.1"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
-
-got@^9.6.0:
- version "9.6.0"
- resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
- integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==
- dependencies:
- "@sindresorhus/is" "^0.14.0"
- "@szmarczak/http-timer" "^1.1.2"
- cacheable-request "^6.0.0"
- decompress-response "^3.3.0"
- duplexer3 "^0.1.4"
- get-stream "^4.1.0"
- lowercase-keys "^1.0.1"
- mimic-response "^1.0.1"
- p-cancelable "^1.0.0"
- to-readable-stream "^1.0.0"
- url-parse-lax "^3.0.0"
-
-graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2:
- version "4.2.6"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
- integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
-
-gray-matter@^4.0.2:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798"
- integrity sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==
- dependencies:
- js-yaml "^3.13.1"
- kind-of "^6.0.2"
- section-matter "^1.0.0"
- strip-bom-string "^1.0.0"
-
-gzip-size@5.1.1, gzip-size@^5.0.0:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274"
- integrity sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==
- dependencies:
- duplexer "^0.1.1"
- pify "^4.0.1"
-
-handle-thing@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e"
- integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==
-
-has-ansi@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
- integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
- dependencies:
- ansi-regex "^2.0.0"
-
-has-bigints@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113"
- integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==
-
-has-flag@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
- integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
-
-has-flag@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
- integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-
-has-symbols@^1.0.1, has-symbols@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423"
- integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
-
-has-value@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
- integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=
- dependencies:
- get-value "^2.0.3"
- has-values "^0.1.4"
- isobject "^2.0.0"
-
-has-value@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
- integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=
- dependencies:
- get-value "^2.0.6"
- has-values "^1.0.0"
- isobject "^3.0.0"
-
-has-values@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
- integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E=
-
-has-values@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
- integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=
- dependencies:
- is-number "^3.0.0"
- kind-of "^4.0.0"
-
-has-yarn@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77"
- integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==
-
-has@^1.0.0, has@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
- integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
- dependencies:
- function-bind "^1.1.1"
-
-hash-base@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33"
- integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==
- dependencies:
- inherits "^2.0.4"
- readable-stream "^3.6.0"
- safe-buffer "^5.2.0"
-
-hash.js@^1.0.0, hash.js@^1.0.3:
- version "1.1.7"
- resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
- integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==
- dependencies:
- inherits "^2.0.3"
- minimalistic-assert "^1.0.1"
-
-hast-to-hyperscript@^9.0.0:
- version "9.0.1"
- resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz#9b67fd188e4c81e8ad66f803855334173920218d"
- integrity sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==
- dependencies:
- "@types/unist" "^2.0.3"
- comma-separated-tokens "^1.0.0"
- property-information "^5.3.0"
- space-separated-tokens "^1.0.0"
- style-to-object "^0.3.0"
- unist-util-is "^4.0.0"
- web-namespaces "^1.0.0"
-
-hast-util-from-parse5@^5.0.0:
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-5.0.3.tgz#3089dc0ee2ccf6ec8bc416919b51a54a589e097c"
- integrity sha512-gOc8UB99F6eWVWFtM9jUikjN7QkWxB3nY0df5Z0Zq1/Nkwl5V4hAAsl0tmwlgWl/1shlTF8DnNYLO8X6wRV9pA==
- dependencies:
- ccount "^1.0.3"
- hastscript "^5.0.0"
- property-information "^5.0.0"
- web-namespaces "^1.1.2"
- xtend "^4.0.1"
-
-hast-util-from-parse5@^6.0.0:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz#554e34abdeea25ac76f5bd950a1f0180e0b3bc2a"
- integrity sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==
- dependencies:
- "@types/parse5" "^5.0.0"
- hastscript "^6.0.0"
- property-information "^5.0.0"
- vfile "^4.0.0"
- vfile-location "^3.2.0"
- web-namespaces "^1.0.0"
-
-hast-util-parse-selector@^2.0.0:
- version "2.2.5"
- resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a"
- integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==
-
-hast-util-raw@6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/hast-util-raw/-/hast-util-raw-6.0.1.tgz#973b15930b7529a7b66984c98148b46526885977"
- integrity sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==
- dependencies:
- "@types/hast" "^2.0.0"
- hast-util-from-parse5 "^6.0.0"
- hast-util-to-parse5 "^6.0.0"
- html-void-elements "^1.0.0"
- parse5 "^6.0.0"
- unist-util-position "^3.0.0"
- vfile "^4.0.0"
- web-namespaces "^1.0.0"
- xtend "^4.0.0"
- zwitch "^1.0.0"
-
-hast-util-to-parse5@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz#1ec44650b631d72952066cea9b1445df699f8479"
- integrity sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==
- dependencies:
- hast-to-hyperscript "^9.0.0"
- property-information "^5.0.0"
- web-namespaces "^1.0.0"
- xtend "^4.0.0"
- zwitch "^1.0.0"
-
-hastscript@^5.0.0:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-5.1.2.tgz#bde2c2e56d04c62dd24e8c5df288d050a355fb8a"
- integrity sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ==
- dependencies:
- comma-separated-tokens "^1.0.0"
- hast-util-parse-selector "^2.0.0"
- property-information "^5.0.0"
- space-separated-tokens "^1.0.0"
-
-hastscript@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640"
- integrity sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==
- dependencies:
- "@types/hast" "^2.0.0"
- comma-separated-tokens "^1.0.0"
- hast-util-parse-selector "^2.0.0"
- property-information "^5.0.0"
- space-separated-tokens "^1.0.0"
-
-he@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
- integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
-
-hex-color-regex@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
- integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
-
-history@^4.9.0:
- version "4.10.1"
- resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3"
- integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==
- dependencies:
- "@babel/runtime" "^7.1.2"
- loose-envify "^1.2.0"
- resolve-pathname "^3.0.0"
- tiny-invariant "^1.0.2"
- tiny-warning "^1.0.0"
- value-equal "^1.0.1"
-
-hmac-drbg@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
- integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=
- dependencies:
- hash.js "^1.0.3"
- minimalistic-assert "^1.0.0"
- minimalistic-crypto-utils "^1.0.1"
-
-hoist-non-react-statics@^3.1.0:
- version "3.3.2"
- resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
- integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
- dependencies:
- react-is "^16.7.0"
-
-hoopy@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d"
- integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==
-
-hpack.js@^2.1.6:
- version "2.1.6"
- resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
- integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=
- dependencies:
- inherits "^2.0.1"
- obuf "^1.0.0"
- readable-stream "^2.0.1"
- wbuf "^1.1.0"
-
-hsl-regex@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e"
- integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=
-
-hsla-regex@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38"
- integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg=
-
-html-entities@^1.3.1:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc"
- integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==
-
-html-minifier-terser@^5.0.1, html-minifier-terser@^5.0.5:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#922e96f1f3bb60832c2634b79884096389b1f054"
- integrity sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==
- dependencies:
- camel-case "^4.1.1"
- clean-css "^4.2.3"
- commander "^4.1.1"
- he "^1.2.0"
- param-case "^3.0.3"
- relateurl "^0.2.7"
- terser "^4.6.3"
-
-html-tags@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140"
- integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==
-
-html-void-elements@^1.0.0:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-1.0.5.tgz#ce9159494e86d95e45795b166c2021c2cfca4483"
- integrity sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==
-
-html-webpack-plugin@^4.0.4:
- version "4.5.2"
- resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz#76fc83fa1a0f12dd5f7da0404a54e2699666bc12"
- integrity sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==
- dependencies:
- "@types/html-minifier-terser" "^5.0.0"
- "@types/tapable" "^1.0.5"
- "@types/webpack" "^4.41.8"
- html-minifier-terser "^5.0.1"
- loader-utils "^1.2.3"
- lodash "^4.17.20"
- pretty-error "^2.1.1"
- tapable "^1.1.3"
- util.promisify "1.0.0"
-
-htmlparser2@^3.9.1:
- version "3.10.1"
- resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
- integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==
- dependencies:
- domelementtype "^1.3.1"
- domhandler "^2.3.0"
- domutils "^1.5.1"
- entities "^1.1.1"
- inherits "^2.0.1"
- readable-stream "^3.1.1"
-
-htmlparser2@^6.1.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
- integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
- dependencies:
- domelementtype "^2.0.1"
- domhandler "^4.0.0"
- domutils "^2.5.2"
- entities "^2.0.0"
-
-http-cache-semantics@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
- integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
-
-http-deceiver@^1.2.7:
- version "1.2.7"
- resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
- integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=
-
-http-errors@1.7.2:
- version "1.7.2"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
- integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
- dependencies:
- depd "~1.1.2"
- inherits "2.0.3"
- setprototypeof "1.1.1"
- statuses ">= 1.5.0 < 2"
- toidentifier "1.0.0"
-
-http-errors@~1.6.2:
- version "1.6.3"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
- integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
- dependencies:
- depd "~1.1.2"
- inherits "2.0.3"
- setprototypeof "1.1.0"
- statuses ">= 1.4.0 < 2"
-
-http-errors@~1.7.2:
- version "1.7.3"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
- integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
- dependencies:
- depd "~1.1.2"
- inherits "2.0.4"
- setprototypeof "1.1.1"
- statuses ">= 1.5.0 < 2"
- toidentifier "1.0.0"
-
-http-parser-js@>=0.5.1:
- version "0.5.3"
- resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9"
- integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==
-
-http-proxy-middleware@0.19.1:
- version "0.19.1"
- resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a"
- integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==
- dependencies:
- http-proxy "^1.17.0"
- is-glob "^4.0.0"
- lodash "^4.17.11"
- micromatch "^3.1.10"
-
-http-proxy@^1.17.0:
- version "1.18.1"
- resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
- integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
- dependencies:
- eventemitter3 "^4.0.0"
- follow-redirects "^1.0.0"
- requires-port "^1.0.0"
-
-https-browserify@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
- integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
-
-human-signals@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
- integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
-
-iconv-lite@0.4.24, iconv-lite@^0.4.24:
- version "0.4.24"
- resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
- integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
- dependencies:
- safer-buffer ">= 2.1.2 < 3"
-
-icss-utils@^4.0.0, icss-utils@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467"
- integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==
- dependencies:
- postcss "^7.0.14"
-
-ieee754@^1.1.4:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
- integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
-
-iferr@^0.1.5:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
- integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE=
-
-ignore@^3.3.5:
- version "3.3.10"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
- integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==
-
-ignore@^5.1.1, ignore@^5.1.4:
- version "5.1.8"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
- integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
-
-immer@1.10.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d"
- integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==
-
-import-cwd@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
- integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=
- dependencies:
- import-from "^2.1.0"
-
-import-fresh@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
- integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY=
- dependencies:
- caller-path "^2.0.0"
- resolve-from "^3.0.0"
-
-import-fresh@^3.2.1:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
- integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
- dependencies:
- parent-module "^1.0.0"
- resolve-from "^4.0.0"
-
-import-from@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1"
- integrity sha1-M1238qev/VOqpHHUuAId7ja387E=
- dependencies:
- resolve-from "^3.0.0"
-
-import-lazy@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
- integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
-
-import-local@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
- integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==
- dependencies:
- pkg-dir "^3.0.0"
- resolve-cwd "^2.0.0"
-
-imurmurhash@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
- integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
-
-indent-string@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
- integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
-
-indexes-of@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
- integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc=
-
-infer-owner@^1.0.3, infer-owner@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
- integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
-
-infima@0.2.0-alpha.13:
- version "0.2.0-alpha.13"
- resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.13.tgz#2d28a4cf0af988abe804cdab34652df921201055"
- integrity sha512-BxCZ1pMcUF0PcL4WV07l/lvaeBBdUUw7uVqNyyeGAutzDpkDyFOl5gOv9wFAJKLo5yerPNFXxFPgDitNjctqIA==
-
-inflight@^1.0.4:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
- integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
- dependencies:
- once "^1.3.0"
- wrappy "1"
-
-inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
- integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-
-inherits@2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
- integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=
-
-inherits@2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
- integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
-
-ini@1.3.7:
- version "1.3.7"
- resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84"
- integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==
-
-ini@^1.3.5, ini@~1.3.0:
- version "1.3.8"
- resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
- integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
-
-inline-style-parser@0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1"
- integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==
-
-inquirer@7.0.4:
- version "7.0.4"
- resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.4.tgz#99af5bde47153abca23f5c7fc30db247f39da703"
- integrity sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==
- dependencies:
- ansi-escapes "^4.2.1"
- chalk "^2.4.2"
- cli-cursor "^3.1.0"
- cli-width "^2.0.0"
- external-editor "^3.0.3"
- figures "^3.0.0"
- lodash "^4.17.15"
- mute-stream "0.0.8"
- run-async "^2.2.0"
- rxjs "^6.5.3"
- string-width "^4.1.0"
- strip-ansi "^5.1.0"
- through "^2.3.6"
-
-inquirer@^7.2.0:
- version "7.3.3"
- resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003"
- integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==
- dependencies:
- ansi-escapes "^4.2.1"
- chalk "^4.1.0"
- cli-cursor "^3.1.0"
- cli-width "^3.0.0"
- external-editor "^3.0.3"
- figures "^3.0.0"
- lodash "^4.17.19"
- mute-stream "0.0.8"
- run-async "^2.4.0"
- rxjs "^6.6.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
- through "^2.3.6"
-
-internal-ip@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907"
- integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==
- dependencies:
- default-gateway "^4.2.0"
- ipaddr.js "^1.9.0"
-
-interpret@^1.0.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
- integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
-
-ip-regex@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
- integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=
-
-ip@^1.1.0, ip@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
- integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
-
-ipaddr.js@1.9.1, ipaddr.js@^1.9.0:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
- integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
-
-is-absolute-url@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
- integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=
-
-is-absolute-url@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698"
- integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==
-
-is-accessor-descriptor@^0.1.6:
- version "0.1.6"
- resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
- integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=
- dependencies:
- kind-of "^3.0.2"
-
-is-accessor-descriptor@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
- integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==
- dependencies:
- kind-of "^6.0.0"
-
-is-alphabetical@1.0.4, is-alphabetical@^1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d"
- integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==
-
-is-alphanumerical@^1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf"
- integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==
- dependencies:
- is-alphabetical "^1.0.0"
- is-decimal "^1.0.0"
-
-is-arguments@^1.0.4:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9"
- integrity sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==
- dependencies:
- call-bind "^1.0.0"
-
-is-arrayish@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
- integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
-
-is-arrayish@^0.3.1:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
- integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
-
-is-bigint@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.2.tgz#ffb381442503235ad245ea89e45b3dbff040ee5a"
- integrity sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==
-
-is-binary-path@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
- integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=
- dependencies:
- binary-extensions "^1.0.0"
-
-is-binary-path@~2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
- integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
- dependencies:
- binary-extensions "^2.0.0"
-
-is-boolean-object@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.1.tgz#3c0878f035cb821228d350d2e1e36719716a3de8"
- integrity sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==
- dependencies:
- call-bind "^1.0.2"
-
-is-buffer@^1.1.5:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
- integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
-
-is-buffer@^2.0.0:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
- integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
-
-is-callable@^1.1.4, is-callable@^1.2.3:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e"
- integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==
-
-is-ci@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
- integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==
- dependencies:
- ci-info "^2.0.0"
-
-is-color-stop@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345"
- integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=
- dependencies:
- css-color-names "^0.0.4"
- hex-color-regex "^1.1.0"
- hsl-regex "^1.0.0"
- hsla-regex "^1.0.0"
- rgb-regex "^1.0.1"
- rgba-regex "^1.0.0"
-
-is-core-module@^2.2.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1"
- integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==
- dependencies:
- has "^1.0.3"
-
-is-core-module@^2.8.0:
- version "2.8.1"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211"
- integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==
- dependencies:
- has "^1.0.3"
-
-is-data-descriptor@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
- integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=
- dependencies:
- kind-of "^3.0.2"
-
-is-data-descriptor@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
- integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==
- dependencies:
- kind-of "^6.0.0"
-
-is-date-object@^1.0.1:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.4.tgz#550cfcc03afada05eea3dd30981c7b09551f73e5"
- integrity sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==
-
-is-decimal@^1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5"
- integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==
-
-is-descriptor@^0.1.0:
- version "0.1.6"
- resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
- integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==
- dependencies:
- is-accessor-descriptor "^0.1.6"
- is-data-descriptor "^0.1.4"
- kind-of "^5.0.0"
-
-is-descriptor@^1.0.0, is-descriptor@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
- integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==
- dependencies:
- is-accessor-descriptor "^1.0.0"
- is-data-descriptor "^1.0.0"
- kind-of "^6.0.2"
-
-is-directory@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
- integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=
-
-is-docker@^2.0.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
- integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
-
-is-extendable@^0.1.0, is-extendable@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
- integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
-
-is-extendable@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
- integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
- dependencies:
- is-plain-object "^2.0.4"
-
-is-extglob@^2.1.0, is-extglob@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
- integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
-
-is-fullwidth-code-point@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
- integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
-
-is-fullwidth-code-point@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
- integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
-
-is-glob@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
- integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
- dependencies:
- is-extglob "^2.1.0"
-
-is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
- integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
- dependencies:
- is-extglob "^2.1.1"
-
-is-hexadecimal@^1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7"
- integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==
-
-is-installed-globally@^0.3.1:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141"
- integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==
- dependencies:
- global-dirs "^2.0.1"
- is-path-inside "^3.0.1"
-
-is-negative-zero@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
- integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==
-
-is-npm@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d"
- integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==
-
-is-number-object@^1.0.4:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.5.tgz#6edfaeed7950cff19afedce9fbfca9ee6dd289eb"
- integrity sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==
-
-is-number@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
- integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=
- dependencies:
- kind-of "^3.0.2"
-
-is-number@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
- integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
-
-is-obj@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
- integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
-
-is-obj@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982"
- integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
-
-is-path-cwd@^2.0.0, is-path-cwd@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb"
- integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==
-
-is-path-in-cwd@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb"
- integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==
- dependencies:
- is-path-inside "^2.1.0"
-
-is-path-inside@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2"
- integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==
- dependencies:
- path-is-inside "^1.0.2"
-
-is-path-inside@^3.0.1:
- 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.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
- integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
-
-is-plain-obj@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
- integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
-
-is-plain-object@^2.0.3, is-plain-object@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
- integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
- dependencies:
- isobject "^3.0.1"
-
-is-regex@^1.0.4, is-regex@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f"
- integrity sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==
- dependencies:
- call-bind "^1.0.2"
- has-symbols "^1.0.2"
-
-is-regexp@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
- integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk=
-
-is-resolvable@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88"
- integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==
-
-is-root@2.1.0, is-root@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c"
- integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==
-
-is-stream@^1.1.0:
- version "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.0"
- resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
- integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
-
-is-string@^1.0.5, is-string@^1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f"
- integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==
-
-is-symbol@^1.0.2, is-symbol@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c"
- integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==
- dependencies:
- has-symbols "^1.0.2"
-
-is-typedarray@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
- integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
-
-is-whitespace-character@^1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7"
- integrity sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==
-
-is-windows@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
- integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
-
-is-word-character@^1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230"
- integrity sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==
-
-is-wsl@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
- integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
-
-is-wsl@^2.1.1:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
- integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
- dependencies:
- is-docker "^2.0.0"
-
-is-yarn-global@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232"
- integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==
-
-isarray@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
- integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
-
-isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
- integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
-
-isexe@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
- integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
-
-isobject@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
- integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
- dependencies:
- isarray "1.0.0"
-
-isobject@^3.0.0, isobject@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
- integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
-
-jest-worker@^26.5.0:
- version "26.6.2"
- resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed"
- integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==
- dependencies:
- "@types/node" "*"
- merge-stream "^2.0.0"
- supports-color "^7.0.0"
-
-"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
- integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-
-js-tokens@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
- integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
-
-js-yaml@^3.13.1:
- version "3.14.1"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
- integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
- dependencies:
- argparse "^1.0.7"
- esprima "^4.0.0"
-
-jsesc@^2.5.1:
- version "2.5.2"
- resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
- integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
-
-jsesc@~0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
- integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
-
-json-buffer@3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
- integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=
-
-json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
- integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
-
-json-parse-even-better-errors@^2.3.0:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
- integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
-
-json-schema-traverse@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
- integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
-
-json3@^3.3.3:
- version "3.3.3"
- resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81"
- integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==
-
-json5@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
- integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
- dependencies:
- minimist "^1.2.0"
-
-json5@^2.1.2:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
- integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
- dependencies:
- minimist "^1.2.5"
-
-jsonfile@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
- integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
- optionalDependencies:
- graceful-fs "^4.1.6"
-
-keyv@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
- integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==
- dependencies:
- json-buffer "3.0.0"
-
-killable@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
- integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==
-
-kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
- version "3.2.2"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
- integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
- dependencies:
- is-buffer "^1.1.5"
-
-kind-of@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
- integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
- dependencies:
- is-buffer "^1.1.5"
-
-kind-of@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
- integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
-
-kind-of@^6.0.0, kind-of@^6.0.2:
- version "6.0.3"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
- integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
-
-last-call-webpack-plugin@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555"
- integrity sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==
- dependencies:
- lodash "^4.17.5"
- webpack-sources "^1.1.0"
-
-latest-version@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face"
- integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==
- dependencies:
- package-json "^6.3.0"
-
-leven@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
- integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
-
-lines-and-columns@^1.1.6:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
- integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
-
-loader-runner@^2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
- integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==
-
-loader-utils@1.2.3:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
- integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==
- dependencies:
- big.js "^5.2.2"
- emojis-list "^2.0.0"
- json5 "^1.0.1"
-
-loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
- integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
- dependencies:
- big.js "^5.2.2"
- emojis-list "^3.0.0"
- json5 "^1.0.1"
-
-loader-utils@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0"
- integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==
- dependencies:
- big.js "^5.2.2"
- emojis-list "^3.0.0"
- json5 "^2.1.2"
-
-locate-path@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
- integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
- dependencies:
- p-locate "^3.0.0"
- path-exists "^3.0.0"
-
-locate-path@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
- integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
- dependencies:
- p-locate "^4.1.0"
-
-lodash.assignin@^4.0.9:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2"
- integrity sha1-uo31+4QesKPoBEIysOJjqNxqKKI=
-
-lodash.bind@^4.1.4:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35"
- integrity sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=
-
-lodash.camelcase@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
- integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
-
-lodash.chunk@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.chunk/-/lodash.chunk-4.2.0.tgz#66e5ce1f76ed27b4303d8c6512e8d1216e8106bc"
- integrity sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw=
-
-lodash.curry@^4.0.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170"
- integrity sha1-JI42By7ekGUB11lmIAqG2riyMXA=
-
-lodash.debounce@^4.0.8:
- version "4.0.8"
- resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
- integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
-
-lodash.defaults@^4.0.1:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
- integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
-
-lodash.filter@^4.4.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace"
- integrity sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=
-
-lodash.flatmap@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.flatmap/-/lodash.flatmap-4.5.0.tgz#ef8cbf408f6e48268663345305c6acc0b778702e"
- integrity sha1-74y/QI9uSCaGYzRTBcaswLd4cC4=
-
-lodash.flatten@^4.2.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
- integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
-
-lodash.flow@^3.3.0:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a"
- integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=
-
-lodash.foreach@^4.3.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53"
- integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=
-
-lodash.groupby@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1"
- integrity sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=
-
-lodash.has@^4.5.2:
- version "4.5.2"
- resolved "https://registry.yarnpkg.com/lodash.has/-/lodash.has-4.5.2.tgz#d19f4dc1095058cccbe2b0cdf4ee0fe4aa37c862"
- integrity sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=
-
-lodash.isplainobject@^4.0.6:
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
- integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
-
-lodash.isstring@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
- integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=
-
-lodash.kebabcase@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36"
- integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY=
-
-lodash.map@^4.4.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3"
- integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=
-
-lodash.memoize@^4.1.2:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
- integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
-
-lodash.merge@^4.4.0:
- version "4.6.2"
- resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
- integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-
-lodash.padstart@^4.6.1:
- version "4.6.1"
- resolved "https://registry.yarnpkg.com/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b"
- integrity sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=
-
-lodash.pick@^4.2.1, lodash.pick@^4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
- integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=
-
-lodash.pickby@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff"
- integrity sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=
-
-lodash.reduce@^4.4.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b"
- integrity sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=
-
-lodash.reject@^4.4.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415"
- integrity sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=
-
-lodash.some@^4.4.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"
- integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=
-
-lodash.sortby@^4.6.0, lodash.sortby@^4.7.0:
- version "4.7.0"
- resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
- integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
-
-lodash.toarray@^4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
- integrity sha1-JMS/zWsvuji/0FlNsRedjptlZWE=
-
-lodash.uniq@4.5.0, lodash.uniq@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
- integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
-
-lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.5, lodash@^4.5.2:
- version "4.17.21"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
- integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-
-loglevel@^1.6.8:
- version "1.7.1"
- resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197"
- integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==
-
-loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
- integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
- dependencies:
- js-tokens "^3.0.0 || ^4.0.0"
-
-lower-case@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
- integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
- dependencies:
- tslib "^2.0.3"
-
-lowercase-keys@^1.0.0, lowercase-keys@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
- integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
-
-lowercase-keys@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
- integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
-
-lru-cache@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
- integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
- dependencies:
- yallist "^3.0.2"
-
-lru-cache@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
- integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
- dependencies:
- yallist "^4.0.0"
-
-make-dir@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
- integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==
- dependencies:
- pify "^4.0.1"
- semver "^5.6.0"
-
-make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
- integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
- dependencies:
- semver "^6.0.0"
-
-map-cache@^0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
- integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
-
-map-visit@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
- integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=
- dependencies:
- object-visit "^1.0.0"
-
-markdown-escapes@^1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535"
- integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==
-
-md5.js@^1.3.4:
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
- integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==
- dependencies:
- hash-base "^3.0.0"
- inherits "^2.0.1"
- safe-buffer "^5.1.2"
-
-mdast-squeeze-paragraphs@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz#7c4c114679c3bee27ef10b58e2e015be79f1ef97"
- integrity sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==
- dependencies:
- unist-util-remove "^2.0.0"
-
-mdast-util-definitions@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz#c5c1a84db799173b4dcf7643cda999e440c24db2"
- integrity sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==
- dependencies:
- unist-util-visit "^2.0.0"
-
-mdast-util-to-hast@10.0.1:
- version "10.0.1"
- resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz#0cfc82089494c52d46eb0e3edb7a4eb2aea021eb"
- integrity sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==
- dependencies:
- "@types/mdast" "^3.0.0"
- "@types/unist" "^2.0.0"
- mdast-util-definitions "^4.0.0"
- mdurl "^1.0.0"
- unist-builder "^2.0.0"
- unist-util-generated "^1.0.0"
- unist-util-position "^3.0.0"
- unist-util-visit "^2.0.0"
-
-mdast-util-to-string@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz#27055500103f51637bd07d01da01eb1967a43527"
- integrity sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==
-
-mdn-data@2.0.14:
- version "2.0.14"
- resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
- integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
-
-mdn-data@2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b"
- integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==
-
-mdurl@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
- integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
-
-media-typer@0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
- integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
-
-memory-fs@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
- integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=
- dependencies:
- errno "^0.1.3"
- readable-stream "^2.0.1"
-
-memory-fs@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c"
- integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==
- dependencies:
- errno "^0.1.3"
- readable-stream "^2.0.1"
-
-merge-descriptors@1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
- integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
-
-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.2.3, 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.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
- integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
-
-microevent.ts@~0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0"
- integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==
-
-micromatch@^3.1.10, micromatch@^3.1.4:
- version "3.1.10"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
- integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
- dependencies:
- arr-diff "^4.0.0"
- array-unique "^0.3.2"
- braces "^2.3.1"
- define-property "^2.0.2"
- extend-shallow "^3.0.2"
- extglob "^2.0.4"
- fragment-cache "^0.2.1"
- kind-of "^6.0.2"
- nanomatch "^1.2.9"
- object.pick "^1.3.0"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.2"
-
-micromatch@^4.0.4:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9"
- integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==
- dependencies:
- braces "^3.0.1"
- picomatch "^2.2.3"
-
-miller-rabin@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
- integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==
- dependencies:
- bn.js "^4.0.0"
- brorand "^1.0.1"
-
-mime-db@1.48.0, "mime-db@>= 1.43.0 < 2":
- version "1.48.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d"
- integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==
-
-mime-db@~1.33.0:
- version "1.33.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
- integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==
-
-mime-types@2.1.18:
- version "2.1.18"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
- integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==
- dependencies:
- mime-db "~1.33.0"
-
-mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.24:
- version "2.1.31"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b"
- integrity sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==
- dependencies:
- mime-db "1.48.0"
-
-mime@1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
- integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
-
-mime@^2.4.4:
- version "2.5.2"
- resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe"
- integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==
-
-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==
-
-mimic-response@^1.0.0, mimic-response@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
- integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
-
-mini-create-react-context@^0.4.0:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz#072171561bfdc922da08a60c2197a497cc2d1d5e"
- integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==
- dependencies:
- "@babel/runtime" "^7.12.1"
- tiny-warning "^1.0.3"
-
-mini-css-extract-plugin@^0.8.0:
- version "0.8.2"
- resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.2.tgz#a875e169beb27c88af77dd962771c9eedc3da161"
- integrity sha512-a3Y4of27Wz+mqK3qrcd3VhYz6cU0iW5x3Sgvqzbj+XmlrSizmvu8QQMl5oMYJjgHOC4iyt+w7l4umP+dQeW3bw==
- dependencies:
- loader-utils "^1.1.0"
- normalize-url "1.9.1"
- schema-utils "^1.0.0"
- webpack-sources "^1.1.0"
-
-minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
- integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
-
-minimalistic-crypto-utils@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
- integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
-
-minimatch@3.0.4, minimatch@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
- integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
- dependencies:
- brace-expansion "^1.1.7"
-
-minimist@^1.2.0, minimist@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
-
-minipass-collect@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617"
- integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==
- dependencies:
- minipass "^3.0.0"
-
-minipass-flush@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373"
- integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==
- dependencies:
- minipass "^3.0.0"
-
-minipass-pipeline@^1.2.2:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c"
- integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==
- dependencies:
- minipass "^3.0.0"
-
-minipass@^3.0.0, minipass@^3.1.1:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd"
- integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==
- dependencies:
- yallist "^4.0.0"
-
-minizlib@^2.1.1:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
- integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
- dependencies:
- minipass "^3.0.0"
- yallist "^4.0.0"
-
-mississippi@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022"
- integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==
- dependencies:
- concat-stream "^1.5.0"
- duplexify "^3.4.2"
- end-of-stream "^1.1.0"
- flush-write-stream "^1.0.0"
- from2 "^2.1.0"
- parallel-transform "^1.1.0"
- pump "^3.0.0"
- pumpify "^1.3.3"
- stream-each "^1.1.0"
- through2 "^2.0.0"
-
-mixin-deep@^1.2.0:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
- integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
- dependencies:
- for-in "^1.0.2"
- is-extendable "^1.0.1"
-
-mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1:
- version "0.5.5"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
- integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
- dependencies:
- minimist "^1.2.5"
-
-mkdirp@^1.0.3, mkdirp@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
- integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
-
-move-concurrently@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
- integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=
- dependencies:
- aproba "^1.1.1"
- copy-concurrently "^1.0.0"
- fs-write-stream-atomic "^1.0.8"
- mkdirp "^0.5.1"
- rimraf "^2.5.4"
- run-queue "^1.0.3"
-
-ms@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
- integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
-
-ms@2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
- integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
-
-ms@2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
- integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-
-ms@^2.1.1:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
- integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
-
-multicast-dns-service-types@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901"
- integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=
-
-multicast-dns@^6.0.1:
- version "6.2.3"
- resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229"
- integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==
- dependencies:
- dns-packet "^1.3.1"
- thunky "^1.0.2"
-
-mute-stream@0.0.8:
- version "0.0.8"
- resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
- integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
-
-nan@^2.12.1:
- version "2.14.2"
- resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
- integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
-
-nanomatch@^1.2.9:
- version "1.2.13"
- resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
- integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
- dependencies:
- arr-diff "^4.0.0"
- array-unique "^0.3.2"
- define-property "^2.0.2"
- extend-shallow "^3.0.2"
- fragment-cache "^0.2.1"
- is-windows "^1.0.2"
- kind-of "^6.0.2"
- object.pick "^1.3.0"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.1"
-
-negotiator@0.6.2:
- version "0.6.2"
- resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
- integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
-
-neo-async@^2.5.0, neo-async@^2.6.1:
- version "2.6.2"
- resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
- integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
-
-nice-try@^1.0.4:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
- integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
-
-no-case@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
- integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
- dependencies:
- lower-case "^2.0.2"
- tslib "^2.0.3"
-
-node-emoji@^1.10.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da"
- integrity sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==
- dependencies:
- lodash.toarray "^4.4.0"
-
-node-fetch@2.6.1:
- version "2.6.1"
- resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
- integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
-
-node-forge@^0.10.0:
- version "0.10.0"
- resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
- integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==
-
-node-libs-browser@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
- integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==
- dependencies:
- assert "^1.1.1"
- browserify-zlib "^0.2.0"
- buffer "^4.3.0"
- console-browserify "^1.1.0"
- constants-browserify "^1.0.0"
- crypto-browserify "^3.11.0"
- domain-browser "^1.1.1"
- events "^3.0.0"
- https-browserify "^1.0.0"
- os-browserify "^0.3.0"
- path-browserify "0.0.1"
- process "^0.11.10"
- punycode "^1.2.4"
- querystring-es3 "^0.2.0"
- readable-stream "^2.3.3"
- stream-browserify "^2.0.1"
- stream-http "^2.7.2"
- string_decoder "^1.0.0"
- timers-browserify "^2.0.4"
- tty-browserify "0.0.0"
- url "^0.11.0"
- util "^0.11.0"
- vm-browserify "^1.0.1"
-
-node-releases@^1.1.52, node-releases@^1.1.71:
- version "1.1.73"
- resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.73.tgz#dd4e81ddd5277ff846b80b52bb40c49edf7a7b20"
- integrity sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==
-
-normalize-path@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
- integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
- dependencies:
- remove-trailing-separator "^1.0.1"
-
-normalize-path@^3.0.0, normalize-path@~3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
- integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
-
-normalize-range@^0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
- integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=
-
-normalize-url@1.9.1:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c"
- integrity sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=
- dependencies:
- object-assign "^4.0.1"
- prepend-http "^1.0.0"
- query-string "^4.1.0"
- sort-keys "^1.0.0"
-
-normalize-url@^3.0.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559"
- integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==
-
-normalize-url@^4.1.0:
- version "4.5.1"
- resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a"
- integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==
-
-npm-run-path@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
- integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
- dependencies:
- path-key "^2.0.0"
-
-npm-run-path@^4.0.0:
- 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"
-
-nprogress@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1"
- integrity sha1-y480xTIT2JVyP8urkH6UIq28r7E=
-
-nth-check@^1.0.2, nth-check@~1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c"
- integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==
- dependencies:
- boolbase "~1.0.0"
-
-nth-check@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125"
- integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==
- dependencies:
- boolbase "^1.0.0"
-
-null-loader@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/null-loader/-/null-loader-3.0.0.tgz#3e2b6c663c5bda8c73a54357d8fa0708dc61b245"
- integrity sha512-hf5sNLl8xdRho4UPBOOeoIwT3WhjYcMUQm0zj44EhD6UscMAz72o2udpoDFBgykucdEDGIcd6SXbc/G6zssbzw==
- dependencies:
- loader-utils "^1.2.3"
- schema-utils "^1.0.0"
-
-num2fraction@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
- integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=
-
-object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
- integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
-
-object-copy@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
- integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw=
- dependencies:
- copy-descriptor "^0.1.0"
- define-property "^0.2.5"
- kind-of "^3.0.3"
-
-object-inspect@^1.10.3:
- version "1.10.3"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369"
- integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==
-
-object-is@^1.0.1:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac"
- integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
-
-object-keys@^1.0.12, object-keys@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
- integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
-
-object-visit@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
- integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=
- dependencies:
- isobject "^3.0.0"
-
-object.assign@^4.1.0, object.assign@^4.1.2:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
- integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
- dependencies:
- call-bind "^1.0.0"
- define-properties "^1.1.3"
- has-symbols "^1.0.1"
- object-keys "^1.1.1"
-
-object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7"
- integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.18.0-next.2"
-
-object.pick@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
- integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
- dependencies:
- isobject "^3.0.1"
-
-object.values@^1.1.0:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30"
- integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.18.2"
-
-obuf@^1.0.0, obuf@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
- integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
-
-on-finished@~2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
- integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
- dependencies:
- ee-first "1.1.1"
-
-on-headers@~1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
- integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
-
-once@^1.3.0, once@^1.3.1, once@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
- integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
- dependencies:
- wrappy "1"
-
-onetime@^5.1.0:
- 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"
-
-open@^7.0.2:
- version "7.4.2"
- resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321"
- integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==
- dependencies:
- is-docker "^2.0.0"
- is-wsl "^2.1.1"
-
-opener@^1.5.1:
- version "1.5.2"
- resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598"
- integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==
-
-opn@^5.5.0:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc"
- integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==
- dependencies:
- is-wsl "^1.1.0"
-
-optimize-css-assets-webpack-plugin@^5.0.3:
- version "5.0.8"
- resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.8.tgz#cbccdcf5a6ef61d4f8cc78cf083a67446e5f402a"
- integrity sha512-mgFS1JdOtEGzD8l+EuISqL57cKO+We9GcoiQEmdCWRqqck+FGNmYJtx9qfAPzEz+lRrlThWMuGDaRkI/yWNx/Q==
- dependencies:
- cssnano "^4.1.10"
- last-call-webpack-plugin "^3.0.0"
-
-original@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f"
- integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==
- dependencies:
- url-parse "^1.4.3"
-
-os-browserify@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
- integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=
-
-os-tmpdir@~1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
- integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
-
-p-cancelable@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"
- integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==
-
-p-finally@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
- integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
-
-p-finally@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561"
- integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==
-
-p-limit@^2.0.0, p-limit@^2.2.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
- integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
- dependencies:
- p-try "^2.0.0"
-
-p-limit@^3.0.2:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
- integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
- dependencies:
- yocto-queue "^0.1.0"
-
-p-locate@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
- integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
- dependencies:
- p-limit "^2.0.0"
-
-p-locate@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
- integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
- dependencies:
- p-limit "^2.2.0"
-
-p-map@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
- integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==
-
-p-map@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d"
- integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==
- dependencies:
- aggregate-error "^3.0.0"
-
-p-map@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b"
- integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==
- dependencies:
- aggregate-error "^3.0.0"
-
-p-retry@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328"
- integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==
- dependencies:
- retry "^0.12.0"
-
-p-try@^2.0.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==
-
-package-json@^6.3.0:
- version "6.5.0"
- resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0"
- integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==
- dependencies:
- got "^9.6.0"
- registry-auth-token "^4.0.0"
- registry-url "^5.0.0"
- semver "^6.2.0"
-
-pako@~1.0.5:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
- integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
-
-parallel-transform@^1.1.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc"
- integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==
- dependencies:
- cyclist "^1.0.1"
- inherits "^2.0.3"
- readable-stream "^2.1.5"
-
-param-case@^3.0.3:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5"
- integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==
- dependencies:
- dot-case "^3.0.4"
- tslib "^2.0.3"
-
-parent-module@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
- integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
- dependencies:
- callsites "^3.0.0"
-
-parse-asn1@^5.0.0, parse-asn1@^5.1.5:
- version "5.1.6"
- resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4"
- integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==
- dependencies:
- asn1.js "^5.2.0"
- browserify-aes "^1.0.0"
- evp_bytestokey "^1.0.0"
- pbkdf2 "^3.0.3"
- safe-buffer "^5.1.1"
-
-parse-entities@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8"
- integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==
- dependencies:
- character-entities "^1.0.0"
- character-entities-legacy "^1.0.0"
- character-reference-invalid "^1.0.0"
- is-alphanumerical "^1.0.0"
- is-decimal "^1.0.0"
- is-hexadecimal "^1.0.0"
-
-parse-json@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
- integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=
- dependencies:
- error-ex "^1.3.1"
- json-parse-better-errors "^1.0.1"
-
-parse-json@^5.0.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
- integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
- dependencies:
- "@babel/code-frame" "^7.0.0"
- error-ex "^1.3.1"
- json-parse-even-better-errors "^2.3.0"
- lines-and-columns "^1.1.6"
-
-parse-numeric-range@^0.0.2:
- version "0.0.2"
- resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-0.0.2.tgz#b4f09d413c7adbcd987f6e9233c7b4b210c938e4"
- integrity sha1-tPCdQTx6282Yf26SM8e0shDJOOQ=
-
-parse5@^5.0.0:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178"
- integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==
-
-parse5@^6.0.0:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
- integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
-
-parseurl@~1.3.2, parseurl@~1.3.3:
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
- integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
-
-pascal-case@^3.1.2:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb"
- integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==
- dependencies:
- no-case "^3.0.4"
- tslib "^2.0.3"
-
-pascalcase@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
- integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
-
-path-browserify@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
- integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==
-
-path-dirname@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
- integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
-
-path-exists@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
- integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
-
-path-exists@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
- integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
-
-path-is-absolute@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
- integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
-
-path-is-inside@1.0.2, path-is-inside@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
- integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
-
-path-key@^2.0.0, path-key@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
- integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
-
-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==
-
-path-parse@^1.0.6, path-parse@^1.0.7:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
- integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
-
-path-to-regexp@0.1.7:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
- integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
-
-path-to-regexp@2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45"
- integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==
-
-path-to-regexp@^1.7.0:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
- integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
- dependencies:
- isarray "0.0.1"
-
-path-type@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
- integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==
- dependencies:
- pify "^3.0.0"
-
-path-type@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
- integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
-
-pbkdf2@^3.0.3:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075"
- integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==
- dependencies:
- create-hash "^1.1.2"
- create-hmac "^1.1.4"
- ripemd160 "^2.0.1"
- safe-buffer "^5.0.1"
- sha.js "^2.4.8"
-
-picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
- integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
-
-pify@^2.0.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
- integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
-
-pify@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
- integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
-
-pify@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
- integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
-
-pinkie-promise@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
- integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
- dependencies:
- pinkie "^2.0.0"
-
-pinkie@^2.0.0:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
- integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
-
-pkg-dir@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3"
- integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==
- dependencies:
- find-up "^3.0.0"
-
-pkg-dir@^4.1.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
- integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
- dependencies:
- find-up "^4.0.0"
-
-pkg-up@3.1.0, pkg-up@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5"
- integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==
- dependencies:
- find-up "^3.0.0"
-
-pnp-webpack-plugin@^1.6.4:
- version "1.6.4"
- resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149"
- integrity sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==
- dependencies:
- ts-pnp "^1.1.6"
-
-portfinder@^1.0.26:
- version "1.0.28"
- resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778"
- integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==
- dependencies:
- async "^2.6.2"
- debug "^3.1.1"
- mkdirp "^0.5.5"
-
-posix-character-classes@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
- integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
-
-postcss-attribute-case-insensitive@^4.0.1:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz#d93e46b504589e94ac7277b0463226c68041a880"
- integrity sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==
- dependencies:
- postcss "^7.0.2"
- postcss-selector-parser "^6.0.2"
-
-postcss-calc@^7.0.1:
- version "7.0.5"
- resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.5.tgz#f8a6e99f12e619c2ebc23cf6c486fdc15860933e"
- integrity sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==
- dependencies:
- postcss "^7.0.27"
- postcss-selector-parser "^6.0.2"
- postcss-value-parser "^4.0.2"
-
-postcss-color-functional-notation@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz#5efd37a88fbabeb00a2966d1e53d98ced93f74e0"
- integrity sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==
- dependencies:
- postcss "^7.0.2"
- postcss-values-parser "^2.0.0"
-
-postcss-color-gray@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz#532a31eb909f8da898ceffe296fdc1f864be8547"
- integrity sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw==
- dependencies:
- "@csstools/convert-colors" "^1.4.0"
- postcss "^7.0.5"
- postcss-values-parser "^2.0.0"
-
-postcss-color-hex-alpha@^5.0.3:
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz#a8d9ca4c39d497c9661e374b9c51899ef0f87388"
- integrity sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==
- dependencies:
- postcss "^7.0.14"
- postcss-values-parser "^2.0.1"
-
-postcss-color-mod-function@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz#816ba145ac11cc3cb6baa905a75a49f903e4d31d"
- integrity sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==
- dependencies:
- "@csstools/convert-colors" "^1.4.0"
- postcss "^7.0.2"
- postcss-values-parser "^2.0.0"
-
-postcss-color-rebeccapurple@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz#c7a89be872bb74e45b1e3022bfe5748823e6de77"
- integrity sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==
- dependencies:
- postcss "^7.0.2"
- postcss-values-parser "^2.0.0"
-
-postcss-colormin@^4.0.3:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381"
- integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==
- dependencies:
- browserslist "^4.0.0"
- color "^3.0.0"
- has "^1.0.0"
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-convert-values@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f"
- integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==
- dependencies:
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-custom-media@^7.0.8:
- version "7.0.8"
- resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz#fffd13ffeffad73621be5f387076a28b00294e0c"
- integrity sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==
- dependencies:
- postcss "^7.0.14"
-
-postcss-custom-properties@^8.0.11:
- version "8.0.11"
- resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz#2d61772d6e92f22f5e0d52602df8fae46fa30d97"
- integrity sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==
- dependencies:
- postcss "^7.0.17"
- postcss-values-parser "^2.0.1"
-
-postcss-custom-selectors@^5.1.2:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz#64858c6eb2ecff2fb41d0b28c9dd7b3db4de7fba"
- integrity sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==
- dependencies:
- postcss "^7.0.2"
- postcss-selector-parser "^5.0.0-rc.3"
-
-postcss-dir-pseudo-class@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz#6e3a4177d0edb3abcc85fdb6fbb1c26dabaeaba2"
- integrity sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==
- dependencies:
- postcss "^7.0.2"
- postcss-selector-parser "^5.0.0-rc.3"
-
-postcss-discard-comments@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033"
- integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==
- dependencies:
- postcss "^7.0.0"
-
-postcss-discard-duplicates@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb"
- integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==
- dependencies:
- postcss "^7.0.0"
-
-postcss-discard-empty@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765"
- integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==
- dependencies:
- postcss "^7.0.0"
-
-postcss-discard-overridden@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57"
- integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==
- dependencies:
- postcss "^7.0.0"
-
-postcss-double-position-gradients@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz#fc927d52fddc896cb3a2812ebc5df147e110522e"
- integrity sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==
- dependencies:
- postcss "^7.0.5"
- postcss-values-parser "^2.0.0"
-
-postcss-env-function@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-2.0.2.tgz#0f3e3d3c57f094a92c2baf4b6241f0b0da5365d7"
- integrity sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==
- dependencies:
- postcss "^7.0.2"
- postcss-values-parser "^2.0.0"
-
-postcss-focus-visible@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz#477d107113ade6024b14128317ade2bd1e17046e"
- integrity sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==
- dependencies:
- postcss "^7.0.2"
-
-postcss-focus-within@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz#763b8788596cee9b874c999201cdde80659ef680"
- integrity sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==
- dependencies:
- postcss "^7.0.2"
-
-postcss-font-variant@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz#42d4c0ab30894f60f98b17561eb5c0321f502641"
- integrity sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==
- dependencies:
- postcss "^7.0.2"
-
-postcss-gap-properties@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz#431c192ab3ed96a3c3d09f2ff615960f902c1715"
- integrity sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==
- dependencies:
- postcss "^7.0.2"
-
-postcss-image-set-function@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz#28920a2f29945bed4c3198d7df6496d410d3f288"
- integrity sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==
- dependencies:
- postcss "^7.0.2"
- postcss-values-parser "^2.0.0"
-
-postcss-initial@^3.0.0:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-3.0.4.tgz#9d32069a10531fe2ecafa0b6ac750ee0bc7efc53"
- integrity sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg==
- dependencies:
- postcss "^7.0.2"
-
-postcss-lab-function@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz#bb51a6856cd12289ab4ae20db1e3821ef13d7d2e"
- integrity sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==
- dependencies:
- "@csstools/convert-colors" "^1.4.0"
- postcss "^7.0.2"
- postcss-values-parser "^2.0.0"
-
-postcss-load-config@^2.0.0:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.2.tgz#c5ea504f2c4aef33c7359a34de3573772ad7502a"
- integrity sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==
- dependencies:
- cosmiconfig "^5.0.0"
- import-cwd "^2.0.0"
-
-postcss-loader@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d"
- integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==
- dependencies:
- loader-utils "^1.1.0"
- postcss "^7.0.0"
- postcss-load-config "^2.0.0"
- schema-utils "^1.0.0"
-
-postcss-logical@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-3.0.0.tgz#2495d0f8b82e9f262725f75f9401b34e7b45d5b5"
- integrity sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==
- dependencies:
- postcss "^7.0.2"
-
-postcss-media-minmax@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz#b75bb6cbc217c8ac49433e12f22048814a4f5ed5"
- integrity sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==
- dependencies:
- postcss "^7.0.2"
-
-postcss-merge-longhand@^4.0.11:
- version "4.0.11"
- resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24"
- integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==
- dependencies:
- css-color-names "0.0.4"
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
- stylehacks "^4.0.0"
-
-postcss-merge-rules@^4.0.3:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650"
- integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==
- dependencies:
- browserslist "^4.0.0"
- caniuse-api "^3.0.0"
- cssnano-util-same-parent "^4.0.0"
- postcss "^7.0.0"
- postcss-selector-parser "^3.0.0"
- vendors "^1.0.0"
-
-postcss-minify-font-values@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6"
- integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==
- dependencies:
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-minify-gradients@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471"
- integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==
- dependencies:
- cssnano-util-get-arguments "^4.0.0"
- is-color-stop "^1.0.0"
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-minify-params@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874"
- integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==
- dependencies:
- alphanum-sort "^1.0.0"
- browserslist "^4.0.0"
- cssnano-util-get-arguments "^4.0.0"
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
- uniqs "^2.0.0"
-
-postcss-minify-selectors@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8"
- integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==
- dependencies:
- alphanum-sort "^1.0.0"
- has "^1.0.0"
- postcss "^7.0.0"
- postcss-selector-parser "^3.0.0"
-
-postcss-modules-extract-imports@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e"
- integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==
- dependencies:
- postcss "^7.0.5"
-
-postcss-modules-local-by-default@^3.0.2:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz#bb14e0cc78279d504dbdcbfd7e0ca28993ffbbb0"
- integrity sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==
- dependencies:
- icss-utils "^4.1.1"
- postcss "^7.0.32"
- postcss-selector-parser "^6.0.2"
- postcss-value-parser "^4.1.0"
-
-postcss-modules-scope@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee"
- integrity sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==
- dependencies:
- postcss "^7.0.6"
- postcss-selector-parser "^6.0.0"
-
-postcss-modules-values@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10"
- integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==
- dependencies:
- icss-utils "^4.0.0"
- postcss "^7.0.6"
-
-postcss-nesting@^7.0.0:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-7.0.1.tgz#b50ad7b7f0173e5b5e3880c3501344703e04c052"
- integrity sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==
- dependencies:
- postcss "^7.0.2"
-
-postcss-normalize-charset@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4"
- integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==
- dependencies:
- postcss "^7.0.0"
-
-postcss-normalize-display-values@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a"
- integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==
- dependencies:
- cssnano-util-get-match "^4.0.0"
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-normalize-positions@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f"
- integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==
- dependencies:
- cssnano-util-get-arguments "^4.0.0"
- has "^1.0.0"
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-normalize-repeat-style@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c"
- integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==
- dependencies:
- cssnano-util-get-arguments "^4.0.0"
- cssnano-util-get-match "^4.0.0"
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-normalize-string@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c"
- integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==
- dependencies:
- has "^1.0.0"
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-normalize-timing-functions@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9"
- integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==
- dependencies:
- cssnano-util-get-match "^4.0.0"
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-normalize-unicode@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb"
- integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==
- dependencies:
- browserslist "^4.0.0"
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-normalize-url@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1"
- integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==
- dependencies:
- is-absolute-url "^2.0.0"
- normalize-url "^3.0.0"
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-normalize-whitespace@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82"
- integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==
- dependencies:
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-ordered-values@^4.1.2:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee"
- integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==
- dependencies:
- cssnano-util-get-arguments "^4.0.0"
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-overflow-shorthand@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz#31ecf350e9c6f6ddc250a78f0c3e111f32dd4c30"
- integrity sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==
- dependencies:
- postcss "^7.0.2"
-
-postcss-page-break@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-2.0.0.tgz#add52d0e0a528cabe6afee8b46e2abb277df46bf"
- integrity sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==
- dependencies:
- postcss "^7.0.2"
-
-postcss-place@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-4.0.1.tgz#e9f39d33d2dc584e46ee1db45adb77ca9d1dcc62"
- integrity sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==
- dependencies:
- postcss "^7.0.2"
- postcss-values-parser "^2.0.0"
-
-postcss-preset-env@^6.7.0:
- version "6.7.0"
- resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz#c34ddacf8f902383b35ad1e030f178f4cdf118a5"
- integrity sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg==
- dependencies:
- autoprefixer "^9.6.1"
- browserslist "^4.6.4"
- caniuse-lite "^1.0.30000981"
- css-blank-pseudo "^0.1.4"
- css-has-pseudo "^0.10.0"
- css-prefers-color-scheme "^3.1.1"
- cssdb "^4.4.0"
- postcss "^7.0.17"
- postcss-attribute-case-insensitive "^4.0.1"
- postcss-color-functional-notation "^2.0.1"
- postcss-color-gray "^5.0.0"
- postcss-color-hex-alpha "^5.0.3"
- postcss-color-mod-function "^3.0.3"
- postcss-color-rebeccapurple "^4.0.1"
- postcss-custom-media "^7.0.8"
- postcss-custom-properties "^8.0.11"
- postcss-custom-selectors "^5.1.2"
- postcss-dir-pseudo-class "^5.0.0"
- postcss-double-position-gradients "^1.0.0"
- postcss-env-function "^2.0.2"
- postcss-focus-visible "^4.0.0"
- postcss-focus-within "^3.0.0"
- postcss-font-variant "^4.0.0"
- postcss-gap-properties "^2.0.0"
- postcss-image-set-function "^3.0.1"
- postcss-initial "^3.0.0"
- postcss-lab-function "^2.0.1"
- postcss-logical "^3.0.0"
- postcss-media-minmax "^4.0.0"
- postcss-nesting "^7.0.0"
- postcss-overflow-shorthand "^2.0.0"
- postcss-page-break "^2.0.0"
- postcss-place "^4.0.1"
- postcss-pseudo-class-any-link "^6.0.0"
- postcss-replace-overflow-wrap "^3.0.0"
- postcss-selector-matches "^4.0.0"
- postcss-selector-not "^4.0.0"
-
-postcss-pseudo-class-any-link@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz#2ed3eed393b3702879dec4a87032b210daeb04d1"
- integrity sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==
- dependencies:
- postcss "^7.0.2"
- postcss-selector-parser "^5.0.0-rc.3"
-
-postcss-reduce-initial@^4.0.3:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df"
- integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==
- dependencies:
- browserslist "^4.0.0"
- caniuse-api "^3.0.0"
- has "^1.0.0"
- postcss "^7.0.0"
-
-postcss-reduce-transforms@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29"
- integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==
- dependencies:
- cssnano-util-get-match "^4.0.0"
- has "^1.0.0"
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
-
-postcss-replace-overflow-wrap@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz#61b360ffdaedca84c7c918d2b0f0d0ea559ab01c"
- integrity sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==
- dependencies:
- postcss "^7.0.2"
-
-postcss-selector-matches@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz#71c8248f917ba2cc93037c9637ee09c64436fcff"
- integrity sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==
- dependencies:
- balanced-match "^1.0.0"
- postcss "^7.0.2"
-
-postcss-selector-not@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz#263016eef1cf219e0ade9a913780fc1f48204cbf"
- integrity sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==
- dependencies:
- balanced-match "^1.0.0"
- postcss "^7.0.2"
-
-postcss-selector-parser@^3.0.0:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz#b310f5c4c0fdaf76f94902bbaa30db6aa84f5270"
- integrity sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==
- dependencies:
- dot-prop "^5.2.0"
- indexes-of "^1.0.1"
- uniq "^1.0.1"
-
-postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c"
- integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==
- dependencies:
- cssesc "^2.0.0"
- indexes-of "^1.0.1"
- uniq "^1.0.1"
-
-postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2:
- version "6.0.6"
- resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea"
- integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==
- dependencies:
- cssesc "^3.0.0"
- util-deprecate "^1.0.2"
-
-postcss-svgo@^4.0.3:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.3.tgz#343a2cdbac9505d416243d496f724f38894c941e"
- integrity sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==
- dependencies:
- postcss "^7.0.0"
- postcss-value-parser "^3.0.0"
- svgo "^1.0.0"
-
-postcss-unique-selectors@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac"
- integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==
- dependencies:
- alphanum-sort "^1.0.0"
- postcss "^7.0.0"
- uniqs "^2.0.0"
-
-postcss-value-parser@^3.0.0:
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
- integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
-
-postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
- integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
-
-postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz#da8b472d901da1e205b47bdc98637b9e9e550e5f"
- integrity sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==
- dependencies:
- flatten "^1.0.2"
- indexes-of "^1.0.1"
- uniq "^1.0.1"
-
-postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6:
- version "7.0.36"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.36.tgz#056f8cffa939662a8f5905950c07d5285644dfcb"
- integrity sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==
- dependencies:
- chalk "^2.4.2"
- source-map "^0.6.1"
- supports-color "^6.1.0"
-
-prepend-http@^1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
- integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
-
-prepend-http@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
- integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
-
-pretty-error@^2.1.1:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6"
- integrity sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==
- dependencies:
- lodash "^4.17.20"
- renderkid "^2.0.4"
-
-pretty-time@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e"
- integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==
-
-prism-react-renderer@^1.1.0:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.2.1.tgz#392460acf63540960e5e3caa699d851264e99b89"
- integrity sha512-w23ch4f75V1Tnz8DajsYKvY5lF7H1+WvzvLUcF0paFxkTHSp42RS0H5CttdN2Q8RR3DRGZ9v5xD/h3n8C8kGmg==
-
-prismjs@^1.20.0:
- version "1.25.0"
- resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756"
- integrity sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg==
-
-process-nextick-args@~2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
- integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
-
-process@^0.11.10:
- version "0.11.10"
- resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
- integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
-
-promise-inflight@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
- integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
-
-promise@^7.1.1:
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
- integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
- dependencies:
- asap "~2.0.3"
-
-prop-types@^15.5.0, prop-types@^15.6.2, prop-types@^15.7.2:
- version "15.7.2"
- resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
- integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
- dependencies:
- loose-envify "^1.4.0"
- object-assign "^4.1.1"
- react-is "^16.8.1"
-
-property-information@^5.0.0, property-information@^5.3.0:
- version "5.6.0"
- resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69"
- integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==
- dependencies:
- xtend "^4.0.0"
-
-proxy-addr@~2.0.5:
- version "2.0.7"
- resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
- integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
- dependencies:
- forwarded "0.2.0"
- ipaddr.js "1.9.1"
-
-prr@~1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
- integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
-
-public-encrypt@^4.0.0:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0"
- integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==
- dependencies:
- bn.js "^4.1.0"
- browserify-rsa "^4.0.0"
- create-hash "^1.1.0"
- parse-asn1 "^5.0.0"
- randombytes "^2.0.1"
- safe-buffer "^5.1.2"
-
-pump@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
- integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
- dependencies:
- end-of-stream "^1.1.0"
- once "^1.3.1"
-
-pump@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
- integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
- dependencies:
- end-of-stream "^1.1.0"
- once "^1.3.1"
-
-pumpify@^1.3.3:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
- integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==
- dependencies:
- duplexify "^3.6.0"
- inherits "^2.0.3"
- pump "^2.0.0"
-
-punycode@1.3.2:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
- integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=
-
-punycode@^1.2.4, punycode@^1.3.2:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
- integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
-
-punycode@^2.1.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
- integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
-
-pupa@^2.0.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62"
- integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==
- dependencies:
- escape-goat "^2.0.0"
-
-pure-color@^1.2.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e"
- integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=
-
-q@^1.1.2:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
- integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
-
-qs@6.7.0:
- version "6.7.0"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
- integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
-
-query-string@^4.1.0:
- version "4.3.4"
- resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
- integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s=
- dependencies:
- object-assign "^4.1.0"
- strict-uri-encode "^1.0.0"
-
-querystring-es3@^0.2.0:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
- integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=
-
-querystring@0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
- integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
-
-querystringify@^2.1.1:
- version "2.2.0"
- 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==
-
-randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
- integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
- dependencies:
- safe-buffer "^5.1.0"
-
-randomfill@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458"
- integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==
- dependencies:
- randombytes "^2.0.5"
- safe-buffer "^5.1.0"
-
-range-parser@1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
- integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=
-
-range-parser@^1.2.1, range-parser@~1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
- integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
-
-raw-body@2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
- integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
- dependencies:
- bytes "3.1.0"
- http-errors "1.7.2"
- iconv-lite "0.4.24"
- unpipe "1.0.0"
-
-rc@^1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
- integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
- dependencies:
- deep-extend "^0.6.0"
- ini "~1.3.0"
- minimist "^1.2.0"
- strip-json-comments "~2.0.1"
-
-react-base16-styling@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c"
- integrity sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw=
- dependencies:
- base16 "^1.0.0"
- lodash.curry "^4.0.1"
- lodash.flow "^3.3.0"
- pure-color "^1.2.0"
-
-react-dev-utils@^10.2.1:
- version "10.2.1"
- resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-10.2.1.tgz#f6de325ae25fa4d546d09df4bb1befdc6dd19c19"
- integrity sha512-XxTbgJnYZmxuPtY3y/UV0D8/65NKkmaia4rXzViknVnZeVlklSh8u6TnaEYPfAi/Gh1TP4mEOXHI6jQOPbeakQ==
- dependencies:
- "@babel/code-frame" "7.8.3"
- address "1.1.2"
- browserslist "4.10.0"
- chalk "2.4.2"
- cross-spawn "7.0.1"
- detect-port-alt "1.1.6"
- escape-string-regexp "2.0.0"
- filesize "6.0.1"
- find-up "4.1.0"
- fork-ts-checker-webpack-plugin "3.1.1"
- global-modules "2.0.0"
- globby "8.0.2"
- gzip-size "5.1.1"
- immer "1.10.0"
- inquirer "7.0.4"
- is-root "2.1.0"
- loader-utils "1.2.3"
- open "^7.0.2"
- pkg-up "3.1.0"
- react-error-overlay "^6.0.7"
- recursive-readdir "2.2.2"
- shell-quote "1.7.2"
- strip-ansi "6.0.0"
- text-table "0.2.0"
-
-react-dom@^16.8.4:
- version "16.14.0"
- resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89"
- integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==
- dependencies:
- loose-envify "^1.1.0"
- object-assign "^4.1.1"
- prop-types "^15.6.2"
- scheduler "^0.19.1"
-
-react-error-overlay@^6.0.7:
- version "6.0.9"
- resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
- integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
-
-react-fast-compare@^3.1.1:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
- integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
-
-react-helmet@^6.0.0-beta:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726"
- integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==
- dependencies:
- object-assign "^4.1.1"
- prop-types "^15.7.2"
- react-fast-compare "^3.1.1"
- react-side-effect "^2.1.0"
-
-react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
- version "16.13.1"
- resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
- integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
-
-react-json-view@^1.19.1:
- version "1.21.3"
- resolved "https://registry.yarnpkg.com/react-json-view/-/react-json-view-1.21.3.tgz#f184209ee8f1bf374fb0c41b0813cff54549c475"
- integrity sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==
- dependencies:
- flux "^4.0.1"
- react-base16-styling "^0.6.0"
- react-lifecycles-compat "^3.0.4"
- react-textarea-autosize "^8.3.2"
-
-react-lifecycles-compat@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
- integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
-
-react-loadable-ssr-addon@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/react-loadable-ssr-addon/-/react-loadable-ssr-addon-0.3.0.tgz#ae9b2d3b11721930f8d8255476d288c0e9f9290f"
- integrity sha512-E+lnmDakV0k6ut6R2J77vurwCOwTKEwKlHs9S62G8ez+ujecLPcqjt3YAU8M58kIGjp2QjFlZ7F9QWkq/mr6Iw==
- dependencies:
- "@babel/runtime" "^7.10.3"
-
-react-loadable@^5.5.0:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/react-loadable/-/react-loadable-5.5.0.tgz#582251679d3da86c32aae2c8e689c59f1196d8c4"
- integrity sha512-C8Aui0ZpMd4KokxRdVAm2bQtI03k2RMRNzOB+IipV3yxFTSVICv7WoUr5L9ALB5BmKO1iHgZtWM8EvYG83otdg==
- dependencies:
- prop-types "^15.5.0"
-
-react-router-config@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/react-router-config/-/react-router-config-5.1.1.tgz#0f4263d1a80c6b2dc7b9c1902c9526478194a988"
- integrity sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==
- dependencies:
- "@babel/runtime" "^7.1.2"
-
-react-router-dom@^5.1.2:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662"
- integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==
- dependencies:
- "@babel/runtime" "^7.1.2"
- history "^4.9.0"
- loose-envify "^1.3.1"
- prop-types "^15.6.2"
- react-router "5.2.0"
- tiny-invariant "^1.0.2"
- tiny-warning "^1.0.0"
-
-react-router@5.2.0, react-router@^5.1.2:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293"
- integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==
- dependencies:
- "@babel/runtime" "^7.1.2"
- history "^4.9.0"
- hoist-non-react-statics "^3.1.0"
- loose-envify "^1.3.1"
- mini-create-react-context "^0.4.0"
- path-to-regexp "^1.7.0"
- prop-types "^15.6.2"
- react-is "^16.6.0"
- tiny-invariant "^1.0.2"
- tiny-warning "^1.0.0"
-
-react-side-effect@^2.1.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.1.tgz#66c5701c3e7560ab4822a4ee2742dee215d72eb3"
- integrity sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ==
-
-react-textarea-autosize@^8.3.2:
- version "8.3.3"
- resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz#f70913945369da453fd554c168f6baacd1fa04d8"
- integrity sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ==
- dependencies:
- "@babel/runtime" "^7.10.2"
- use-composed-ref "^1.0.0"
- use-latest "^1.0.0"
-
-react-toggle@^4.1.1:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/react-toggle/-/react-toggle-4.1.2.tgz#b00500832f925ad524356d909821821ae39f6c52"
- integrity sha512-4Ohw31TuYQdhWfA6qlKafeXx3IOH7t4ZHhmRdwsm1fQREwOBGxJT+I22sgHqR/w8JRdk+AeMCJXPImEFSrNXow==
- dependencies:
- classnames "^2.2.5"
-
-react@^16.8.4:
- version "16.14.0"
- resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d"
- integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==
- dependencies:
- loose-envify "^1.1.0"
- object-assign "^4.1.1"
- prop-types "^15.6.2"
-
-"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
- version "2.3.7"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
- integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.3"
- isarray "~1.0.0"
- process-nextick-args "~2.0.0"
- safe-buffer "~5.1.1"
- string_decoder "~1.1.1"
- util-deprecate "~1.0.1"
-
-readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.6.0:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
- integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
- dependencies:
- inherits "^2.0.3"
- string_decoder "^1.1.1"
- util-deprecate "^1.0.1"
-
-readdirp@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
- integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==
- dependencies:
- graceful-fs "^4.1.11"
- micromatch "^3.1.10"
- readable-stream "^2.0.2"
-
-readdirp@~3.6.0:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
- integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
- dependencies:
- picomatch "^2.2.1"
-
-reading-time@^1.2.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/reading-time/-/reading-time-1.3.0.tgz#d13e74431589a4a9038669f24d5acbc08bbb015d"
- integrity sha512-RJ8J5O6UvrclfZpcPSPuKusrdRfoY7uXXoYOOdeswZNtSkQaewT3919yz6RyloDBR+iwcUyz5zGOUjhgvfuv3g==
-
-rechoir@^0.6.2:
- version "0.6.2"
- resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
- integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=
- dependencies:
- resolve "^1.1.6"
-
-recursive-readdir@2.2.2:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f"
- integrity sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==
- dependencies:
- minimatch "3.0.4"
-
-regenerate-unicode-properties@^8.2.0:
- version "8.2.0"
- resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
- integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==
- dependencies:
- regenerate "^1.4.0"
-
-regenerate@^1.4.0:
- version "1.4.2"
- resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
- integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
-
-regenerator-runtime@^0.13.4:
- version "0.13.7"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
- integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
-
-regenerator-transform@^0.14.2:
- version "0.14.5"
- resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4"
- integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==
- dependencies:
- "@babel/runtime" "^7.8.4"
-
-regex-not@^1.0.0, regex-not@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
- integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
- dependencies:
- extend-shallow "^3.0.2"
- safe-regex "^1.1.0"
-
-regexp.prototype.flags@^1.2.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26"
- integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
-
-regexpu-core@^4.7.1:
- version "4.7.1"
- resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6"
- integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==
- dependencies:
- regenerate "^1.4.0"
- regenerate-unicode-properties "^8.2.0"
- regjsgen "^0.5.1"
- regjsparser "^0.6.4"
- unicode-match-property-ecmascript "^1.0.4"
- unicode-match-property-value-ecmascript "^1.2.0"
-
-registry-auth-token@^4.0.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250"
- integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==
- dependencies:
- rc "^1.2.8"
-
-registry-url@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009"
- integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==
- dependencies:
- rc "^1.2.8"
-
-regjsgen@^0.5.1:
- version "0.5.2"
- resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733"
- integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==
-
-regjsparser@^0.6.4:
- version "0.6.9"
- resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.9.tgz#b489eef7c9a2ce43727627011429cf833a7183e6"
- integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==
- dependencies:
- jsesc "~0.5.0"
-
-rehype-parse@^6.0.2:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/rehype-parse/-/rehype-parse-6.0.2.tgz#aeb3fdd68085f9f796f1d3137ae2b85a98406964"
- integrity sha512-0S3CpvpTAgGmnz8kiCyFLGuW5yA4OQhyNTm/nwPopZ7+PI11WnGl1TTWTGv/2hPEe/g2jRLlhVVSsoDH8waRug==
- dependencies:
- hast-util-from-parse5 "^5.0.0"
- parse5 "^5.0.0"
- xtend "^4.0.0"
-
-relateurl@^0.2.7:
- version "0.2.7"
- resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
- integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
-
-remark-admonitions@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/remark-admonitions/-/remark-admonitions-1.2.1.tgz#87caa1a442aa7b4c0cafa04798ed58a342307870"
- integrity sha512-Ji6p68VDvD+H1oS95Fdx9Ar5WA2wcDA4kwrrhVU7fGctC6+d3uiMICu7w7/2Xld+lnU7/gi+432+rRbup5S8ow==
- dependencies:
- rehype-parse "^6.0.2"
- unified "^8.4.2"
- unist-util-visit "^2.0.1"
-
-remark-emoji@^2.1.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/remark-emoji/-/remark-emoji-2.2.0.tgz#1c702090a1525da5b80e15a8f963ef2c8236cac7"
- integrity sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w==
- dependencies:
- emoticon "^3.2.0"
- node-emoji "^1.10.0"
- unist-util-visit "^2.0.3"
-
-remark-footnotes@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/remark-footnotes/-/remark-footnotes-2.0.0.tgz#9001c4c2ffebba55695d2dd80ffb8b82f7e6303f"
- integrity sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==
-
-remark-mdx@1.6.22:
- version "1.6.22"
- resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-1.6.22.tgz#06a8dab07dcfdd57f3373af7f86bd0e992108bbd"
- integrity sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==
- dependencies:
- "@babel/core" "7.12.9"
- "@babel/helper-plugin-utils" "7.10.4"
- "@babel/plugin-proposal-object-rest-spread" "7.12.1"
- "@babel/plugin-syntax-jsx" "7.12.1"
- "@mdx-js/util" "1.6.22"
- is-alphabetical "1.0.4"
- remark-parse "8.0.3"
- unified "9.2.0"
-
-remark-parse@8.0.3:
- version "8.0.3"
- resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-8.0.3.tgz#9c62aa3b35b79a486454c690472906075f40c7e1"
- integrity sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==
- dependencies:
- ccount "^1.0.0"
- collapse-white-space "^1.0.2"
- is-alphabetical "^1.0.0"
- is-decimal "^1.0.0"
- is-whitespace-character "^1.0.0"
- is-word-character "^1.0.0"
- markdown-escapes "^1.0.0"
- parse-entities "^2.0.0"
- repeat-string "^1.5.4"
- state-toggle "^1.0.0"
- trim "0.0.1"
- trim-trailing-lines "^1.0.0"
- unherit "^1.0.4"
- unist-util-remove-position "^2.0.0"
- vfile-location "^3.0.0"
- xtend "^4.0.1"
-
-remark-squeeze-paragraphs@4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz#76eb0e085295131c84748c8e43810159c5653ead"
- integrity sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==
- dependencies:
- mdast-squeeze-paragraphs "^4.0.0"
-
-remove-trailing-separator@^1.0.1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
- integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
-
-renderkid@^2.0.4:
- version "2.0.7"
- resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.7.tgz#464f276a6bdcee606f4a15993f9b29fc74ca8609"
- integrity sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==
- dependencies:
- css-select "^4.1.3"
- dom-converter "^0.2.0"
- htmlparser2 "^6.1.0"
- lodash "^4.17.21"
- strip-ansi "^3.0.1"
-
-repeat-element@^1.1.2:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9"
- integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==
-
-repeat-string@^1.5.4, repeat-string@^1.6.1:
- version "1.6.1"
- resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
- integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
-
-require-directory@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
- integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
-
-"require-like@>= 0.1.1":
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/require-like/-/require-like-0.1.2.tgz#ad6f30c13becd797010c468afa775c0c0a6b47fa"
- integrity sha1-rW8wwTvs15cBDEaK+ndcDAprR/o=
-
-require-main-filename@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
- integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
-
-requires-port@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
- integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
-
-resolve-cwd@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
- integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=
- dependencies:
- resolve-from "^3.0.0"
-
-resolve-from@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
- integrity sha1-six699nWiBvItuZTM17rywoYh0g=
-
-resolve-from@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
- integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
-
-resolve-pathname@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd"
- integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==
-
-resolve-url@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
- integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
-
-resolve@^1.1.6:
- version "1.21.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f"
- integrity sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==
- dependencies:
- is-core-module "^2.8.0"
- path-parse "^1.0.7"
- supports-preserve-symlinks-flag "^1.0.0"
-
-resolve@^1.14.2, resolve@^1.3.2:
- version "1.20.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
- integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
- dependencies:
- is-core-module "^2.2.0"
- path-parse "^1.0.6"
-
-responselike@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
- integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=
- dependencies:
- lowercase-keys "^1.0.0"
-
-restore-cursor@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
- integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
- dependencies:
- onetime "^5.1.0"
- signal-exit "^3.0.2"
-
-ret@~0.1.10:
- version "0.1.15"
- resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
- integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
-
-retry@^0.12.0:
- version "0.12.0"
- resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
- integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
-
-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"
- integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE=
-
-rgba-regex@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
- integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
-
-rimraf@^2.5.4, rimraf@^2.6.3:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
- integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
- dependencies:
- glob "^7.1.3"
-
-rimraf@^3.0.0, rimraf@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
- integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
- dependencies:
- glob "^7.1.3"
-
-ripemd160@^2.0.0, ripemd160@^2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
- integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==
- dependencies:
- hash-base "^3.0.0"
- inherits "^2.0.1"
-
-run-async@^2.2.0, run-async@^2.4.0:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
- integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
-
-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"
- integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=
- dependencies:
- aproba "^1.1.1"
-
-rx@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
- integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=
-
-rxjs@^6.5.3, rxjs@^6.6.0:
- version "6.6.7"
- resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
- integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
- dependencies:
- tslib "^1.9.0"
-
-safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
- integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-
-safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
- version "5.2.1"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
- integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
-
-safe-regex@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
- integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4=
- dependencies:
- ret "~0.1.10"
-
-"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.1.0:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
- integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
-
-sax@^1.2.4, sax@~1.2.4:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
- integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
-
-scheduler@^0.19.1:
- version "0.19.1"
- resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196"
- integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==
- dependencies:
- loose-envify "^1.1.0"
- object-assign "^4.1.1"
-
-schema-utils@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770"
- integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==
- dependencies:
- ajv "^6.1.0"
- ajv-errors "^1.0.0"
- ajv-keywords "^3.1.0"
-
-schema-utils@^2.0.0, schema-utils@^2.6.5, schema-utils@^2.7.0:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7"
- integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==
- dependencies:
- "@types/json-schema" "^7.0.5"
- ajv "^6.12.4"
- ajv-keywords "^3.5.2"
-
-schema-utils@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.0.0.tgz#67502f6aa2b66a2d4032b4279a2944978a0913ef"
- integrity sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==
- dependencies:
- "@types/json-schema" "^7.0.6"
- ajv "^6.12.5"
- ajv-keywords "^3.5.2"
-
-section-matter@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167"
- integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==
- dependencies:
- extend-shallow "^2.0.1"
- kind-of "^6.0.0"
-
-select-hose@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
- integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
-
-selfsigned@^1.10.8:
- version "1.10.11"
- resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.11.tgz#24929cd906fe0f44b6d01fb23999a739537acbe9"
- integrity sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==
- dependencies:
- node-forge "^0.10.0"
-
-semver-diff@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b"
- integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==
- dependencies:
- semver "^6.3.0"
-
-semver@7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
- integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
-
-semver@^5.4.1, semver@^5.5.0, semver@^5.6.0:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
- integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
-
-semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
- integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-
-send@0.17.1:
- version "0.17.1"
- resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
- integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
- dependencies:
- debug "2.6.9"
- depd "~1.1.2"
- destroy "~1.0.4"
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- etag "~1.8.1"
- fresh "0.5.2"
- http-errors "~1.7.2"
- mime "1.6.0"
- ms "2.1.1"
- on-finished "~2.3.0"
- range-parser "~1.2.1"
- statuses "~1.5.0"
-
-serialize-javascript@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
- integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==
- dependencies:
- randombytes "^2.1.0"
-
-serialize-javascript@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4"
- integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==
- dependencies:
- randombytes "^2.1.0"
-
-serve-handler@^6.1.3:
- version "6.1.3"
- resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.3.tgz#1bf8c5ae138712af55c758477533b9117f6435e8"
- integrity sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==
- dependencies:
- bytes "3.0.0"
- content-disposition "0.5.2"
- fast-url-parser "1.1.3"
- mime-types "2.1.18"
- minimatch "3.0.4"
- path-is-inside "1.0.2"
- path-to-regexp "2.2.1"
- range-parser "1.2.0"
-
-serve-index@^1.9.1:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
- integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=
- dependencies:
- accepts "~1.3.4"
- batch "0.6.1"
- debug "2.6.9"
- escape-html "~1.0.3"
- http-errors "~1.6.2"
- mime-types "~2.1.17"
- parseurl "~1.3.2"
-
-serve-static@1.14.1:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
- integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
- dependencies:
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- parseurl "~1.3.3"
- send "0.17.1"
-
-set-blocking@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
- integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
-
-set-value@^2.0.0, set-value@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
- integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
- dependencies:
- extend-shallow "^2.0.1"
- is-extendable "^0.1.1"
- is-plain-object "^2.0.3"
- split-string "^3.0.1"
-
-setimmediate@^1.0.4, setimmediate@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
- integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
-
-setprototypeof@1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
- integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
-
-setprototypeof@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
- integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
-
-sha.js@^2.4.0, sha.js@^2.4.8:
- version "2.4.11"
- resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
- integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
- dependencies:
- inherits "^2.0.1"
- safe-buffer "^5.0.1"
-
-shebang-command@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
- integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
- dependencies:
- shebang-regex "^1.0.0"
-
-shebang-command@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
- integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
- dependencies:
- shebang-regex "^3.0.0"
-
-shebang-regex@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
- integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
-
-shebang-regex@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
- integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
-
-shell-quote@1.7.2:
- version "1.7.2"
- resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2"
- integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==
-
-shelljs@^0.8.4:
- version "0.8.5"
- resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c"
- integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==
- dependencies:
- glob "^7.0.0"
- interpret "^1.0.0"
- rechoir "^0.6.2"
-
-signal-exit@^3.0.0, signal-exit@^3.0.2:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
- integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
-
-simple-swizzle@^0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
- integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=
- dependencies:
- is-arrayish "^0.3.1"
-
-sitemap@^3.2.2:
- version "3.2.2"
- resolved "https://registry.yarnpkg.com/sitemap/-/sitemap-3.2.2.tgz#3f77c358fa97b555c879e457098e39910095c62b"
- integrity sha512-TModL/WU4m2q/mQcrDgNANn0P4LwprM9MMvG4hu5zP4c6IIKs2YLTu6nXXnNr8ODW/WFtxKggiJ1EGn2W0GNmg==
- dependencies:
- lodash.chunk "^4.2.0"
- lodash.padstart "^4.6.1"
- whatwg-url "^7.0.0"
- xmlbuilder "^13.0.0"
-
-slash@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
- integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=
-
-slash@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
- integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
-
-snapdragon-node@^2.0.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
- integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==
- dependencies:
- define-property "^1.0.0"
- isobject "^3.0.0"
- snapdragon-util "^3.0.1"
-
-snapdragon-util@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
- integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==
- dependencies:
- kind-of "^3.2.0"
-
-snapdragon@^0.8.1:
- version "0.8.2"
- resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
- integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
- dependencies:
- base "^0.11.1"
- debug "^2.2.0"
- define-property "^0.2.5"
- extend-shallow "^2.0.1"
- map-cache "^0.2.2"
- source-map "^0.5.6"
- source-map-resolve "^0.5.0"
- use "^3.1.0"
-
-sockjs-client@^1.5.0:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.1.tgz#256908f6d5adfb94dabbdbd02c66362cca0f9ea6"
- integrity sha512-VnVAb663fosipI/m6pqRXakEOw7nvd7TUgdr3PlR/8V2I95QIdwT8L4nMxhyU8SmDBHYXU1TOElaKOmKLfYzeQ==
- dependencies:
- debug "^3.2.6"
- eventsource "^1.0.7"
- faye-websocket "^0.11.3"
- inherits "^2.0.4"
- json3 "^3.3.3"
- url-parse "^1.5.1"
-
-sockjs@^0.3.21:
- version "0.3.21"
- resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.21.tgz#b34ffb98e796930b60a0cfa11904d6a339a7d417"
- integrity sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==
- dependencies:
- faye-websocket "^0.11.3"
- uuid "^3.4.0"
- websocket-driver "^0.7.4"
-
-sort-keys@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
- integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0=
- dependencies:
- is-plain-obj "^1.0.0"
-
-source-list-map@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
- integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
-
-source-map-resolve@^0.5.0:
- version "0.5.3"
- resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
- integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
- dependencies:
- atob "^2.1.2"
- decode-uri-component "^0.2.0"
- resolve-url "^0.2.1"
- source-map-url "^0.4.0"
- urix "^0.1.0"
-
-source-map-support@~0.5.12, source-map-support@~0.5.19:
- version "0.5.19"
- resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
- integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
- dependencies:
- buffer-from "^1.0.0"
- source-map "^0.6.0"
-
-source-map-url@^0.4.0:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
- integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
-
-source-map@^0.5.0, source-map@^0.5.6:
- version "0.5.7"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
- integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
-
-source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
- integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
-
-source-map@^0.7.3, source-map@~0.7.2:
- version "0.7.3"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
- integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
-
-space-separated-tokens@^1.0.0:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899"
- integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==
-
-spdy-transport@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31"
- integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==
- dependencies:
- debug "^4.1.0"
- detect-node "^2.0.4"
- hpack.js "^2.1.6"
- obuf "^1.1.2"
- readable-stream "^3.0.6"
- wbuf "^1.7.3"
-
-spdy@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b"
- integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==
- dependencies:
- debug "^4.1.0"
- handle-thing "^2.0.0"
- http-deceiver "^1.2.7"
- select-hose "^2.0.0"
- spdy-transport "^3.0.0"
-
-split-string@^3.0.1, split-string@^3.0.2:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
- integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
- dependencies:
- extend-shallow "^3.0.0"
-
-sprintf-js@~1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
- integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
-
-ssri@^6.0.1:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5"
- integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==
- dependencies:
- figgy-pudding "^3.5.1"
-
-ssri@^8.0.1:
- version "8.0.1"
- resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af"
- integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==
- dependencies:
- minipass "^3.1.1"
-
-stable@^0.1.8:
- version "0.1.8"
- resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
- integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
-
-state-toggle@^1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe"
- integrity sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==
-
-static-extend@^0.1.1:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
- integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=
- dependencies:
- define-property "^0.2.5"
- object-copy "^0.1.0"
-
-"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
- integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
-
-std-env@^2.2.1:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/std-env/-/std-env-2.3.0.tgz#66d4a4a4d5224242ed8e43f5d65cfa9095216eee"
- integrity sha512-4qT5B45+Kjef2Z6pE0BkskzsH0GO7GrND0wGlTM1ioUe3v0dGYx9ZJH0Aro/YyA8fqQ5EyIKDRjZojJYMFTflw==
- dependencies:
- ci-info "^3.0.0"
-
-stream-browserify@^2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
- integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==
- dependencies:
- inherits "~2.0.1"
- readable-stream "^2.0.2"
-
-stream-each@^1.1.0:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
- integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==
- dependencies:
- end-of-stream "^1.1.0"
- stream-shift "^1.0.0"
-
-stream-http@^2.7.2:
- version "2.8.3"
- resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc"
- integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==
- dependencies:
- builtin-status-codes "^3.0.0"
- inherits "^2.0.1"
- readable-stream "^2.3.6"
- to-arraybuffer "^1.0.0"
- xtend "^4.0.0"
-
-stream-shift@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
- integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
-
-strict-uri-encode@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
- integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=
-
-string-width@^3.0.0, string-width@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
- integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
- dependencies:
- emoji-regex "^7.0.1"
- is-fullwidth-code-point "^2.0.0"
- strip-ansi "^5.1.0"
-
-string-width@^4.0.0, string-width@^4.1.0:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5"
- integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.0"
-
-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"
- integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
-
-string.prototype.trimstart@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed"
- integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
-
-string_decoder@^1.0.0, string_decoder@^1.1.1:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
- integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
- dependencies:
- safe-buffer "~5.2.0"
-
-string_decoder@~1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
- integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
- dependencies:
- safe-buffer "~5.1.0"
-
-stringify-object@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629"
- integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==
- dependencies:
- get-own-enumerable-property-symbols "^3.0.0"
- is-obj "^1.0.1"
- is-regexp "^1.0.0"
-
-strip-ansi@6.0.0, strip-ansi@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
- integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
- dependencies:
- ansi-regex "^5.0.0"
-
-strip-ansi@^3.0.0, strip-ansi@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
- integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
- dependencies:
- ansi-regex "^2.0.0"
-
-strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
- integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
- dependencies:
- ansi-regex "^4.1.0"
-
-strip-bom-string@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92"
- integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=
-
-strip-eof@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
- integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
-
-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-json-comments@~2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
- integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
-
-style-to-object@0.3.0, style-to-object@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46"
- integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==
- dependencies:
- inline-style-parser "0.1.1"
-
-stylehacks@^4.0.0:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5"
- integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==
- dependencies:
- browserslist "^4.0.0"
- postcss "^7.0.0"
- postcss-selector-parser "^3.0.0"
-
-supports-color@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
- integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
-
-supports-color@^5.3.0:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
- integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
- dependencies:
- has-flag "^3.0.0"
-
-supports-color@^6.1.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3"
- integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==
- dependencies:
- has-flag "^3.0.0"
-
-supports-color@^7.0.0, supports-color@^7.1.0:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
- integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
- dependencies:
- has-flag "^4.0.0"
-
-supports-preserve-symlinks-flag@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
- integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-
-svg-parser@^2.0.2:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5"
- integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==
-
-svgo@^1.0.0, svgo@^1.2.2:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167"
- integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==
- dependencies:
- chalk "^2.4.1"
- coa "^2.0.2"
- css-select "^2.0.0"
- css-select-base-adapter "^0.1.1"
- css-tree "1.0.0-alpha.37"
- csso "^4.0.2"
- js-yaml "^3.13.1"
- mkdirp "~0.5.1"
- object.values "^1.1.0"
- sax "~1.2.4"
- stable "^0.1.8"
- unquote "~1.1.1"
- util.promisify "~1.0.0"
-
-tapable@^1.0.0, tapable@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
- integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
-
-tar@^6.0.2:
- version "6.1.11"
- resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
- integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==
- dependencies:
- chownr "^2.0.0"
- fs-minipass "^2.0.0"
- minipass "^3.0.0"
- minizlib "^2.1.1"
- mkdirp "^1.0.3"
- yallist "^4.0.0"
-
-term-size@^2.1.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54"
- integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==
-
-terser-webpack-plugin@^1.4.3:
- version "1.4.5"
- resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b"
- integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==
- dependencies:
- cacache "^12.0.2"
- find-cache-dir "^2.1.0"
- is-wsl "^1.1.0"
- schema-utils "^1.0.0"
- serialize-javascript "^4.0.0"
- source-map "^0.6.1"
- terser "^4.1.2"
- webpack-sources "^1.4.0"
- worker-farm "^1.7.0"
-
-terser-webpack-plugin@^4.1.0:
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz#28daef4a83bd17c1db0297070adc07fc8cfc6a9a"
- integrity sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==
- dependencies:
- cacache "^15.0.5"
- find-cache-dir "^3.3.1"
- jest-worker "^26.5.0"
- p-limit "^3.0.2"
- schema-utils "^3.0.0"
- serialize-javascript "^5.0.1"
- source-map "^0.6.1"
- terser "^5.3.4"
- webpack-sources "^1.4.3"
-
-terser@^4.1.2, terser@^4.6.3:
- version "4.8.0"
- resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17"
- integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==
- dependencies:
- commander "^2.20.0"
- source-map "~0.6.1"
- source-map-support "~0.5.12"
-
-terser@^5.3.4:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.1.tgz#2dc7a61009b66bb638305cb2a824763b116bf784"
- integrity sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==
- dependencies:
- commander "^2.20.0"
- source-map "~0.7.2"
- source-map-support "~0.5.19"
-
-text-table@0.2.0, text-table@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
- integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
-
-through2@^2.0.0:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
- integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
- dependencies:
- readable-stream "~2.3.6"
- xtend "~4.0.1"
-
-through@^2.3.6:
- version "2.3.8"
- resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
- integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
-
-thunky@^1.0.2:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
- integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==
-
-timers-browserify@^2.0.4:
- version "2.0.12"
- resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee"
- integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==
- dependencies:
- setimmediate "^1.0.4"
-
-timsort@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
- integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
-
-tiny-invariant@^1.0.2:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875"
- integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==
-
-tiny-warning@^1.0.0, tiny-warning@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
- integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
-
-tmp@^0.0.33:
- version "0.0.33"
- resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
- integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
- dependencies:
- os-tmpdir "~1.0.2"
-
-to-arraybuffer@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
- integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
-
-to-fast-properties@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
- integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
-
-to-object-path@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
- integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=
- dependencies:
- kind-of "^3.0.2"
-
-to-readable-stream@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771"
- integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==
-
-to-regex-range@^2.1.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
- integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=
- dependencies:
- is-number "^3.0.0"
- repeat-string "^1.6.1"
-
-to-regex-range@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
- integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
- dependencies:
- is-number "^7.0.0"
-
-to-regex@^3.0.1, to-regex@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
- integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
- dependencies:
- define-property "^2.0.2"
- extend-shallow "^3.0.2"
- regex-not "^1.0.2"
- safe-regex "^1.1.0"
-
-toidentifier@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
- integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
-
-tr46@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
- integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=
- dependencies:
- punycode "^2.1.0"
-
-trim-trailing-lines@^1.0.0:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz#bd4abbec7cc880462f10b2c8b5ce1d8d1ec7c2c0"
- integrity sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==
-
-trim@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd"
- integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0=
-
-trough@^1.0.0:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406"
- integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==
-
-tryer@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
- integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
-
-ts-essentials@^2.0.3:
- version "2.0.12"
- resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-2.0.12.tgz#c9303f3d74f75fa7528c3d49b80e089ab09d8745"
- integrity sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==
-
-ts-pnp@^1.1.6:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92"
- integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==
-
-tslib@^1.9.0:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
- integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
-
-tslib@^2.0.3:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
- integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
-
-tty-browserify@0.0.0:
- version "0.0.0"
- resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
- integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=
-
-type-fest@^0.21.3:
- version "0.21.3"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
- integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
-
-type-fest@^0.8.1:
- version "0.8.1"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
- integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
-
-type-is@~1.6.17, type-is@~1.6.18:
- version "1.6.18"
- resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
- integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
- dependencies:
- media-typer "0.3.0"
- mime-types "~2.1.24"
-
-typedarray-to-buffer@^3.1.5:
- version "3.1.5"
- resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
- integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
- dependencies:
- is-typedarray "^1.0.0"
-
-typedarray@^0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
- integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-
-ua-parser-js@^0.7.18:
- version "0.7.28"
- resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31"
- integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==
-
-unbox-primitive@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471"
- integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==
- dependencies:
- function-bind "^1.1.1"
- has-bigints "^1.0.1"
- has-symbols "^1.0.2"
- which-boxed-primitive "^1.0.2"
-
-unherit@^1.0.4:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22"
- integrity sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==
- dependencies:
- inherits "^2.0.0"
- xtend "^4.0.0"
-
-unicode-canonical-property-names-ecmascript@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
- integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==
-
-unicode-match-property-ecmascript@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c"
- integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==
- dependencies:
- unicode-canonical-property-names-ecmascript "^1.0.4"
- unicode-property-aliases-ecmascript "^1.0.4"
-
-unicode-match-property-value-ecmascript@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531"
- integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==
-
-unicode-property-aliases-ecmascript@^1.0.4:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4"
- integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==
-
-unified@9.2.0:
- version "9.2.0"
- resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.0.tgz#67a62c627c40589edebbf60f53edfd4d822027f8"
- integrity sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==
- dependencies:
- bail "^1.0.0"
- extend "^3.0.0"
- is-buffer "^2.0.0"
- is-plain-obj "^2.0.0"
- trough "^1.0.0"
- vfile "^4.0.0"
-
-unified@^8.4.2:
- version "8.4.2"
- resolved "https://registry.yarnpkg.com/unified/-/unified-8.4.2.tgz#13ad58b4a437faa2751a4a4c6a16f680c500fff1"
- integrity sha512-JCrmN13jI4+h9UAyKEoGcDZV+i1E7BLFuG7OsaDvTXI5P0qhHX+vZO/kOhz9jn8HGENDKbwSeB0nVOg4gVStGA==
- dependencies:
- bail "^1.0.0"
- extend "^3.0.0"
- is-plain-obj "^2.0.0"
- trough "^1.0.0"
- vfile "^4.0.0"
-
-union-value@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
- integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
- dependencies:
- arr-union "^3.1.0"
- get-value "^2.0.6"
- is-extendable "^0.1.1"
- set-value "^2.0.1"
-
-uniq@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
- integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=
-
-uniqs@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
- integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI=
-
-unique-filename@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"
- integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==
- dependencies:
- unique-slug "^2.0.0"
-
-unique-slug@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c"
- integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==
- dependencies:
- imurmurhash "^0.1.4"
-
-unique-string@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
- integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==
- dependencies:
- crypto-random-string "^2.0.0"
-
-unist-builder@2.0.3, unist-builder@^2.0.0:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-2.0.3.tgz#77648711b5d86af0942f334397a33c5e91516436"
- integrity sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==
-
-unist-util-generated@^1.0.0:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-1.1.6.tgz#5ab51f689e2992a472beb1b35f2ce7ff2f324d4b"
- integrity sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==
-
-unist-util-is@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797"
- integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==
-
-unist-util-position@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-3.1.0.tgz#1c42ee6301f8d52f47d14f62bbdb796571fa2d47"
- integrity sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==
-
-unist-util-remove-position@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz#5d19ca79fdba712301999b2b73553ca8f3b352cc"
- integrity sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==
- dependencies:
- unist-util-visit "^2.0.0"
-
-unist-util-remove@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/unist-util-remove/-/unist-util-remove-2.1.0.tgz#b0b4738aa7ee445c402fda9328d604a02d010588"
- integrity sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==
- dependencies:
- unist-util-is "^4.0.0"
-
-unist-util-stringify-position@^2.0.0:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da"
- integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==
- dependencies:
- "@types/unist" "^2.0.2"
-
-unist-util-visit-parents@^3.0.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz#65a6ce698f78a6b0f56aa0e88f13801886cdaef6"
- integrity sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==
- dependencies:
- "@types/unist" "^2.0.0"
- unist-util-is "^4.0.0"
-
-unist-util-visit@2.0.3, unist-util-visit@^2.0.0, unist-util-visit@^2.0.1, unist-util-visit@^2.0.2, unist-util-visit@^2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.3.tgz#c3703893146df47203bb8a9795af47d7b971208c"
- integrity sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==
- dependencies:
- "@types/unist" "^2.0.0"
- unist-util-is "^4.0.0"
- unist-util-visit-parents "^3.0.0"
-
-universalify@^0.1.0:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
- integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
-
-unpipe@1.0.0, unpipe@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
- integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
-
-unquote@~1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544"
- integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=
-
-unset-value@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
- integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=
- dependencies:
- has-value "^0.3.1"
- isobject "^3.0.0"
-
-upath@^1.1.1:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
- integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==
-
-update-notifier@^4.1.0:
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3"
- integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==
- dependencies:
- boxen "^4.2.0"
- chalk "^3.0.0"
- configstore "^5.0.1"
- has-yarn "^2.1.0"
- import-lazy "^2.1.0"
- is-ci "^2.0.0"
- is-installed-globally "^0.3.1"
- is-npm "^4.0.0"
- is-yarn-global "^0.3.0"
- latest-version "^5.0.0"
- pupa "^2.0.1"
- semver-diff "^3.1.1"
- xdg-basedir "^4.0.0"
-
-uri-js@^4.2.2:
- version "4.4.1"
- resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
- integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
- dependencies:
- punycode "^2.1.0"
-
-urix@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
- integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
-
-url-loader@^4.1.0:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2"
- integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==
- dependencies:
- loader-utils "^2.0.0"
- mime-types "^2.1.27"
- schema-utils "^3.0.0"
-
-url-parse-lax@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c"
- integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=
- dependencies:
- prepend-http "^2.0.0"
-
-url-parse@^1.4.3, url-parse@^1.5.1:
- version "1.5.3"
- resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862"
- integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==
- dependencies:
- querystringify "^2.1.1"
- requires-port "^1.0.0"
-
-url@^0.11.0:
- version "0.11.0"
- resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
- integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=
- dependencies:
- punycode "1.3.2"
- querystring "0.2.0"
-
-use-composed-ref@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.1.0.tgz#9220e4e94a97b7b02d7d27eaeab0b37034438bbc"
- integrity sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg==
- dependencies:
- ts-essentials "^2.0.3"
-
-use-isomorphic-layout-effect@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz#7bb6589170cd2987a152042f9084f9effb75c225"
- integrity sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==
-
-use-latest@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.2.0.tgz#a44f6572b8288e0972ec411bdd0840ada366f232"
- integrity sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==
- dependencies:
- use-isomorphic-layout-effect "^1.0.0"
-
-use-onclickoutside@^0.3.1:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/use-onclickoutside/-/use-onclickoutside-0.3.2.tgz#1681704055463295a34236dee43d5911c6c3c418"
- integrity sha512-7P+U4B6nUlWLtmktuF6KTNg9mzxf7VqnBVxv418i3SQytw68/19Fk8hUW1uZjZv3DGHtGEwLa4vnjbm5sPL2ZQ==
- dependencies:
- are-passive-events-supported "^1.1.0"
- use-latest "^1.0.0"
-
-use@^3.1.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
- integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
-
-util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
- integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
-
-util.promisify@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030"
- integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==
- dependencies:
- define-properties "^1.1.2"
- object.getownpropertydescriptors "^2.0.3"
-
-util.promisify@~1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee"
- integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==
- dependencies:
- define-properties "^1.1.3"
- es-abstract "^1.17.2"
- has-symbols "^1.0.1"
- object.getownpropertydescriptors "^2.1.0"
-
-util@0.10.3:
- version "0.10.3"
- resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
- integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk=
- dependencies:
- inherits "2.0.1"
-
-util@^0.11.0:
- version "0.11.1"
- resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61"
- integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==
- dependencies:
- inherits "2.0.3"
-
-utila@~0.4:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
- integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=
-
-utility-types@^3.10.0:
- version "3.10.0"
- resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b"
- integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==
-
-utils-merge@1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
- integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
-
-uuid@^3.3.2, uuid@^3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
- integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
-
-value-equal@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c"
- integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==
-
-vary@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
- integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
-
-vendors@^1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e"
- integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==
-
-vfile-location@^3.0.0, vfile-location@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.2.0.tgz#d8e41fbcbd406063669ebf6c33d56ae8721d0f3c"
- integrity sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==
-
-vfile-message@^2.0.0:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a"
- integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==
- dependencies:
- "@types/unist" "^2.0.0"
- unist-util-stringify-position "^2.0.0"
-
-vfile@^4.0.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624"
- integrity sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==
- dependencies:
- "@types/unist" "^2.0.0"
- is-buffer "^2.0.0"
- unist-util-stringify-position "^2.0.0"
- vfile-message "^2.0.0"
-
-vm-browserify@^1.0.1:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
- integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
-
-wait-file@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/wait-file/-/wait-file-1.0.5.tgz#377f48795f1765046a41bb0671c142ef8e509ae6"
- integrity sha512-udLpJY/eOxlrMm3+XD1RLuF2oT9B7J7wiyR5/9xrvQymS6YR6trWvVhzOldHrVbLwyiRmLj9fcvsjzpSXeZHkw==
- dependencies:
- "@hapi/joi" "^15.1.0"
- fs-extra "^8.1.0"
- rx "^4.1.0"
-
-watchpack-chokidar2@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957"
- integrity sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==
- dependencies:
- chokidar "^2.1.8"
-
-watchpack@^1.7.4:
- version "1.7.5"
- resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453"
- integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==
- dependencies:
- graceful-fs "^4.1.2"
- neo-async "^2.5.0"
- optionalDependencies:
- chokidar "^3.4.1"
- watchpack-chokidar2 "^2.0.1"
-
-wbuf@^1.1.0, wbuf@^1.7.3:
- version "1.7.3"
- resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df"
- integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==
- dependencies:
- minimalistic-assert "^1.0.0"
-
-web-namespaces@^1.0.0, web-namespaces@^1.1.2:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec"
- integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==
-
-webidl-conversions@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
- integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
-
-webpack-bundle-analyzer@^3.6.1:
- version "3.9.0"
- resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.0.tgz#f6f94db108fb574e415ad313de41a2707d33ef3c"
- integrity sha512-Ob8amZfCm3rMB1ScjQVlbYYUEJyEjdEtQ92jqiFUYt5VkEeO2v5UMbv49P/gnmCZm3A6yaFQzCBvpZqN4MUsdA==
- dependencies:
- acorn "^7.1.1"
- acorn-walk "^7.1.1"
- bfj "^6.1.1"
- chalk "^2.4.1"
- commander "^2.18.0"
- ejs "^2.6.1"
- express "^4.16.3"
- filesize "^3.6.1"
- gzip-size "^5.0.0"
- lodash "^4.17.19"
- mkdirp "^0.5.1"
- opener "^1.5.1"
- ws "^6.0.0"
-
-webpack-dev-middleware@^3.7.2:
- version "3.7.3"
- resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5"
- integrity sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==
- dependencies:
- memory-fs "^0.4.1"
- mime "^2.4.4"
- mkdirp "^0.5.1"
- range-parser "^1.2.1"
- webpack-log "^2.0.0"
-
-webpack-dev-server@^3.11.0:
- version "3.11.2"
- resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz#695ebced76a4929f0d5de7fd73fafe185fe33708"
- integrity sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ==
- dependencies:
- ansi-html "0.0.7"
- bonjour "^3.5.0"
- chokidar "^2.1.8"
- compression "^1.7.4"
- connect-history-api-fallback "^1.6.0"
- debug "^4.1.1"
- del "^4.1.1"
- express "^4.17.1"
- html-entities "^1.3.1"
- http-proxy-middleware "0.19.1"
- import-local "^2.0.0"
- internal-ip "^4.3.0"
- ip "^1.1.5"
- is-absolute-url "^3.0.3"
- killable "^1.0.1"
- loglevel "^1.6.8"
- opn "^5.5.0"
- p-retry "^3.0.1"
- portfinder "^1.0.26"
- schema-utils "^1.0.0"
- selfsigned "^1.10.8"
- semver "^6.3.0"
- serve-index "^1.9.1"
- sockjs "^0.3.21"
- sockjs-client "^1.5.0"
- spdy "^4.0.2"
- strip-ansi "^3.0.1"
- supports-color "^6.1.0"
- url "^0.11.0"
- webpack-dev-middleware "^3.7.2"
- webpack-log "^2.0.0"
- ws "^6.2.1"
- yargs "^13.3.2"
-
-webpack-log@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f"
- integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==
- dependencies:
- ansi-colors "^3.0.0"
- uuid "^3.3.2"
-
-webpack-merge@^4.2.2:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d"
- integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==
- dependencies:
- lodash "^4.17.15"
-
-webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3:
- version "1.4.3"
- resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
- integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
- dependencies:
- source-list-map "^2.0.0"
- source-map "~0.6.1"
-
-webpack@^4.44.1:
- version "4.46.0"
- resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542"
- integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-module-context" "1.9.0"
- "@webassemblyjs/wasm-edit" "1.9.0"
- "@webassemblyjs/wasm-parser" "1.9.0"
- acorn "^6.4.1"
- ajv "^6.10.2"
- ajv-keywords "^3.4.1"
- chrome-trace-event "^1.0.2"
- enhanced-resolve "^4.5.0"
- eslint-scope "^4.0.3"
- json-parse-better-errors "^1.0.2"
- loader-runner "^2.4.0"
- loader-utils "^1.2.3"
- memory-fs "^0.4.1"
- micromatch "^3.1.10"
- mkdirp "^0.5.3"
- neo-async "^2.6.1"
- node-libs-browser "^2.2.1"
- schema-utils "^1.0.0"
- tapable "^1.1.3"
- terser-webpack-plugin "^1.4.3"
- watchpack "^1.7.4"
- webpack-sources "^1.4.1"
-
-webpackbar@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/webpackbar/-/webpackbar-4.0.0.tgz#ee7a87f16077505b5720551af413c8ecd5b1f780"
- integrity sha512-k1qRoSL/3BVuINzngj09nIwreD8wxV4grcuhHTD8VJgUbGcy8lQSPqv+bM00B7F+PffwIsQ8ISd4mIwRbr23eQ==
- dependencies:
- ansi-escapes "^4.2.1"
- chalk "^2.4.2"
- consola "^2.10.0"
- figures "^3.0.0"
- pretty-time "^1.1.0"
- std-env "^2.2.1"
- text-table "^0.2.0"
- wrap-ansi "^6.0.0"
-
-websocket-driver@>=0.5.1, websocket-driver@^0.7.4:
- version "0.7.4"
- resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760"
- integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==
- dependencies:
- http-parser-js ">=0.5.1"
- safe-buffer ">=5.1.0"
- websocket-extensions ">=0.1.1"
-
-websocket-extensions@>=0.1.1:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42"
- integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==
-
-whatwg-url@^7.0.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"
- integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==
- dependencies:
- lodash.sortby "^4.7.0"
- tr46 "^1.0.1"
- webidl-conversions "^4.0.2"
-
-which-boxed-primitive@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
- integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
- dependencies:
- is-bigint "^1.0.1"
- is-boolean-object "^1.1.0"
- is-number-object "^1.0.4"
- is-string "^1.0.5"
- is-symbol "^1.0.3"
-
-which-module@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
- integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
-
-which@^1.2.9, which@^1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
- integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
- dependencies:
- isexe "^2.0.0"
-
-which@^2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
- integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
- dependencies:
- isexe "^2.0.0"
-
-widest-line@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca"
- integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==
- dependencies:
- string-width "^4.0.0"
-
-worker-farm@^1.7.0:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8"
- integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==
- dependencies:
- errno "~0.1.7"
-
-worker-rpc@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5"
- integrity sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==
- dependencies:
- microevent.ts "~0.1.1"
-
-wrap-ansi@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
- integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==
- dependencies:
- ansi-styles "^3.2.0"
- string-width "^3.0.0"
- strip-ansi "^5.0.0"
-
-wrap-ansi@^6.0.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
- integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
-
-wrappy@1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
- integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
-
-write-file-atomic@^3.0.0:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
- integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==
- dependencies:
- imurmurhash "^0.1.4"
- is-typedarray "^1.0.0"
- signal-exit "^3.0.2"
- typedarray-to-buffer "^3.1.5"
-
-ws@^6.0.0, ws@^6.2.1:
- version "6.2.2"
- resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e"
- integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==
- dependencies:
- async-limiter "~1.0.0"
-
-xdg-basedir@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
- integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
-
-xml-js@^1.6.11:
- version "1.6.11"
- resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9"
- integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==
- dependencies:
- sax "^1.2.4"
-
-xmlbuilder@^13.0.0:
- version "13.0.2"
- resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-13.0.2.tgz#02ae33614b6a047d1c32b5389c1fdacb2bce47a7"
- integrity sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==
-
-xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
- integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
-
-y18n@^4.0.0:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
- integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==
-
-yallist@^3.0.2:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
- integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
-
-yallist@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
- integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
-
-yaml@^1.10.0:
- version "1.10.2"
- resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
- integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
-
-yargs-parser@^13.1.2:
- version "13.1.2"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"
- integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==
- dependencies:
- camelcase "^5.0.0"
- decamelize "^1.2.0"
-
-yargs@^13.3.2:
- version "13.3.2"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"
- integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==
- dependencies:
- cliui "^5.0.0"
- find-up "^3.0.0"
- get-caller-file "^2.0.1"
- require-directory "^2.1.1"
- require-main-filename "^2.0.0"
- set-blocking "^2.0.0"
- string-width "^3.0.0"
- which-module "^2.0.0"
- y18n "^4.0.0"
- yargs-parser "^13.1.2"
-
-yocto-queue@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
- integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
-
-zwitch@^1.0.0:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920"
- integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==
diff --git a/instapy/__init__.py b/instapy/__init__.py
deleted file mode 100644
index caca94c58..000000000
--- a/instapy/__init__.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# flake8: noqa
-
-# __variables__ with double-quoted values will be available in setup.py
-__version__ = "0.6.16"
-
-from .instapy import InstaPy
-from .util import smart_run
-from .settings import Settings
-from .file_manager import set_workspace
-from .file_manager import get_workspace
diff --git a/instapy/browser.py b/instapy/browser.py
deleted file mode 100644
index dceb79c3d..000000000
--- a/instapy/browser.py
+++ /dev/null
@@ -1,317 +0,0 @@
-# import built-in & third-party modules
-import os
-import zipfile
-import shutil
-
-from os.path import sep
-from selenium import webdriver
-from selenium.webdriver.common.keys import Keys
-from selenium.webdriver.firefox.options import Options as Firefox_Options
-from selenium.webdriver import Remote
-from webdriverdownloader import GeckoDriverDownloader
-
-# import InstaPy modules
-from .util import interruption_handler
-from .util import highlight_print
-from .util import emergency_exit
-from .util import get_current_url
-from .util import check_authorization
-from .util import web_address_navigator
-from .file_manager import use_assets
-from .settings import Settings
-from .time_util import sleep
-
-# import exceptions
-from selenium.common.exceptions import WebDriverException
-from selenium.common.exceptions import UnexpectedAlertPresentException
-
-
-def get_geckodriver():
- # prefer using geckodriver from path
- gecko_path = shutil.which("geckodriver") or shutil.which("geckodriver.exe")
- if gecko_path:
- return gecko_path
-
- asset_path = use_assets()
- gdd = GeckoDriverDownloader(asset_path, asset_path)
- # skips download if already downloaded
- sym_path = gdd.download_and_install()[1]
- return sym_path
-
-
-def create_firefox_extension():
- ext_path = os.path.abspath(os.path.dirname(__file__) + sep + "firefox_extension")
- # safe into assets folder
- zip_file = use_assets() + sep + "extension.xpi"
-
- files = ["manifest.json", "content.js", "arrive.js"]
- with zipfile.ZipFile(zip_file, "w", zipfile.ZIP_DEFLATED, False) as zipf:
- for file in files:
- zipf.write(ext_path + sep + file, file)
-
- return zip_file
-
-
-def set_selenium_local_session(
- proxy_address,
- proxy_port,
- proxy_username,
- proxy_password,
- headless_browser,
- browser_profile_path,
- disable_image_load,
- page_delay,
- geckodriver_path,
- browser_executable_path,
- logfolder,
- logger,
- geckodriver_log_level,
-):
- """Starts local session for a selenium server.
- Default case scenario."""
-
- browser = None
- err_msg = ""
-
- firefox_options = Firefox_Options()
-
- if headless_browser:
- firefox_options.add_argument("-headless")
-
- if browser_profile_path is not None:
- firefox_profile = webdriver.FirefoxProfile(browser_profile_path)
- else:
- firefox_profile = webdriver.FirefoxProfile()
-
- if browser_executable_path is not None:
- firefox_options.binary = browser_executable_path
-
- # set "info" by default
- # set "trace" for debubging, Development only
- firefox_options.log.level = geckodriver_log_level
-
- # set English language
- firefox_profile.set_preference("intl.accept_languages", "en-US")
- firefox_profile.set_preference("general.useragent.override", Settings.user_agent)
-
- if disable_image_load:
- # permissions.default.image = 2: Disable images load,
- # this setting can improve pageload & save bandwidth
- firefox_profile.set_preference("permissions.default.image", 2)
-
- if proxy_address and proxy_port:
- firefox_profile.set_preference("network.proxy.type", 1)
- firefox_profile.set_preference("network.proxy.http", proxy_address)
- firefox_profile.set_preference("network.proxy.http_port", int(proxy_port))
- firefox_profile.set_preference("network.proxy.ssl", proxy_address)
- firefox_profile.set_preference("network.proxy.ssl_port", int(proxy_port))
-
- # mute audio while watching stories
- firefox_profile.set_preference("media.volume_scale", "0.0")
-
- # prevent Hide Selenium Extension: error
- firefox_profile.set_preference("dom.webdriver.enabled", False)
- firefox_profile.set_preference("useAutomationExtension", False)
- firefox_profile.set_preference("general.platform.override", "iPhone")
- firefox_profile.update_preferences()
-
- # geckodriver log in specific user logfolder
- geckodriver_log = "{}geckodriver.log".format(logfolder)
-
- # prefer user path before downloaded one
- driver_path = geckodriver_path or get_geckodriver()
- browser = webdriver.Firefox(
- firefox_profile=firefox_profile,
- executable_path=driver_path,
- log_path=geckodriver_log,
- options=firefox_options,
- )
-
- # add extension to hide selenium
- browser.install_addon(create_firefox_extension(), temporary=True)
-
- # converts to custom browser
- # browser = convert_selenium_browser(browser)
-
- # authenticate with popup alert window
- if proxy_username and proxy_password:
- proxy_authentication(browser, logger, proxy_username, proxy_password)
-
- browser.implicitly_wait(page_delay)
-
- # Apple iPhone X: 375, 812
- # Apple iPhone XS Max: 414, 896
- try:
- browser.set_window_size(414, 896)
- except UnexpectedAlertPresentException as exc:
- logger.exception(
- "Unexpected alert on resizing web browser!\n\t"
- "{}".format(str(exc).encode("utf-8"))
- )
- close_browser(browser, False, logger)
- return browser, "Unexpected alert on browser resize"
-
- message = "Session started!"
- highlight_print("browser", message, "initialization", "info", logger)
-
- return browser, err_msg
-
-
-def proxy_authentication(browser, logger, proxy_username, proxy_password):
- """Authenticate proxy using popup alert window"""
-
- # FIXME: https://github.com/SeleniumHQ/selenium/issues/7239
- # this feature is not working anymore due to the Selenium bug report above
- logger.warning(
- "Proxy Authentication is not working anymore due to the Selenium bug "
- "report: https://github.com/SeleniumHQ/selenium/issues/7239"
- )
-
- try:
- # sleep(1) is enough, sleep(2) is to make sure we
- # give time to the popup windows
- sleep(2)
- alert_popup = browser.switch_to_alert()
- alert_popup.send_keys(
- "{username}{tab}{password}{tab}".format(
- username=proxy_username, tab=Keys.TAB, password=proxy_password
- )
- )
- alert_popup.accept()
- except Exception:
- logger.warning("Unable to proxy authenticate")
-
-
-def close_browser(browser, threaded_session, logger):
- with interruption_handler(threaded=threaded_session):
- # delete cookies
- try:
- browser.delete_all_cookies()
- except Exception as exc:
- if isinstance(exc, WebDriverException):
- logger.exception(
- "Error occurred while deleting cookies "
- "from web browser!\n\t{}".format(str(exc).encode("utf-8"))
- )
-
- # close web browser
- try:
- browser.quit()
- except Exception as exc:
- if isinstance(exc, WebDriverException):
- logger.exception(
- "Error occurred while "
- "closing web browser!\n\t{}".format(str(exc).encode("utf-8"))
- )
-
-
-def retry(max_retry_count=3, start_page=None):
- """
- Decorator which refreshes the page and tries to execute the function again.
- Use it like that: @retry() => the '()' are important because its a decorator
- with params.
- """
-
- def real_decorator(org_func):
- def wrapper(*args, **kwargs):
- browser = None
- _start_page = start_page
-
- # try to find instance of a browser in the arguments
- # all webdriver classes (chrome, firefox, ...) inherit from Remote class
- for arg in args:
- if not isinstance(arg, Remote):
- continue
-
- browser = arg
- break
-
- else:
- for _, value in kwargs.items():
- if not isinstance(value, Remote):
- continue
-
- browser = value
- break
-
- if not browser:
- print("not able to find browser in parameters!")
- return org_func(*args, **kwargs)
-
- if max_retry_count == 0:
- print("max retry count is set to 0, this function is useless right now")
- return org_func(*args, **kwargs)
-
- # get current page if none is given
- if not start_page:
- _start_page = browser.current_url
-
- rv = None
- retry_count = 0
- while True:
- try:
- rv = org_func(*args, **kwargs)
- break
- except Exception as e:
- # TODO: maybe handle only certain exceptions here
- retry_count += 1
-
- # if above max retries => throw original exception
- if retry_count > max_retry_count:
- raise e
-
- rv = None
-
- # refresh page
- browser.get(_start_page)
-
- return rv
-
- return wrapper
-
- return real_decorator
-
-
-class custom_browser(Remote):
- """Custom browser instance for manipulation later on"""
-
- def find_element_by_xpath(self, *args, **kwargs):
- """example usage of hooking into built in functions"""
- rv = super(custom_browser, self).find_element_by_xpath(*args, **kwargs)
- return rv
-
- def wait_for_valid_connection(self, username, logger):
- counter = 0
- while True and counter < 10:
- sirens_wailing, emergency_state = emergency_exit(self, username, logger)
- if sirens_wailing and emergency_state == "not connected":
- logger.warning("there is no valid connection")
- counter += 1
- sleep(60)
- else:
- break
-
- def wait_for_valid_authorization(self, username, logger):
- # save current page
- current_url = get_current_url(self)
-
- # stuck on invalid auth
- auth_method = "activity counts"
- counter = 0
- while True and counter < 10:
- login_state = check_authorization(self, username, auth_method, logger)
- if login_state is False:
- logger.warning("not logged in")
- counter += 1
- sleep(60)
- else:
- break
-
- # return to original page
- web_address_navigator(self, current_url)
-
-
-def convert_selenium_browser(driver):
- """Changed the class to our custom class"""
- driver.__class__ = custom_browser
- return driver
diff --git a/instapy/clarifai_util.py b/instapy/clarifai_util.py
deleted file mode 100644
index d2d0dec42..000000000
--- a/instapy/clarifai_util.py
+++ /dev/null
@@ -1,251 +0,0 @@
-"""Module which handles the clarifai api and checks
-the image for invalid content"""
-from clarifai.rest import ClarifaiApp, Workflow
-from selenium.common.exceptions import NoSuchElementException
-from selenium.webdriver.common.by import By
-
-from .xpath import read_xpath
-
-
-def check_image(
- browser,
- clarifai_api_key,
- img_tags,
- img_tags_skip_if_contain,
- logger,
- clarifai_models,
- workflow,
- probability,
- full_match=False,
- check_video=False,
- proxy=None,
- picture_url=None,
-):
- try:
- """Uses the link to the image to check for invalid content in the
- image.
- If a workflow has been selected, get list of tags from Clarifai API
- by checking link against models included in the workflow. If a workflow
- hasn't been provided, InstaPy will check images against given model(
- s)"""
- clarifai_api = ClarifaiApp(api_key=clarifai_api_key)
- clarifai_tags = []
-
- if proxy is not None:
- clarifai_api.api.session.proxies = {"https": proxy}
- # Set req image or video source URL to given one or get it from
- # current page
- if picture_url is None:
- source_link = get_source_link(browser)
- else:
- source_link = [picture_url]
-
- # No image in page
- if not source_link:
- return True, [], []
-
- # Check image using workflow if provided. If no workflow,
- # check image using model(s)
- if workflow:
- clarifai_workflow = Workflow(clarifai_api.api, workflow_id=workflow[0])
- # If source is video, checks keyframe against models as video
- # inputs not supported when using workflows
- if source_link[0].endswith("mp4"):
- clarifai_response = clarifai_workflow.predict_by_url(source_link[1])
- else:
- clarifai_response = clarifai_workflow.predict_by_url(source_link[0])
-
- for response in clarifai_response["results"][0]["outputs"]:
- results = get_clarifai_tags(response, probability)
- clarifai_tags.extend(results)
- else:
- for model in clarifai_models:
- clarifai_response = get_clarifai_response(
- clarifai_api, model, source_link, check_video
- )
- results = get_clarifai_tags(
- clarifai_response["outputs"][0], probability
- )
- clarifai_tags.extend(results)
-
- logger.info(
- "source_link {} got predicted result(s):\n{}".format(
- source_link, clarifai_tags
- )
- )
-
- # Will not comment on an image if any of the tags in
- # img_tags_skip_if_contain are matched
- if given_tags_in_result(img_tags_skip_if_contain, clarifai_tags):
- logger.info(
- 'Not Commenting, image contains concept(s): "{}".'.format(
- ", ".join(list(set(clarifai_tags) & set(img_tags_skip_if_contain)))
- )
- )
- return False, [], clarifai_tags
-
- for (tags, should_comment, comments) in img_tags:
- if should_comment and given_tags_in_result(tags, clarifai_tags, full_match):
- return True, comments, clarifai_tags
- elif given_tags_in_result(tags, clarifai_tags, full_match):
- logger.info(
- 'Not Commenting, image contains concept(s): "{}".'.format(
- ", ".join(list(set(clarifai_tags) & set(tags)))
- )
- )
- return False, [], clarifai_tags
-
- return True, [], clarifai_tags
-
- except Exception as err:
- logger.error("Image check error: {}".format(err))
-
-
-def given_tags_in_result(search_tags, clarifai_tags, full_match=False):
- """Checks the clarifai tags if it contains one (or all) search tags"""
- if full_match:
- return all([tag in clarifai_tags for tag in search_tags])
- else:
- return any((tag in clarifai_tags for tag in search_tags))
-
-
-def get_source_link(browser):
- """Checks to see if a post is an image. If so, returns list with image
- source URL.
- If a NoSuchElement exception occurs, checks post for video and returns
- the source URLs
- for both the video and the video's keyframe."""
- source = []
-
- try:
- source.append(
- browser.find_element(
- By.XPATH, read_xpath(get_source_link.__name__, "image")
- ).get_attribute("src")
- )
- except NoSuchElementException:
- source.append(
- browser.find_element(
- By.XPATH, read_xpath(get_source_link.__name__, "video")
- ).get_attribute("src")
- )
- source.append(
- browser.find_element(
- By.XPATH, read_xpath(get_source_link.__name__, "image_alt")
- ).get_attribute("src")
- )
-
- return source
-
-
-def get_clarifai_response(clarifai_api, clarifai_model, source_link, check_video):
- """Compiles a list of tags from Clarifai using the chosen models.
- First checks the value of each item in the models list against a
- dictionary. If the model value provided does not match one of the
- keys in the dictionary below, model value is used in
- clarifai_api.models.get(). Useful for custom models."""
- # List of models which support video inputs
- video_models = ["apparel", "food", "general", "nsfw", "travel", "wedding"]
- clarifai_models = {
- "general": "general-v1.3",
- "nsfw": "nsfw-v1.0",
- "apparel": "apparel",
- "celebrity": "celeb-v1.3",
- "color": "color",
- "demographics": "demographics",
- "food": "food-items-v1.0",
- "landscape quality": "Landscape Quality",
- "logo": "logo",
- "moderation": "moderation",
- "portrait quality": "Portrait Quality",
- "textures": "Textures & Patterns",
- "travel": "travel-v1.0",
- "weddings": "weddings-v1.0",
- }
-
- model = clarifai_api.models.get(
- clarifai_models.get(clarifai_model.lower(), clarifai_model)
- )
- # Get response from Clarifai API
- # If source is video, model accepts video inputs and check_video is
- # True, analyze content of frames in video
- if (
- check_video
- and source_link[0].endswith("mp4")
- and clarifai_model.lower() in video_models
- ):
- response = model.predict_by_url(source_link[0], is_video=True)
- # If source is video but model does not accept video inputs or
- # check_video is False, analyze content of keyframe
- elif source_link[0].endswith("mp4"):
- response = model.predict_by_url(source_link[1])
- else:
- response = model.predict_by_url(source_link[0])
-
- return response
-
-
-def get_clarifai_tags(clarifai_response, probability):
- """Get the response from the Clarifai API and return results filtered by
- concepts with a confidence set by probability parameter (default 50%)"""
- results = []
- concepts = []
-
- # Parse response for Color model
- try:
- concepts = [
- {concept.get("w3c", {}).get("name").lower(): concept.get("value")}
- for concept in clarifai_response["data"]["colors"]
- ]
- except KeyError:
- pass
-
- # Parse response for Celebrity and Demographics models
- try:
- for value in clarifai_response["data"]["regions"]:
- for face in value["data"]["face"].values():
- concepts.extend(
- [
- {concept.get("name").lower(): concept.get("value")}
- for concept in face["concepts"]
- ]
- )
- except KeyError:
- pass
-
- # Parse response for Logo model
- try:
- concepts = [
- {concept.get("name").lower(): concept.get("value")}
- for concept in clarifai_response["data"]["regions"][0]["data"]["concepts"]
- ]
- except KeyError:
- pass
-
- # Parse response for General model and similarly structured responses
- try:
- concepts = [
- {concept.get("name").lower(): concept.get("value")}
- for concept in clarifai_response["data"]["concepts"]
- ]
- except KeyError:
- pass
-
- # Parse response for Video input
- try:
- for frame in clarifai_response["data"]["frames"]:
- concepts.extend(
- [
- {concept.get("name").lower(): concept.get("value")}
- for concept in frame["data"]["concepts"]
- ]
- )
- except KeyError:
- pass
-
- # Filter concepts based on probability threshold
- for concept in concepts:
- if float([x for x in concept.values()][0]) > probability:
- results.append(str([x for x in concept.keys()][0]))
-
- return results
diff --git a/instapy/comment_util.py b/instapy/comment_util.py
deleted file mode 100644
index 48982e275..000000000
--- a/instapy/comment_util.py
+++ /dev/null
@@ -1,470 +0,0 @@
-# -*- coding: utf-8 -*-
-""" Module which handles the commenting features """
-# import built-in & third-party modules
-import random
-
-import emoji
-
-# import exceptions
-from selenium.common.exceptions import (
- InvalidElementStateException,
- NoSuchElementException,
- WebDriverException,
-)
-from selenium.webdriver.common.action_chains import ActionChains
-from selenium.webdriver.common.by import By
-from selenium.webdriver.common.keys import Keys
-
-from .event import Event
-from .quota_supervisor import quota_supervisor
-
-# import InstaPy modules
-from .time_util import sleep
-from .util import (
- add_user_to_blacklist,
- click_element,
- evaluate_mandatory_words,
- explicit_wait,
- get_action_delay,
- getMediaData,
- update_activity,
- web_address_navigator,
-)
-from .xpath import read_xpath
-
-
-def get_comment_input(browser):
- comment_input = browser.find_elements(
- By.XPATH, read_xpath(get_comment_input.__name__, "comment_input")
- )
-
- if len(comment_input) <= 0:
- comment_input = browser.find_elements(
- By.XPATH, read_xpath(get_comment_input.__name__, "placeholder")
- )
-
- return comment_input
-
-
-def open_comment_section(browser, logger):
- missing_comment_elem_warning = (
- "--> Comment Button Not Found!"
- "\t~may cause issues with browser windows of smaller widths"
- )
-
- comment_elem = browser.find_elements(
- By.XPATH, read_xpath(open_comment_section.__name__, "comment_elem")
- )
-
- if len(comment_elem) > 0:
- try:
- click_element(browser, comment_elem[0])
-
- except WebDriverException:
- logger.warning(missing_comment_elem_warning)
-
- else:
- logger.warning(missing_comment_elem_warning)
-
-
-def comment_image(browser, username, comments, blacklist, logger, logfolder):
- """Checks if it should comment on the image"""
- # check action availability
- if quota_supervisor("comments") == "jump":
- return False, "jumped"
-
- rand_comment = random.choice(comments).format(username)
- rand_comment = emoji.demojize(rand_comment)
- rand_comment = emoji.emojize(rand_comment, use_aliases=True)
-
- open_comment_section(browser, logger)
- # wait, to avoid crash
- sleep(3)
- comment_input = get_comment_input(browser)
-
- try:
- if len(comment_input) > 0:
- # wait, to avoid crash
- sleep(2)
- comment_input = get_comment_input(browser)
- # below, an extra space is added to force
- # the input box to update the reactJS core
- comment_to_be_sent = rand_comment
-
- # wait, to avoid crash
- sleep(2)
- # click on textarea/comment box and enter comment
- (
- ActionChains(browser)
- .move_to_element(comment_input[0])
- .click()
- .send_keys(comment_to_be_sent)
- .perform()
- )
- # wait, to avoid crash
- sleep(2)
- # post comment /
- (
- ActionChains(browser)
- .move_to_element(comment_input[0])
- .send_keys(Keys.ENTER)
- .perform()
- )
-
- update_activity(
- browser,
- action="comments",
- state=None,
- logfolder=logfolder,
- logger=logger,
- )
-
- if blacklist["enabled"] is True:
- action = "commented"
- add_user_to_blacklist(
- username, blacklist["campaign"], action, logger, logfolder
- )
- else:
- logger.warning(
- "--> Comment Action Likely Failed!\t~comment Element was not found"
- )
- return False, "commenting disabled"
-
- except InvalidElementStateException:
- logger.warning(
- "--> Comment Action Likely Failed!"
- "\t~encountered `InvalidElementStateException` :/"
- )
- return False, "invalid element state"
- except WebDriverException as ex:
- logger.error(ex)
-
- logger.info("--> Commented: {}".format(rand_comment.encode("utf-8")))
- Event().commented(username)
-
- # get the post-comment delay time to sleep
- naply = get_action_delay("comment")
- sleep(naply)
-
- return True, "success"
-
-
-def verify_commenting(browser, maximum, minimum, logger):
- """
- Get the amount of existing existing comments and
- compare it against maximum & minimum values defined by user
- """
-
- commenting_state, msg = is_commenting_enabled(browser, logger)
- if commenting_state is not True:
- disapproval_reason = "--> Not commenting! {}".format(msg)
- return False, disapproval_reason
-
- comments_count, msg = get_comments_count(browser, logger)
- if comments_count is None:
- disapproval_reason = "--> Not commenting! {}".format(msg)
- return False, disapproval_reason
-
- if maximum is not None and comments_count > maximum:
- disapproval_reason = "Not commented on this post! ~more comments exist off maximum limit at {}".format(
- comments_count
- )
- return False, disapproval_reason
-
- elif minimum is not None and comments_count < minimum:
- disapproval_reason = "Not commented on this post! ~less comments exist off minimum limit at {}".format(
- comments_count
- )
- return False, disapproval_reason
-
- return True, "Approval"
-
-
-def verify_mandatory_words(
- mand_words,
- comments,
- browser,
- logger,
-):
- if len(mand_words) > 0 or isinstance(comments[0], dict):
- try:
- post_desc = getMediaData(
- "edge_media_to_caption.edges.0.node.text", browser
- ).lower()
-
- except Exception:
- post_desc = None
-
- try:
- first_comment = getMediaData(
- "edge_media_to_parent_comment.edges.0.node.text", browser
- ).lower()
-
- except Exception:
- first_comment = None
-
- if post_desc is None and first_comment is None:
- return False, [], "couldn't get post description and comments"
-
- text = (
- post_desc
- if post_desc is not None
- else "" + " " + first_comment
- if first_comment is not None
- else ""
- )
-
- if len(mand_words) > 0:
- if not evaluate_mandatory_words(text, mand_words):
- return False, [], "mandatory words not in post desc"
-
- if isinstance(comments[0], dict):
- # The comments definition is a compound definition of conditions and comments
- for compund_comment in comments:
- if (
- "mandatory_words" not in compund_comment
- or evaluate_mandatory_words(
- text, compund_comment["mandatory_words"]
- )
- ):
- return True, compund_comment["comments"], "Approval"
- return (
- False,
- [],
- "Coulnd't match the mandatory words in any comment definition",
- )
-
- return True, comments, "Approval"
-
-
-def get_comments_on_post(
- browser, owner, poster, amount, post_link, ignore_users, randomize, logger
-):
- """Fetch comments data on posts"""
- web_address_navigator(browser, post_link)
-
- comments = []
- commenters = []
-
- if randomize is True:
- amount = amount * 3
-
- # check if commenting on the post is enabled
- (commenting_approved, disapproval_reason,) = verify_commenting(
- browser,
- None,
- None,
- logger,
- )
- if not commenting_approved:
- logger.info(disapproval_reason)
- return None
-
- # get comments & commenters information path
- like_button_full_XPath = read_xpath(
- get_comments_on_post.__name__, "like_button_full_XPath"
- )
- unlike_button_full_XPath = read_xpath(
- get_comments_on_post.__name__, "unlike_button_full_XPath"
- )
-
- # wait for page fully load [IMPORTANT!]
- explicit_wait(browser, "PFL", [], logger, 10)
-
- try:
- all_comment_like_buttons = browser.find_elements(
- By.XPATH, like_button_full_XPath
- )
-
- if all_comment_like_buttons:
- commenter = None
- comment = None
-
- data = getMediaData("edge_media_to_parent_comment", browser)
- for value in data["edges"]:
- commenter = value["node"]["owner"]["username"]
- comment = value["node"]["text"]
-
- if (
- commenter
- and commenter not in commenters
- and commenter not in [owner, poster, ignore_users]
- and comment
- ):
- commenters.append(commenter)
- comments.append(comment)
- else:
- logger.info("Could not grab any commenter from this post")
-
- else:
- comment_unlike_buttons = browser.find_elements(
- By.XPATH, unlike_button_full_XPath
- )
-
- if comment_unlike_buttons:
- logger.info(
- "Grabbed {} comment(s) on this post and already liked.".format(
- len(comment_unlike_buttons)
- )
- )
- else:
- logger.info("There are no any comments available on this post.")
- return None
-
- except NoSuchElementException:
- logger.info("Failed to grab comments on this post.")
- return None
-
- if not comments:
- logger.info("Could not grab any usable comments from this post...")
- return None
-
- else:
- comment_data = list(zip(commenters, comments))
- if randomize is True:
- random.shuffle(comment_data)
-
- logger.info(
- "Grabbed only {} usable comment(s) from this post...".format(
- len(comment_data)
- )
- )
-
- return comment_data
-
-
-def is_commenting_enabled(browser, logger):
- """Find out if commenting on the post is enabled"""
-
- comments_disabled = getMediaData("comments_disabled", browser)
-
- if comments_disabled is True:
- msg = "Comments are disabled for this post."
- return False, msg
-
- return True, "Success"
-
-
-def get_comments_count(browser, logger):
- """Get the number of total comments in the post"""
-
- comments_count = getMediaData("edge_media_preview_comment.count", browser)
- return comments_count, "Success"
-
-
-def verify_commented_image(browser, link, owner, logger):
- """Fetch comments data on posts to determine if already commented"""
-
- web_address_navigator(browser, link)
-
- # wait for page fully load [IMPORTANT!]
- explicit_wait(browser, "PFL", [], logger, 10)
-
- try:
- commenter = None
- comment = None
- data = getMediaData("edge_media_to_parent_comment", browser)
- for value in data["edges"]:
- commenter = value["node"]["owner"]["username"]
- comment = value["node"]["text"]
-
- if commenter and commenter == owner:
- message = (
- "--> The post has already been commented on before: '{}'".format(
- comment
- )
- )
- return True, message
-
- except NoSuchElementException:
- # Cannot be determined if the post has been comment by InstaPy user,
- # and then it will not be commented until next loop, maybe comments
- # on the post have been limited. Return True, to emulate or assume the
- # post has been commented by user.
- message = (
- "--> Failed to get comments on this post, will not comment the post..."
- )
- return True, message
-
- message = "--> Could not found owner's comment in this post, trying to comment..."
- return None, message
-
-
-def process_comments(
- comments,
- clarifai_comments,
- delimit_commenting,
- max_comments,
- min_comments,
- comments_mandatory_words,
- owner,
- user_name,
- blacklist,
- browser,
- link,
- logger,
- logfolder,
- publish=True,
-):
-
- # comments
- if delimit_commenting:
- (commenting_approved, disapproval_reason,) = verify_commenting(
- browser,
- max_comments,
- min_comments,
- logger,
- )
- if not commenting_approved:
- logger.info(disapproval_reason)
- return False
-
- (
- commenting_approved,
- selected_comments,
- disapproval_reason,
- ) = verify_mandatory_words(
- comments_mandatory_words,
- comments,
- browser,
- logger,
- )
-
- if not commenting_approved:
- logger.info(disapproval_reason)
- return False
-
- if len(clarifai_comments) > 0:
- selected_comments = clarifai_comments
-
- # smart commenting
- if comments and publish:
- # Check if InstaPy already commented on this post, it could be the
- # case that the image has been liked (manually) but not commented, so
- # we want to comment the post like usually we do.
- commented_image, message = verify_commented_image(browser, link, owner, logger)
-
- if commented_image:
- # The post has already been commented, either manually or InstaPy
- # Commenting twice by InstaPy user is not allowed by now or could
- # not get comments on this post to check if InstaPy user commented
- # before, so will not comment until next check
- logger.info(message)
- return False
- else:
- logger.info(message)
-
- comment_state, _ = comment_image(
- browser,
- user_name,
- selected_comments,
- blacklist,
- logger,
- logfolder,
- )
-
- # Return to the target uset page
- user_link = "https://www.instagram.com/{}/".format(user_name)
- web_address_navigator(browser, user_link)
-
- return comment_state
diff --git a/instapy/commenters_util.py b/instapy/commenters_util.py
deleted file mode 100644
index f6c9576d0..000000000
--- a/instapy/commenters_util.py
+++ /dev/null
@@ -1,473 +0,0 @@
-"""Methods to extract the data for the given usernames profile"""
-# code created by modification of original code copied from
-# https://github.com/timgrossmann/instagram-profilecrawl/blob/master/util/extractor.py
-# import built-in & third-party modules
-import collections
-import random
-import time
-from datetime import datetime, timedelta
-from operator import itemgetter
-from time import sleep
-
-# import exceptions
-from selenium.common.exceptions import (
- NoSuchElementException,
- StaleElementReferenceException,
-)
-from selenium.webdriver.common.by import By
-from selenium.webdriver.common.keys import Keys
-
-# import InstaPy modules
-from .util import (
- click_element,
- close_dialog_box,
- get_number_of_posts,
- get_users_from_dialog,
- progress_tracker,
- scroll_bottom,
- update_activity,
- username_url_to_username,
- web_address_navigator,
-)
-from .xpath import read_xpath
-
-
-def check_exists_by_xpath(browser, xpath):
- try:
- browser.find_element(By.XPATH, xpath)
- except NoSuchElementException:
- return False
- return True
-
-
-def remove_duplicates_preserving_order(seq):
- seen = set()
- seen_add = seen.add
- return [x for x in seq if not (x in seen or seen_add(x))]
-
-
-def extract_post_info(browser, logger):
- """Get the information from the current post"""
- web_address_navigator(browser, browser.current_url + "comments/")
- comments = []
- user_commented_list = []
- last_comment_count = 0
- # load all hidden comments
- while check_exists_by_xpath(
- browser, read_xpath(extract_post_info.__name__, "load_more_comments_element")
- ):
- load_more_comments_element = browser.find_element(
- By.XPATH,
- read_xpath(extract_post_info.__name__, "load_more_comments_element"),
- )
- click_element(browser, load_more_comments_element)
- sleep(0.5)
- # get comment list
- comment_list = browser.find_element(
- By.XPATH, read_xpath(extract_post_info.__name__, "comment_list")
- )
- comments = comment_list.find_elements(
- By.XPATH, read_xpath(extract_post_info.__name__, "comments")
- )
- # check instagram comment load bug
- if len(comments) == last_comment_count:
- break
- if (len(comments) - last_comment_count) < 3:
- break
- last_comment_count = len(comments)
-
- # get all comment list
- comment_list = browser.find_element(
- By.XPATH, read_xpath(extract_post_info.__name__, "comment_list")
- )
- comments = comment_list.find_elements(
- By.XPATH, read_xpath(extract_post_info.__name__, "comments")
- )
-
- # get all commenter list
- try:
- for comm in comments:
- user_commented = (
- comm.find_element(By.TAG_NAME, "a").get_attribute("href").split("/")
- )
- logger.info("Found commenter: {}".format(user_commented[3]))
- user_commented_list.append(user_commented[3])
-
- except Exception as e:
- logger.warning("Cant get comments".format(str(e).encode("utf-8")))
-
- date_time = browser.find_element(By.TAG_NAME, "time").get_attribute("datetime")
- return user_commented_list, date_time
-
-
-def extract_information(browser, username, daysold, max_pic, logger):
- """Get all the information for the given username"""
- web_address_navigator(browser, "https://www.instagram.com/" + username)
-
- try:
- num_of_posts = get_number_of_posts(browser)
- num_of_posts = min(num_of_posts, max_pic)
- # we don't need to scroll more than is max number of posts we want
- # to extract
-
- links1 = []
- links2 = []
- links3 = []
- # list links1 contains 30 links from the current view, as that is the
- # maximum Instagram is showing at one time
- # list links2 contains all the links collected so far without
- # duplicates, in mixed order
- # list links3 contains all the links collected so far with
- # duplicates in preserved order
-
- except Exception as e:
- logger.error(
- "Error: Couldn't get user profile. Moving on... \n\t{}".format(
- str(e).encode("utf-8")
- )
- )
- return []
-
- # PROFILE SCROLLING AND HARVESTING LINKS
- try:
- body_elem = browser.find_element(By.TAG_NAME, "body")
- previouslen = -1
-
- # every 60 links we will open picture and check it's date not to
- # scroll endlessly in huge profiles such as natgeo
- opened_overlay = 42
- sleep(0.5)
-
- # cycle that scrolls down the feed and collects links and saving
- # them into links2
- while len(links2) < num_of_posts:
- prev_divs = browser.find_elements(By.TAG_NAME, "main")
- # harvesting current img links:
- links_elems = [div.find_elements(By.TAG_NAME, "a") for div in prev_divs]
- links1 = sum(
- [
- [link_elem.get_attribute("href") for link_elem in elems]
- for elems in links_elems
- ],
- [],
- )
- # saving links for later:
- for link in links1:
- if "/p/" in link:
- links2.append(link)
- links3.append(link)
-
- links2 = list(set(links2))
- # if after previous scroll, size of links2 didnt increase,
- # we should finish else we continue
- if len(links2) == previouslen:
- logger.info("Cannot scroll, quitting...")
- sleep(0.5)
- break
-
- else:
- logger.info(
- "Scrolling profile. Links and posts: {}/{}",
- len(links2),
- num_of_posts,
- )
-
- # TRYING TO END SCROLLING IN TIME
- # check the date of the image once in a 60 to not scroll too
- # much
- # only do it if we have a lot to images to go
- if (num_of_posts - len(links2) > 60) and (len(links2) > opened_overlay):
- opened_overlay += 60
-
- logger.info("Clicking on one photo...")
- try:
- one_pic_elem = browser.find_element(
- By.XPATH,
- read_xpath(extract_information.__name__, "one_pic_elem"),
- )
- click_element(browser, one_pic_elem)
- except Exception:
- logger.error("Cant click on the photo...")
-
- sleep(1.5)
-
- # following 6 lines give like to opened picture, to use
- # our time effectively and look less suspicious
- try:
- like_element = browser.find_elements(
- By.XPATH,
- read_xpath(extract_information.__name__, "like_element"),
- )
- click_element(browser, like_element[0])
- logger.info("Clicking like...")
- except Exception:
- pass
- sleep(2)
-
- pic_date_time = browser.find_element(
- By.TAG_NAME, "time"
- ).get_attribute("datetime")
- pastdate = datetime.now() - timedelta(days=daysold)
- date_of_pic = datetime.strptime(
- pic_date_time, "%Y-%m-%dT%H:%M:%S.%fZ"
- )
-
- # Informational
- logger.info("Closing overlay...")
- close_overlay = browser.find_element(
- By.XPATH,
- read_xpath(extract_information.__name__, "close_overlay"),
- )
- click_element(browser, close_overlay)
-
- logger.info("Date of this picture was: {}".format(date_of_pic))
-
- if date_of_pic < pastdate:
- logger.info("Finished scrolling, too old photos...")
- sleep(3)
- break
- else:
- logger.info("Photos seems to be fresh, continuing scrolling...")
- sleep(2)
-
- previouslen = len(links2)
- body_elem = browser.find_element(By.TAG_NAME, "body")
- body_elem.send_keys(Keys.END)
- sleep(1.5)
-
- except (NoSuchElementException, StaleElementReferenceException) as e:
- logger.warning(
- "- Something went terribly wrong\n - Stopping everything and "
- "moving on with what I have. \n\t{}".format(str(e).encode("utf-8"))
- )
-
- links4 = remove_duplicates_preserving_order(links3)
-
- # PICTURES SCRAPPER ONE BY ONE
- # into user_commented_total_list go all username links who commented on
- # any post of this user
- counter = 1
- user_commented_total_list = []
- for link in links4:
- if max_pic <= 0:
- break
- max_pic -= 1
- logger.info("{} of max {} --- {} to go.".format(counter, len(links4), max_pic))
- counter = counter + 1
- logger.info("Scrapping link: {}".format(link))
-
- try:
- web_address_navigator(browser, link)
- user_commented_list, pic_date_time = extract_post_info(browser, logger)
- user_commented_total_list = user_commented_total_list + user_commented_list
-
- # stop if date older than daysago
- pastdate = datetime.now() - timedelta(days=daysold)
- date_of_pic = datetime.strptime(pic_date_time, "%Y-%m-%dT%H:%M:%S.%fZ")
- logger.info("Date of pic: {}".format(date_of_pic))
-
- if date_of_pic > pastdate:
- logger.info("Recent pic, continue...")
- else:
- logger.info("Old pic, ending getting users who commented.")
- sleep(3)
- break
- sleep(1)
- except NoSuchElementException as e:
- logger.error(
- "- Could not get information from post: {} \n\t{}".format(
- link, str(e).encode("utf-8")
- )
- )
-
- # PREPARE THE USER LIST TO EXPORT
- # sorts the list by frequencies, so users who comment the most are at
- # the top
- counter = collections.Counter(user_commented_total_list)
- com = sorted(counter.most_common(), key=itemgetter(1, 0), reverse=True)
- com = map(lambda x: [x[0]] * x[1], com)
- user_commented_total_list = [item for sublist in com for item in sublist]
-
- # remove duplicates preserving order (that's why not using set())
- user_commented_list = []
- last = ""
- for index, _ in enumerate(user_commented_total_list):
- if username.lower() != user_commented_total_list[index]:
- if (
- last != user_commented_total_list[index]
- and "p" not in user_commented_total_list[index]
- ):
- user_commented_list.append(user_commented_total_list[index])
- last = user_commented_total_list[index]
-
- logger.info(
- "Getting list of users who commented on this profile finished: {}".format(
- user_commented_list
- )
- )
- return user_commented_list
-
-
-def users_liked(browser, photo_url, amount=100, logger=None):
- photo_likers = []
- try:
- web_address_navigator(browser, photo_url)
- photo_likers = likers_from_photo(browser, amount, logger)
- sleep(2)
- except NoSuchElementException:
- logger.info(
- "Could not get information from post: {} nothing to return".format(
- photo_url
- )
- )
-
- return photo_likers
-
-
-def likers_from_photo(browser, amount=20, logger=None):
- """Get the list of users from the 'Likes' dialog of a photo"""
-
- try:
- if check_exists_by_xpath(
- browser, read_xpath(likers_from_photo.__name__, "second_counter_button")
- ):
- liked_this = browser.find_elements(
- By.XPATH,
- read_xpath(likers_from_photo.__name__, "second_counter_button"),
- )
- element_to_click = liked_this[0]
- elif check_exists_by_xpath(
- browser, read_xpath(likers_from_photo.__name__, "liked_counter_button")
- ):
- liked_this = browser.find_elements(
- By.XPATH, read_xpath(likers_from_photo.__name__, "liked_counter_button")
- )
- likers = []
-
- for liker in liked_this:
- if " like this" not in liker.text:
- likers.append(liker.text)
-
- if " others" in liked_this[-1].text:
- element_to_click = liked_this[-1]
-
- elif " likes" in liked_this[0].text:
- element_to_click = liked_this[0]
-
- else:
- logger.info(
- "Few likes, not guaranteed you don't follow these"
- " likers already.\nGot photo likers: {}".format(likers)
- )
- return likers
-
- else:
- # If you are here, it is because you discovered that sometimes an
- # xpath does not work, at the moment the number of views in a video
- # does not behave like the number of likes in a photo. Clicking on
- # the number of views only shows the same number in a floating
- # window; no users to get.
- # www.instagram.com/p/CASprIDgOOO/ -> 3,275,561 views -> 11-24-20
- logger.info("Couldn't find liked counter button. May be a video.")
- logger.info("Trying again for some image, moving on...")
- return []
-
- sleep(1)
- click_element(browser, element_to_click)
- logger.info("Opening likes...")
-
- # update server calls
- update_activity(browser, state=None)
- sleep(1)
-
- # get a reference to the 'Likes' dialog box
- dialog = browser.find_element(
- By.XPATH, read_xpath("class_selectors", "likes_dialog_body_xpath")
- )
-
- # scroll down the page
- previous_len = -1
- browser.execute_script(
- "arguments[0].scrollTop = arguments[0].scrollHeight", dialog
- )
- update_activity(browser, state=None)
- sleep(1)
-
- start_time = time.time()
- user_list = []
-
- while (
- not user_list
- or (len(user_list) != previous_len)
- and (len(user_list) < amount)
- ):
-
- if previous_len + 10 >= amount:
- logger.info("Scrolling finished...")
- if amount < 10:
- user_list = get_users_from_dialog(user_list, dialog, logger)
- sleep(1)
- break
-
- previous_len = len(user_list)
- scroll_bottom(browser, dialog, 2)
-
- user_list = get_users_from_dialog(user_list, dialog, logger)
-
- # write & update records at Progress Tracker
- progress_tracker(len(user_list), amount, start_time, None)
- print("\n")
-
- random.shuffle(user_list)
- sleep(1)
-
- close_dialog_box(browser)
-
- logger.info(
- "Got {} likers shuffled randomly whom you can follow:\n{}".format(
- len(user_list), user_list
- )
- )
- return user_list
-
- except Exception as exc:
- logger.warning("Some problem occurred! \n\t{}".format(str(exc).encode("utf-8")))
- return []
-
-
-def get_photo_urls_from_profile(
- browser, username, links_to_return_amount=1, randomize=True, logger=None
-):
- # try:
- # input can be both username or user profile url
- username = username_url_to_username(username)
- logger.info("Getting likers from user: {}".format(username))
-
- web_address_navigator(browser, "https://www.instagram.com/" + username + "/")
- sleep(1)
-
- photos_a_elems = browser.find_elements(
- By.XPATH, read_xpath(get_photo_urls_from_profile.__name__, "photos_a_elems")
- )
-
- links = []
- for photo_element in photos_a_elems:
- photo_url = photo_element.get_attribute("href")
- # logger.info("Photo url: {}".format(photo_url))
- if "/p/" in photo_url:
- links.append(photo_url)
-
- if randomize is True:
- logger.info("Shuffling links")
- random.shuffle(links)
-
- logger.info(
- "Got {} , returning {} links: {}".format(
- len(links),
- min(links_to_return_amount, len(links)),
- links[:links_to_return_amount],
- )
- )
-
- sleep(1)
- return links[:links_to_return_amount]
diff --git a/instapy/constants.py b/instapy/constants.py
deleted file mode 100644
index e67301e7b..000000000
--- a/instapy/constants.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Media
-# Update new Media Types and also update like_util.py. Do not forget to check the xpaths for new
-# Types, they must be dynamic to reduce errors.
-MEDIA_PHOTO = "Photo"
-MEDIA_CAROUSEL = "Carousel"
-MEDIA_VIDEO = "Video"
-MEDIA_IGTV = "IGTV"
-MEDIA_CLIP = "Clip"
-MEDIA_ALL_TYPES = (MEDIA_PHOTO, MEDIA_CAROUSEL, MEDIA_VIDEO, MEDIA_IGTV, MEDIA_CLIP)
diff --git a/instapy/database_engine.py b/instapy/database_engine.py
deleted file mode 100644
index 78c7ec356..000000000
--- a/instapy/database_engine.py
+++ /dev/null
@@ -1,185 +0,0 @@
-import os
-import sqlite3
-
-from .settings import Settings
-
-SELECT_FROM_PROFILE_WHERE_NAME = "SELECT * FROM profiles WHERE name = :name"
-
-INSERT_INTO_PROFILE = "INSERT INTO profiles (name) VALUES (?)"
-
-SQL_CREATE_PROFILE_TABLE = """
- CREATE TABLE IF NOT EXISTS `profiles` (
- `id` INTEGER PRIMARY KEY AUTOINCREMENT,
- `name` TEXT NOT NULL);"""
-
-SQL_CREATE_RECORD_ACTIVITY_TABLE = """
- CREATE TABLE IF NOT EXISTS `recordActivity` (
- `profile_id` INTEGER REFERENCES `profiles` (id),
- `likes` SMALLINT UNSIGNED NOT NULL,
- `comments` SMALLINT UNSIGNED NOT NULL,
- `follows` SMALLINT UNSIGNED NOT NULL,
- `unfollows` SMALLINT UNSIGNED NOT NULL,
- `server_calls` INT UNSIGNED NOT NULL,
- `created` DATETIME NOT NULL);"""
-
-SQL_CREATE_FOLLOW_RESTRICTION_TABLE = """
- CREATE TABLE IF NOT EXISTS `followRestriction` (
- `profile_id` INTEGER REFERENCES `profiles` (id),
- `username` TEXT NOT NULL,
- `times` TINYINT UNSIGNED NOT NULL);"""
-
-SQL_CREATE_SHARE_WITH_PODS_RESTRICTION_TABLE = """
- CREATE TABLE IF NOT EXISTS `shareWithPodsRestriction` (
- `profile_id` INTEGER REFERENCES `profiles` (id),
- `postid` TEXT NOT NULL,
- `times` TINYINT UNSIGNED NOT NULL);"""
-
-SQL_CREATE_COMMENT_RESTRICTION_TABLE = """
- CREATE TABLE IF NOT EXISTS `commentRestriction` (
- `profile_id` INTEGER REFERENCES `profiles` (id),
- `postid` TEXT NOT NULL,
- `times` TINYINT UNSIGNED NOT NULL);"""
-
-SQL_CREATE_ACCOUNTS_PROGRESS_TABLE = """
- CREATE TABLE IF NOT EXISTS `accountsProgress` (
- `profile_id` INTEGER NOT NULL,
- `followers` INTEGER NOT NULL,
- `following` INTEGER NOT NULL,
- `total_posts` INTEGER NOT NULL,
- `created` DATETIME NOT NULL,
- `modified` DATETIME NOT NULL,
- CONSTRAINT `fk_accountsProgress_profiles1`
- FOREIGN KEY(`profile_id`) REFERENCES `profiles`(`id`));"""
-
-
-def get_database(make=False):
- logger = Settings.logger
- credentials = Settings.profile
-
- profile_id, name = credentials["id"], credentials["name"]
- address = validate_database_address()
-
- if not os.path.isfile(address) or make:
- create_database(address, logger, name)
-
- profile_id = (
- get_profile(name, address, logger) if profile_id is None or make else profile_id
- )
-
- return address, profile_id
-
-
-def create_database(address, logger, name):
- try:
- connection = sqlite3.connect(address)
- with connection:
- connection.row_factory = sqlite3.Row
- cursor = connection.cursor()
-
- create_tables(
- cursor,
- [
- "profiles",
- "recordActivity",
- "followRestriction",
- "shareWithPodsRestriction",
- "commentRestriction",
- "accountsProgress",
- ],
- )
-
- connection.commit()
-
- except Exception as exc:
- logger.warning(
- "Wah! Error occurred while getting a DB for '{}':\n\t{}".format(
- name, str(exc).encode("utf-8")
- )
- )
-
- finally:
- if connection:
- # close the open connection
- connection.close()
-
-
-def create_tables(cursor, tables):
- if "profiles" in tables:
- cursor.execute(SQL_CREATE_PROFILE_TABLE)
-
- if "recordActivity" in tables:
- cursor.execute(SQL_CREATE_RECORD_ACTIVITY_TABLE)
-
- if "followRestriction" in tables:
- cursor.execute(SQL_CREATE_FOLLOW_RESTRICTION_TABLE)
-
- if "shareWithPodsRestriction" in tables:
- cursor.execute(SQL_CREATE_SHARE_WITH_PODS_RESTRICTION_TABLE)
-
- if "commentRestriction" in tables:
- cursor.execute(SQL_CREATE_COMMENT_RESTRICTION_TABLE)
-
- if "accountsProgress" in tables:
- cursor.execute(SQL_CREATE_ACCOUNTS_PROGRESS_TABLE)
-
-
-def verify_database_directories(address):
- db_dir = os.path.dirname(address)
- if not os.path.exists(db_dir):
- os.makedirs(db_dir)
-
-
-def validate_database_address():
- address = Settings.database_location
- if not address.endswith(".db"):
- slash = "\\" if "\\" in address else "/"
- address = address if address.endswith(slash) else address + slash
- address += "instapy.db"
- Settings.database_location = address
- verify_database_directories(address)
- return address
-
-
-def get_profile(name, address, logger):
- try:
- conn = sqlite3.connect(address)
- with conn:
- conn.row_factory = sqlite3.Row
- cursor = conn.cursor()
-
- profile = select_profile_by_username(cursor, name)
-
- if profile is None:
- add_profile(conn, cursor, name)
- # reselect the table after adding data to get the proper `id`
- profile = select_profile_by_username(cursor, name)
- except Exception as exc:
- logger.warning(
- "Heeh! Error occurred while getting a DB profile for '{}':\n\t{}".format(
- name, str(exc).encode("utf-8")
- )
- )
- finally:
- if conn:
- # close the open connection
- conn.close()
-
- profile = dict(profile)
- profile_id = profile["id"]
- # assign the id to its child in `Settings` class
- Settings.profile["id"] = profile_id
-
- return profile_id
-
-
-def add_profile(conn, cursor, name):
- cursor.execute(INSERT_INTO_PROFILE, (name,))
- # commit the latest changes
- conn.commit()
-
-
-def select_profile_by_username(cursor, name):
- cursor.execute(SELECT_FROM_PROFILE_WHERE_NAME, {"name": name})
- profile = cursor.fetchone()
-
- return profile
diff --git a/instapy/event.py b/instapy/event.py
deleted file mode 100644
index 54d73cef7..000000000
--- a/instapy/event.py
+++ /dev/null
@@ -1,51 +0,0 @@
-class Event:
- """Event Singleton Class
-
- How to use example:
- from .event import Event
- Event().profile_data_updated(400, 312)
- """
-
- singleton = None
- callbacks = dict()
-
- def __new__(cls, *args, **kwargs):
- if not cls.singleton:
- cls.singleton = object.__new__(Event)
- return cls.singleton
-
- def __init__(self):
- pass
-
- def fire_callbacks(self, function_name, *args, **kwargs):
- if function_name not in self.callbacks:
- return
- for callback in self.callbacks[function_name]:
- callback(*args, **kwargs)
-
- def add_callback(self, function_name, callback):
- if function_name not in self.callbacks:
- self.callbacks[function_name] = []
-
- self.callbacks[function_name].append(callback)
-
- # place custom events below
- def profile_data_updated(self, username, followers_count, following_count):
- self.fire_callbacks(
- self.profile_data_updated.__name__,
- username,
- followers_count,
- following_count,
- )
-
- def commented(self, username):
- self.fire_callbacks(self.commented.__name__, username)
-
- def liked(self, username):
- self.fire_callbacks(self.liked.__name__, username)
-
- def followed(self, username):
- self.fire_callbacks(self.followed.__name__, username)
-
- def unfollowed(self, username):
- self.fire_callbacks(self.unfollowed.__name__, username)
diff --git a/instapy/exceptions.py b/instapy/exceptions.py
deleted file mode 100644
index 3a49cba42..000000000
--- a/instapy/exceptions.py
+++ /dev/null
@@ -1,5 +0,0 @@
-"""Custom Exceptions"""
-
-
-class InstaPyError(Exception):
- """General error for InstaPy exceptions"""
diff --git a/instapy/feed_util.py b/instapy/feed_util.py
deleted file mode 100644
index 134076f82..000000000
--- a/instapy/feed_util.py
+++ /dev/null
@@ -1,44 +0,0 @@
-""" Module that handles the like features """
-# import built-in & third-party modules
-
-# import exceptions
-from selenium.common.exceptions import NoSuchElementException
-from selenium.webdriver.common.by import By
-
-# import InstaPy modules
-from .util import update_activity
-
-LIKE_TAG_CLASS = "coreSpriteHeartOpen"
-
-
-def get_like_on_feed(browser, amount):
- """
- browser - the selenium browser element
- amount - total amount of likes to perform
-
- --------------------------------------
- The function takes in the total amount of likes to perform
- and then sends buttons to be liked, if it has run out of like
- buttons it will perform a scroll
- """
- assert 1 <= amount
-
- likes_performed = 0
- while likes_performed != amount:
- try:
- like_buttons = browser.find_elements(By.CLASS_NAME, LIKE_TAG_CLASS)
- except NoSuchElementException:
- print("Unable to find the like buttons, aborting")
- break
- else:
- for button in like_buttons:
- likes_performed += 1
- if amount < likes_performed:
- print("Performed the required number of likes")
- break
- yield button
-
- print("--> Total Likes uptil now ->", likes_performed)
-
- browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
- update_activity(browser, state=None)
diff --git a/instapy/file_manager.py b/instapy/file_manager.py
deleted file mode 100644
index 7f1dcdfab..000000000
--- a/instapy/file_manager.py
+++ /dev/null
@@ -1,220 +0,0 @@
-""" A file management utility """
-
-import os
-from os.path import expanduser
-from os.path import exists as path_exists
-from os.path import sep as native_slash
-from platform import python_version
-
-from .util import highlight_print
-from .settings import Settings
-from .settings import localize_path
-from .settings import WORKSPACE
-from .exceptions import InstaPyError
-
-
-def use_workspace():
- """Get workspace folder"""
- workspace_path = slashen(WORKSPACE["path"], "native")
- validate_path(workspace_path)
- return workspace_path
-
-
-def use_assets():
- """Get asset folder"""
- assets_path = "{}{}assets".format(use_workspace(), native_slash)
- validate_path(assets_path)
- return assets_path
-
-
-def get_workspace():
- """Make a workspace ready for user"""
-
- if WORKSPACE["path"]:
- workspace = verify_workspace_name(WORKSPACE["path"])
-
- else:
- home_dir = get_home_path()
- workspace = "{}/{}".format(home_dir, WORKSPACE["name"])
-
- message = 'Workspace in use: "{}"'.format(workspace)
- highlight_print(
- Settings.profile["name"], message, "workspace", "info", Settings.logger
- )
- update_workspace(workspace)
- update_locations()
- return WORKSPACE
-
-
-def set_workspace(path=None):
- """Set a custom workspace for use"""
-
- if not Settings.InstaPy_is_running:
- if path:
- path = verify_workspace_name(path)
- workspace_is_new = differ_paths(WORKSPACE["path"], path)
- if workspace_is_new:
- update_workspace(path)
- update_locations()
- message = 'Custom workspace set: "{}" :]'.format(path)
- highlight_print(
- Settings.profile["name"],
- message,
- "workspace",
- "info",
- Settings.logger,
- )
-
- else:
- message = "Given workspace path is identical as current :/"
- highlight_print(
- Settings.profile["name"],
- message,
- "workspace",
- "info",
- Settings.logger,
- )
-
- else:
- message = "No any custom workspace provided.\t~using existing.."
- highlight_print(
- Settings.profile["name"], message, "workspace", "info", Settings.logger
- )
-
- else:
- message = (
- "Sorry! You can't change workspace after"
- " InstaPy has started :>\t~using existing.."
- )
- highlight_print(
- Settings.profile["name"], message, "workspace", "info", Settings.logger
- )
-
-
-def update_workspace(latest_path):
- """Update the workspace constant with its latest path"""
-
- latest_path = slashen(latest_path, "native")
- validate_path(latest_path)
- WORKSPACE.update(path=latest_path)
-
-
-def move_workspace(old_path, new_path):
- """Find data files in old workspace folder and move to new location"""
- # write in future
-
-
-def update_locations():
- """
- As workspace has changed, locations also should be updated
-
- If the user already has set a location, do not alter it
- """
-
- # update logs location
- if not Settings.log_location:
- Settings.log_location = localize_path("logs")
-
- # update database location
- if not Settings.database_location:
- Settings.database_location = localize_path("db", "instapy.db")
-
-
-def get_home_path():
- """Get user's home directory"""
-
- if python_version() >= "3.5":
- from pathlib import Path
-
- home_dir = str(Path.home()) # this method returns slash as dir sep*
- else:
- home_dir = expanduser("~")
-
- home_dir = slashen(home_dir)
- home_dir = remove_last_slash(home_dir)
-
- return home_dir
-
-
-def slashen(path, direction="forward"):
- """Replace backslashes in paths with forward slashes"""
-
- if direction == "forward":
- path = path.replace("\\", "/")
-
- elif direction == "backwards":
- path = path.replace("/", "\\")
-
- elif direction == "native":
- path = path.replace("/", str(native_slash))
- path = path.replace("\\", str(native_slash))
-
- return path
-
-
-def remove_last_slash(path):
- """Remove the last slash in the given path [if any]"""
-
- if path.endswith("/"):
- path = path[:-1]
-
- return path
-
-
-def verify_workspace_name(path):
- """Make sure chosen workspace name is InstaPy friendly"""
-
- path = slashen(path)
- path = remove_last_slash(path)
- custom_workspace_name = path.split("/")[-1]
- default_workspace_name = WORKSPACE["name"]
-
- if default_workspace_name not in custom_workspace_name:
- if default_workspace_name.lower() not in custom_workspace_name.lower():
- path += "/{}".format(default_workspace_name)
- else:
- nicer_name = custom_workspace_name.lower().replace(
- default_workspace_name.lower(), default_workspace_name
- )
- path = path.replace(custom_workspace_name, nicer_name)
-
- return path
-
-
-def differ_paths(old, new):
- """Compare old and new paths"""
-
- if old and old.endswith(("\\", "/")):
- old = old[:-1]
- old = old.replace("\\", "/")
-
- if new and new.endswith(("\\", "/")):
- new = new[:-1]
- new = new.replace("\\", "/")
-
- return new != old
-
-
-def validate_path(path):
- """Make sure the given path exists"""
-
- if not path_exists(path):
- try:
- os.makedirs(path)
-
- except OSError as exc:
- exc_name = type(exc).__name__
- msg = '{} occurred while making "{}" path!' "\n\t{}".format(
- exc_name, path, str(exc).encode("utf-8")
- )
- raise InstaPyError(msg)
-
-
-def get_logfolder(username, multi_logs):
- if multi_logs:
- logfolder = "{0}{1}{2}{1}".format(Settings.log_location, native_slash, username)
- else:
- logfolder = Settings.log_location + native_slash
-
- validate_path(logfolder)
- return logfolder
diff --git a/instapy/firefox_extension/arrive.js b/instapy/firefox_extension/arrive.js
deleted file mode 100644
index 5960b1a0a..000000000
--- a/instapy/firefox_extension/arrive.js
+++ /dev/null
@@ -1 +0,0 @@
-var Arrive=function(e,t,n){"use strict";function r(e,t,n){l.addMethod(t,n,e.unbindEvent),l.addMethod(t,n,e.unbindEventWithSelectorOrCallback),l.addMethod(t,n,e.unbindEventWithSelectorAndCallback)}function i(e){e.arrive=f.bindEvent,r(f,e,"unbindArrive"),e.leave=d.bindEvent,r(d,e,"unbindLeave")}if(e.MutationObserver&&"undefined"!=typeof HTMLElement){var o=0,l=function(){var t=HTMLElement.prototype.matches||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector;return{matchesSelector:function(e,n){return e instanceof HTMLElement&&t.call(e,n)},addMethod:function(e,t,r){var i=e[t];e[t]=function(){return r.length==arguments.length?r.apply(this,arguments):"function"==typeof i?i.apply(this,arguments):n}},callCallbacks:function(e,t){t&&t.options.onceOnly&&1==t.firedElems.length&&(e=[e[0]]);for(var n,r=0;n=e[r];r++)n&&n.callback&&n.callback.call(n.elem,n.elem);t&&t.options.onceOnly&&1==t.firedElems.length&&t.me.unbindEventWithSelectorAndCallback.call(t.target,t.selector,t.callback)},checkChildNodesRecursively:function(e,t,n,r){for(var i,o=0;i=e[o];o++)n(i,t,r)&&r.push({callback:t.callback,elem:i}),i.childNodes.length>0&&l.checkChildNodesRecursively(i.childNodes,t,n,r)},mergeArrays:function(e,t){var n,r={};for(n in e)e.hasOwnProperty(n)&&(r[n]=e[n]);for(n in t)t.hasOwnProperty(n)&&(r[n]=t[n]);return r},toElementsArray:function(t){return n===t||"number"==typeof t.length&&t!==e||(t=[t]),t}}}(),c=function(){var e=function(){this._eventsBucket=[],this._beforeAdding=null,this._beforeRemoving=null};return e.prototype.addEvent=function(e,t,n,r){var i={target:e,selector:t,options:n,callback:r,firedElems:[]};return this._beforeAdding&&this._beforeAdding(i),this._eventsBucket.push(i),i},e.prototype.removeEvent=function(e){for(var t,n=this._eventsBucket.length-1;t=this._eventsBucket[n];n--)if(e(t)){this._beforeRemoving&&this._beforeRemoving(t);var r=this._eventsBucket.splice(n,1);r&&r.length&&(r[0].callback=null)}},e.prototype.beforeAdding=function(e){this._beforeAdding=e},e.prototype.beforeRemoving=function(e){this._beforeRemoving=e},e}(),a=function(t,r){var i=new c,o=this,a={fireOnAttributesModification:!1};return i.beforeAdding(function(n){var i,l=n.target;(l===e.document||l===e)&&(l=document.getElementsByTagName("html")[0]),i=new MutationObserver(function(e){r.call(this,e,n)});var c=t(n.options);i.observe(l,c),n.observer=i,n.me=o}),i.beforeRemoving(function(e){e.observer.disconnect()}),this.bindEvent=function(e,t,n){t=l.mergeArrays(a,t);for(var r=l.toElementsArray(this),o=0;o0?l.checkChildNodesRecursively(n,t,r,o):"attributes"===e.type&&r(i,t,o)&&o.push({callback:t.callback,elem:i}),l.callCallbacks(o,t)})}function r(e,t){return l.matchesSelector(e,t.selector)&&(e._id===n&&(e._id=o++),-1==t.firedElems.indexOf(e._id))?(t.firedElems.push(e._id),!0):!1}var i={fireOnAttributesModification:!1,onceOnly:!1,existing:!1};f=new a(e,t);var c=f.bindEvent;return f.bindEvent=function(e,t,r){n===r?(r=t,t=i):t=l.mergeArrays(i,t);var o=l.toElementsArray(this);if(t.existing){for(var a=[],s=0;s0&&l.checkChildNodesRecursively(n,t,r,i),l.callCallbacks(i,t)})}function r(e,t){return l.matchesSelector(e,t.selector)}var i={};d=new a(e,t);var o=d.bindEvent;return d.bindEvent=function(e,t,r){n===r?(r=t,t=i):t=l.mergeArrays(i,t),o.call(this,e,t,r)},d},f=new s,d=new u;t&&i(t.fn),i(HTMLElement.prototype),i(NodeList.prototype),i(HTMLCollection.prototype),i(HTMLDocument.prototype),i(Window.prototype);var h={};return r(f,h,"unbindAllArrive"),r(d,h,"unbindAllLeave"),h}}(window,"undefined"==typeof jQuery?null:jQuery,void 0);
diff --git a/instapy/firefox_extension/content.js b/instapy/firefox_extension/content.js
deleted file mode 100644
index 16c5e406e..000000000
--- a/instapy/firefox_extension/content.js
+++ /dev/null
@@ -1,65 +0,0 @@
-var customScript = `
-// Overwrite the contents of the body.
-Object.defineProperty(navigator, 'webdriver', {
- get: () => false,
-});
-
-// -- overwrite the languages property to use a custom getter
-Object.defineProperty(navigator, 'languages', {
- get: () => ['en-US', 'en'],
-});
-
-// -- overwrite the plugins property to use a custom getter
-Object.defineProperty(navigator, 'plugins', {
- get: () => [1, 2, 3, 4, 5],
-});
-
-// -- mock webgl renderer
-var getParameter = WebGLRenderingContext.getParameter;
-WebGLRenderingContext.prototype.getParameter = parameter => {
- // UNMASKED_VENDOR_WEBGL
- if (parameter === 37445) {
- return 'Intel Open Source Technology Center';
- }
- // UNMASKED_RENDERER_WEBGL
- if (parameter === 37446) {
- return 'Mesa DRI Intel(R) Ivybridge Mobile ';
- }
-
- return getParameter(parameter);
-};
-
-// -- mock image size = 0
-['height', 'width'].forEach(property => {
- // store the existing descriptor
- var imageDescriptor = Object.getOwnPropertyDescriptor(HTMLImageElement.prototype, property);
-
- // redefine the property with a patched descriptor
- Object.defineProperty(HTMLImageElement.prototype, property, {
- ...imageDescriptor,
- get: () => {
- // return an arbitrary non-zero dimension if the image failed to load
- if (this.complete && this.naturalHeight == 0) {
- return 20;
- }
- // otherwise, return the actual dimension
- return imageDescriptor.get.apply(this);
- },
- });
-});
-
-// -- pass permissions test
-var originalQuery = window.navigator.permissions.query;
-window.navigator.permissions.query = parameters => (
- parameters.name === 'notifications' ?
- Promise.resolve({ state: Notification.permission }) :
- originalQuery(parameters)
-);
-`;
-
-document.arrive('head', () => {
- var script = document.createElement('script');
- script.innerHTML = customScript;
- script.type = 'text/javascript';
- document.head.insertBefore(script, document.head.children[0]);
-});
diff --git a/instapy/firefox_extension/manifest.json b/instapy/firefox_extension/manifest.json
deleted file mode 100644
index 1160e5f4b..000000000
--- a/instapy/firefox_extension/manifest.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "manifest_version": 2,
- "name": "hide selenium",
- "version": "1.0.0",
- "applications": {
- "gecko": {
- "id": "instapy@rocks"
- }
- },
- "content_scripts": [
- {
- "matches": ["*://*/*"],
- "js": ["arrive.js", "content.js"],
- "run_at": "document_start"
- }
- ]
-}
diff --git a/instapy/follow_util.py b/instapy/follow_util.py
deleted file mode 100644
index da7c0345b..000000000
--- a/instapy/follow_util.py
+++ /dev/null
@@ -1,119 +0,0 @@
-""" Module which handles the follow features """
-# import built-in & third-party modules
-from random import randint
-from time import sleep
-
-# import exceptions
-from selenium.common.exceptions import NoSuchElementException
-from selenium.webdriver.common.by import By
-
-# import InstaPy modules
-from .util import (
- explicit_wait,
- get_username_from_id,
- is_page_available,
- load_user_id,
- update_activity,
- web_address_navigator,
-)
-from .xpath import read_xpath
-
-
-def get_following_status(
- browser, track, username, person, person_id, logger, logfolder
-):
- """Verify if you are following the user in the loaded page"""
- if person == username:
- return "OWNER", None
-
- if track == "profile":
- ig_homepage = "https://www.instagram.com/"
- web_address_navigator(browser, ig_homepage + person)
-
- follow_button_XP = read_xpath(get_following_status.__name__, "follow_button_XP")
- failure_msg = "--> Unable to detect the following status of '{}'!"
- user_inaccessible_msg = (
- "Couldn't access the profile page of '{}'!\t~might have changed the"
- " username".format(person)
- )
-
- # check if the page is available
- valid_page = is_page_available(browser, logger)
- if not valid_page:
- logger.warning(user_inaccessible_msg)
- person_new = verify_username_by_id(
- browser, username, person, None, logger, logfolder
- )
- if person_new:
- ig_homepage = "https://www.instagram.com/"
- web_address_navigator(browser, ig_homepage + person_new)
- valid_page = is_page_available(browser, logger)
- if not valid_page:
- logger.error(failure_msg.format(person_new.encode("utf-8")))
- return "UNAVAILABLE", None
- else:
- logger.error(failure_msg.format(person.encode("utf-8")))
- return "UNAVAILABLE", None
-
- # wait until the follow button is located and visible, then get it
- try:
- browser.find_element(
- By.XPATH, read_xpath(get_following_status.__name__, "follow_button_XP")
- )
- follow_button_XP = read_xpath(get_following_status.__name__, "follow_button_XP")
- except NoSuchElementException:
- try:
- follow_button = browser.find_element(
- By.XPATH,
- read_xpath(get_following_status.__name__, "follow_span_XP_following"),
- )
- return "Following", follow_button
- except:
- return "UNAVAILABLE", None
- follow_button = explicit_wait(
- browser, "VOEL", [follow_button_XP, "XPath"], logger, 7, False
- )
-
- if not follow_button:
- browser.execute_script("location.reload()")
- update_activity(browser, state=None)
- sleep(randint(1, 5))
-
- follow_button = explicit_wait(
- browser, "VOEL", [follow_button_XP, "XPath"], logger, 14, False
- )
- if not follow_button:
- # cannot find the any of the expected buttons
- logger.error(failure_msg.format(person.encode("utf-8")))
- return None, None
-
- # get follow status
- following_status = follow_button.text
-
- return following_status, follow_button
-
-
-def verify_username_by_id(browser, username, person, person_id, logger, logfolder):
- """Check if the given user has changed username after the time of
- followed"""
-
- # try to find the user by ID
- person_id = load_user_id(username, person, logger, logfolder)
-
- # if person_id is None, inform the InstaPy user that record does not exist
- if person_id not in [None, "unknown", "undefined"]:
- # get the [new] username of the user from the stored user ID
- person_new = get_username_from_id(browser, person_id, logger)
-
- # if person_new is None, inform the InstaPy user that record does not exist
- if person_new is not None and person_new != person:
- logger.info(
- "User '{}' has changed username and now is called '{}' :S".format(
- person, person_new
- )
- )
- return person_new
-
- # check who call this def, since will receive a None value
- logger.info("User '{}' doesn't exist in local records".format(person))
- return None
diff --git a/instapy/icons/Linux/qs_exit_linux.png b/instapy/icons/Linux/qs_exit_linux.png
deleted file mode 100644
index 21faa88f9..000000000
Binary files a/instapy/icons/Linux/qs_exit_linux.png and /dev/null differ
diff --git a/instapy/icons/Linux/qs_sleep_linux.png b/instapy/icons/Linux/qs_sleep_linux.png
deleted file mode 100644
index 3adf75140..000000000
Binary files a/instapy/icons/Linux/qs_sleep_linux.png and /dev/null differ
diff --git a/instapy/icons/Linux/qs_wakeup_linux.png b/instapy/icons/Linux/qs_wakeup_linux.png
deleted file mode 100644
index 0b0f9284d..000000000
Binary files a/instapy/icons/Linux/qs_wakeup_linux.png and /dev/null differ
diff --git a/instapy/icons/Mac/qs_exit_mac.icns b/instapy/icons/Mac/qs_exit_mac.icns
deleted file mode 100644
index 137d5d247..000000000
Binary files a/instapy/icons/Mac/qs_exit_mac.icns and /dev/null differ
diff --git a/instapy/icons/Mac/qs_sleep_mac.icns b/instapy/icons/Mac/qs_sleep_mac.icns
deleted file mode 100644
index b025bce3d..000000000
Binary files a/instapy/icons/Mac/qs_sleep_mac.icns and /dev/null differ
diff --git a/instapy/icons/Mac/qs_wakeup_mac.icns b/instapy/icons/Mac/qs_wakeup_mac.icns
deleted file mode 100644
index dfb90f07f..000000000
Binary files a/instapy/icons/Mac/qs_wakeup_mac.icns and /dev/null differ
diff --git a/instapy/icons/Windows/qs_exit_windows.ico b/instapy/icons/Windows/qs_exit_windows.ico
deleted file mode 100644
index 94b3138f7..000000000
Binary files a/instapy/icons/Windows/qs_exit_windows.ico and /dev/null differ
diff --git a/instapy/icons/Windows/qs_sleep_windows.ico b/instapy/icons/Windows/qs_sleep_windows.ico
deleted file mode 100644
index 620d59986..000000000
Binary files a/instapy/icons/Windows/qs_sleep_windows.ico and /dev/null differ
diff --git a/instapy/icons/Windows/qs_wakeup_windows.ico b/instapy/icons/Windows/qs_wakeup_windows.ico
deleted file mode 100644
index 1aa5e7b55..000000000
Binary files a/instapy/icons/Windows/qs_wakeup_windows.ico and /dev/null differ
diff --git a/instapy/icons/qs_originals.zip b/instapy/icons/qs_originals.zip
deleted file mode 100644
index bb8359a53..000000000
Binary files a/instapy/icons/qs_originals.zip and /dev/null differ
diff --git a/instapy/instapy.py b/instapy/instapy.py
deleted file mode 100644
index 2e641e3e6..000000000
--- a/instapy/instapy.py
+++ /dev/null
@@ -1,6176 +0,0 @@
-"""OS Modules environ method to get the setup vars from the Environment"""
-# import built-in & third-party modules
-import csv
-import json
-import logging
-import logging.handlers
-import os
-import random
-import time
-import unicodedata
-from contextlib import contextmanager
-from copy import deepcopy
-from datetime import datetime, timedelta
-from logging.handlers import RotatingFileHandler
-from math import ceil
-from platform import python_version
-from sys import platform
-
-import requests
-from selenium import webdriver
-from selenium.webdriver import DesiredCapabilities
-from selenium.webdriver.common.by import By
-
-try:
- from pyvirtualdisplay import Display
-except ModuleNotFoundError:
- pass
-
-# import exceptions
-from selenium.common.exceptions import NoSuchElementException
-
-# import InstaPy modules
-from . import __version__
-from .browser import close_browser, set_selenium_local_session
-from .clarifai_util import check_image
-from .comment_util import comment_image, get_comments_on_post, process_comments
-from .commenters_util import (
- extract_information,
- get_photo_urls_from_profile,
- users_liked,
-)
-from .constants import MEDIA_PHOTO, MEDIA_VIDEO
-from .database_engine import get_database
-from .exceptions import InstaPyError
-from .file_manager import get_logfolder, get_workspace
-from .like_util import (
- check_link,
- get_links_for_location,
- get_links_for_tag,
- get_links_for_username,
- get_links_from_feed,
- get_tags,
- like_comment,
- like_image,
- verify_liking,
-)
-from .login_util import login_user
-from .pods_util import (
- comment_restriction,
- get_recent_posts_from_pods,
- group_posts,
- share_my_post_with_pods,
- share_with_pods_restriction,
-)
-from .print_log_writer import log_follower_num, log_following_num
-from .relationship_tools import (
- get_fans,
- get_followers,
- get_following,
- get_mutual_following,
- get_nonfollowers,
- get_unfollowers,
-)
-from .settings import Settings, localize_path
-from .story_util import watch_story
-from .text_analytics import text_analysis, yandex_supported_languages
-from .time_util import set_sleep_percentage, sleep
-from .unfollow_util import (
- dump_follow_restriction,
- follow_restriction,
- follow_user,
- get_follow_requests,
- get_given_user_followers,
- get_given_user_following,
- set_automated_followed_pool,
- unfollow,
- unfollow_user,
-)
-from .util import (
- dump_record_activity,
- file_handling,
- get_active_users,
- get_bounding_box,
- get_cord_location,
- highlight_print,
- interruption_handler,
- parse_cli_args,
- save_account_progress,
- scroll_down,
- truncate_float,
- validate_username,
- web_address_navigator,
-)
-from .xpath import read_xpath
-
-
-class InstaPy:
- """Class to be instantiated to use the script"""
-
- def __init__(
- self,
- username: str = None,
- password: str = None,
- nogui: bool = False,
- selenium_local_session: bool = True,
- browser_profile_path: str = None,
- page_delay: int = 25,
- show_logs: bool = True,
- headless_browser: bool = False,
- proxy_username: str = None,
- proxy_password: str = None,
- proxy_address: str = None,
- proxy_port: str = None,
- disable_image_load: bool = False,
- multi_logs: bool = True,
- log_handler=None, # TODO function type ?
- geckodriver_path: str = None,
- split_db: bool = False,
- bypass_security_challenge_using: str = "email",
- security_codes: int = 0000,
- want_check_browser: bool = True,
- browser_executable_path: str = None,
- geckodriver_log_level: str = "info", # "info" by default
- ):
- print("InstaPy Version: {}".format(__version__))
- cli_args = parse_cli_args()
- username = cli_args.username or username
- password = cli_args.password or password
- page_delay = cli_args.page_delay or page_delay
- headless_browser = cli_args.headless_browser or headless_browser
- proxy_address = cli_args.proxy_address or proxy_address
- proxy_port = cli_args.proxy_port or proxy_port
- disable_image_load = cli_args.disable_image_load or disable_image_load
- split_db = cli_args.split_db or split_db
- want_check_browser = cli_args.want_check_browser or want_check_browser
-
- Settings.InstaPy_is_running = True
- # workspace must be ready before anything
- if not get_workspace():
- raise InstaPyError("Oh no! I don't have a workspace to work at :'(")
-
- # virtual display to hide browser (not supported on Windows)
- self.nogui = nogui
- if self.nogui:
- if not platform.startswith("win32"):
- self.display = Display(visible=0, size=(800, 600))
- self.display.start()
- else:
- raise InstaPyError("The 'nogui' parameter isn't supported on Windows.")
-
- self.browser = None
- self.page_delay = page_delay
- self.disable_image_load = disable_image_load
- self.bypass_security_challenge_using = bypass_security_challenge_using
- self.security_codes = security_codes
-
- # choose environment over static typed credentials
- self.username = os.environ.get("INSTA_USER") or username
- self.password = os.environ.get("INSTA_PW") or password
-
- Settings.profile["name"] = self.username
-
- self.split_db = split_db
- if self.split_db:
- Settings.database_location = localize_path(
- "db", "instapy_{}.db".format(self.username)
- )
-
- self.want_check_browser = want_check_browser
-
- self.do_comment = False
- self.comment_percentage = 0
- self.comments = ["Cool!", "Nice!", "Looks good!"]
- self.photo_comments = []
- self.video_comments = []
-
- self.do_reply_to_comments = False
- self.reply_to_comments_percent = 0
- self.comment_replies = []
- self.photo_comment_replies = []
- self.video_comment_replies = []
-
- self.liked_img = 0
- self.already_liked = 0
- self.liked_comments = 0
- self.commented = 0
- self.replied_to_comments = 0
- self.followed = 0
- self.already_followed = 0
- self.unfollowed = 0
- self.followed_by = 0
- self.following_num = 0
- self.inap_img = 0
- self.not_valid_users = 0
- self.video_played = 0
- self.already_Visited = 0
- self.stories_watched = 0
- self.reels_watched = 0
-
- self.follow_times = 1
- self.share_times = 1
- self.comment_times = 1
- self.do_follow = False
- self.follow_percentage = 0
- self.dont_include = set()
- self.white_list = set()
- self.blacklist = {"enabled": "True", "campaign": ""}
- self.automatedFollowedPool = {"all": [], "eligible": []}
- self.do_like = False
- self.like_percentage = 0
- self.do_comment_liked_photo = False
- self.do_story = False
- self.story_percentage = 0
- self.story_simulate = False
- self.smart_hashtags = []
- self.smart_location_hashtags = []
-
- self.dont_like = ["sex", "nsfw"]
- self.mandatory_words = []
- self.ignore_if_contains = []
- self.ignore_users = []
-
- self.user_interact_amount = 0
- self.user_interact_media = None
- self.user_interact_percentage = 0
- self.user_interact_random = False
- self.dont_follow_inap_post = True
-
- self.use_clarifai = False
- self.clarifai_api_key = None
- self.clarifai_models = []
- self.clarifai_workflow = []
- self.clarifai_probability = 0.50
- self.clarifai_img_tags = []
- self.clarifai_img_tags_skip = []
- self.clarifai_full_match = False
- self.clarifai_check_video = False
- self.clarifai_proxy = None
-
- self.potency_ratio = None # 1.3466
- self.delimit_by_numbers = None
-
- self.max_followers = None # 90000
- self.max_following = None # 66834
- self.min_followers = None # 35
- self.min_following = None # 27
-
- self.delimit_liking = False
- self.liking_approved = True
- self.max_likes = 1000
- self.min_likes = 0
-
- self.delimit_commenting = False
- self.commenting_approved = True
- self.max_comments = 35
- self.min_comments = 0
- self.comments_mandatory_words = []
- self.max_posts = None
- self.min_posts = None
- self.skip_business_categories = []
- self.skip_bio_keyword = []
- self.mandatory_bio_keywords = []
- self.dont_skip_business_categories = []
- self.skip_business = False
- self.skip_non_business = False
- self.skip_no_profile_pic = False
- self.skip_private = True
- self.skip_public = False
- self.skip_public_percentage = 0
- self.skip_business_percentage = 100
- self.skip_no_profile_pic_percentage = 100
- self.skip_private_percentage = 100
- self.relationship_data = {username: {"all_following": [], "all_followers": []}}
-
- self.simulation = {"enabled": True, "percentage": 100}
-
- self.mandatory_language = False
- self.mandatory_character = []
- self.check_letters = {}
-
- # use this variable to terminate the nested loops after quotient
- # reaches
- self.quotient_breach = False
- # hold the consecutive jumps and set max of it used with QS to break
- # loops
- self.jumps = {
- "consequent": {"likes": 0, "comments": 0, "follows": 0, "unfollows": 0},
- "limit": {"likes": 7, "comments": 3, "follows": 5, "unfollows": 4},
- }
-
- self.allowed_pod_topics = [
- "general",
- "fashion",
- "food",
- "travel",
- "sports",
- "entertainment",
- ]
- self.allowed_pod_engagement_modes = ["no_comments", "light", "normal", "heavy"]
-
- # stores the features' name which are being used by other features
- self.internal_usage = {}
-
- self.aborting = False
- self.start_time = time.time()
-
- # proxy address
- self.proxy_address = proxy_address
-
- # assign logger
- self.show_logs = show_logs
- Settings.show_logs = show_logs or None
- self.multi_logs = multi_logs
- self.logfolder = get_logfolder(self.username, self.multi_logs)
- self.logger = self.get_instapy_logger(self.show_logs, log_handler)
-
- get_database(make=True) # IMPORTANT: think twice before relocating
-
- if selenium_local_session:
- self.browser, err_msg = set_selenium_local_session(
- proxy_address,
- proxy_port,
- proxy_username,
- proxy_password,
- headless_browser,
- browser_profile_path,
- disable_image_load,
- page_delay,
- geckodriver_path,
- browser_executable_path,
- self.logfolder,
- self.logger,
- geckodriver_log_level,
- )
- if len(err_msg) > 0:
- raise InstaPyError(err_msg)
-
- def get_instapy_logger(self, show_logs: bool, log_handler=None):
- """
- Handles the creation and retrieval of loggers to avoid
- re-instantiation.
- """
-
- existing_logger = Settings.loggers.get(self.username)
- if existing_logger is not None:
- return existing_logger
- else:
- # initialize and setup logging system for the InstaPy object
- logger = logging.getLogger(self.username)
- logger.setLevel(logging.DEBUG)
- # log name and format
- general_log = "{}general.log".format(self.logfolder)
- file_handler = logging.FileHandler(general_log)
- # log rotation, 5 logs with 10MB size each one
- file_handler = RotatingFileHandler(
- general_log, maxBytes=10 * 1024 * 1024, backupCount=5
- )
- file_handler.setLevel(logging.DEBUG)
- extra = {"username": self.username}
- logger_formatter = logging.Formatter(
- "%(levelname)s [%(asctime)s] [%(username)s] %(message)s",
- datefmt="%Y-%m-%d %H:%M:%S",
- )
- file_handler.setFormatter(logger_formatter)
- logger.addHandler(file_handler)
-
- # add custom user handler if given
- if log_handler:
- logger.addHandler(log_handler)
-
- if show_logs is True:
- console_handler = logging.StreamHandler()
- console_handler.setLevel(logging.DEBUG)
- console_handler.setFormatter(logger_formatter)
- logger.addHandler(console_handler)
-
- logger = logging.LoggerAdapter(logger, extra)
-
- Settings.loggers[self.username] = logger
- Settings.logger = logger
- return logger
-
- def set_selenium_remote_session(
- self, logger, selenium_url: str = "", selenium_driver=None
- ):
- """
- Starts remote session for a selenium server.
- Creates a new selenium driver instance for remote session or uses
- provided one. Useful for docker setup.
-
- :param selenium_url: string
- :param selenium_driver: selenium WebDriver
- :return: self
- """
- if self.aborting:
- return self
-
- if selenium_driver:
- self.browser = selenium_driver
- else:
- self.browser = webdriver.Remote(
- command_executor=selenium_url,
- desired_capabilities=DesiredCapabilities.FIREFOX,
- )
-
- # convert_selenium_browser(selenium_driver)
- message = "Session started!"
- highlight_print("browser", message, "initialization", "info", logger)
-
- return self
-
- def login(self):
- """Used to login the user either with the username and password"""
- # InstaPy uses page_delay speed to implicit wait for elements,
- # here we're decreasing it to 5 seconds instead of the default 25
- # seconds to speed up the login process.
- #
- # In short: default page_delay speed took 25 seconds trying to locate
- # every element, now it's taking 5 seconds.
- temporary_page_delay = 5
- self.browser.implicitly_wait(temporary_page_delay)
-
- if not login_user(
- self.browser,
- self.username,
- self.password,
- self.logger,
- self.logfolder,
- self.proxy_address,
- self.bypass_security_challenge_using,
- self.security_codes,
- self.want_check_browser,
- ):
- message = (
- "Unable to login to Instagram! "
- "You will find more information in the logs above."
- )
- highlight_print(self.username, message, "login", "critical", self.logger)
-
- self.aborting = True
- return self
-
- # back the page_delay to default, or the value set by the user
- self.browser.implicitly_wait(self.page_delay)
- message = "Logged in successfully!"
- highlight_print(self.username, message, "login", "info", self.logger)
- # try to save account progress
- try:
- save_account_progress(self.browser, self.username, self.logger)
- except Exception as e:
- # Comment:
- # Saw this error:
- # "TypeError: window._sharedData.entry_data.ProfilePage is undefined"
- # when IG deleted a pic or video due community guidelines, then the
- # FF session shows a different page that interrupts the normal flow.
- self.logger.warning(
- "Unable to save account progress, skipping data update \n\t{}".format(
- str(e).encode("utf-8")
- )
- )
-
- # logs only followers/following numbers when able to login,
- # to speed up the login process and avoid loading profile
- # page (meaning less server calls)
- self.followed_by = log_follower_num(self.browser, self.username, self.logfolder)
- self.following_num = log_following_num(
- self.browser, self.username, self.logfolder
- )
-
- return self
-
- def set_sleep_reduce(self, percentage: int):
- set_sleep_percentage(percentage)
- return self
-
- def set_action_delays(
- self,
- enabled: bool = False,
- like: int = None,
- comment: int = None,
- follow: int = None,
- unfollow: int = None,
- story: int = None,
- randomize: bool = False,
- random_range_from: int = None,
- random_range_to: int = None,
- safety_match: bool = True,
- ):
- """Set custom sleep delay after actions"""
- Settings.action_delays.update(
- {
- "enabled": enabled,
- "like": like,
- "comment": comment,
- "follow": follow,
- "unfollow": unfollow,
- "story": story,
- "randomize": randomize,
- "random_range": (random_range_from, random_range_to),
- "safety_match": safety_match,
- }
- )
-
- def set_do_comment(
- self,
- enabled: bool = False,
- comment_liked_photo: bool = False,
- percentage: int = 0,
- ):
- """
- Defines if images should be commented or not.
- E.g. percentage=25 means every ~4th picture will be commented.
- """
-
- if self.aborting:
- return self
-
- self.do_comment = enabled
- self.do_comment_liked_photo = comment_liked_photo # Comment a liked photo
- self.comment_percentage = percentage
-
- return self
-
- def set_comments(self, comments: list = [], media: str = None):
- """
- Sets the possible posted comments.
- 'What an amazing shot :heart_eyes: !' is an example for using emojis.
- """
- if self.aborting:
- return self
-
- if media not in [None, MEDIA_PHOTO, MEDIA_VIDEO]:
- self.logger.warning('Unkown media type! Treating as "any".')
- media = None
-
- self.comments = comments
-
- if media is None:
- self.comments = comments
- else:
- attr = "{}_comments".format(media.lower())
- setattr(self, attr, comments)
-
- return self
-
- def set_do_follow(self, enabled: bool = False, percentage: int = 0, times: int = 1):
- """Defines if the user of the liked image should be followed"""
- if self.aborting:
- return self
-
- self.follow_times = times
- self.do_follow = enabled
- self.follow_percentage = percentage
-
- return self
-
- def set_do_like(self, enabled: bool = False, percentage: int = 0):
- if self.aborting:
- return self
-
- self.do_like = enabled
- self.like_percentage = min(percentage, 100)
-
- return self
-
- def set_do_story(
- self, enabled: bool = False, percentage: int = 0, simulate: bool = False
- ):
- """
- configure stories
- enabled: to add story to interact
- percentage: how much to watch
- simulate: if True, we will simulate watching (faster),
- but nothing will be seen on the browser window
- """
- if self.aborting:
- return self
-
- self.do_story = enabled
- self.story_percentage = min(percentage, 100)
- self.story_simulate = simulate
-
- return self
-
- def set_dont_like(self, tags: list = []):
- """Changes the possible restriction tags, if one of this
- words is in the description, the image won't be liked but user
- still might be unfollowed"""
- if self.aborting:
- return self
-
- if not isinstance(tags, list):
- self.logger.warning("Unable to use your set_dont_like configuration!")
- self.aborting = True
-
- self.dont_like = tags
-
- return self
-
- def set_mandatory_words(self, tags: list = []):
- """Changes the possible restriction tags, if all of this
- hashtags is in the description, the image will be liked"""
- if self.aborting:
- return self
-
- if not isinstance(tags, list):
- self.logger.warning("Unable to use your set_mandatory_words configuration!")
- self.aborting = True
-
- self.mandatory_words = tags
-
- return self
-
- def set_user_interact(
- self,
- amount: int = 10,
- percentage: int = 100,
- randomize: bool = False,
- media: str = None,
- ):
- """Define if posts of given user should be interacted"""
- if self.aborting:
- return self
-
- self.user_interact_amount = amount
- self.user_interact_random = randomize
- self.user_interact_percentage = percentage
- self.user_interact_media = media
-
- return self
-
- def set_ignore_users(self, users: list = []):
- """Changes the possible restriction to users, if a user who posts
- is one of these, the image won't be liked"""
- if self.aborting:
- return self
-
- self.ignore_users = users
-
- return self
-
- def set_ignore_if_contains(self, words: list = []):
- """Ignores the don't likes if the description contains
- one of the given words"""
- if self.aborting:
- return self
-
- self.ignore_if_contains = words
-
- return self
-
- def set_dont_include(self, friends: list = None):
- """Defines which accounts should not be unfollowed"""
- if self.aborting:
- return self
-
- self.dont_include = set(friends) or set()
- self.white_list = set(friends) or set()
-
- return self
-
- def set_switch_language(self, option: bool = True):
- self.switch_language = option
- return self
-
- def set_use_clarifai(
- self,
- enabled: bool = False,
- api_key: str = None,
- models: list = ["general"],
- workflow: list = [],
- probability: float = 0.50,
- full_match: bool = False,
- check_video: bool = False,
- proxy: str = None,
- ):
- """
- Defines if the clarifai img api should be used
- Which 'project' will be used (only 5000 calls per month)
-
- Raises:
- InstaPyError if os is windows
- """
- if self.aborting:
- return self
-
- # if os.name == 'nt':
- # raise InstaPyError('Clarifai is not supported on Windows')
-
- self.use_clarifai = enabled
-
- if api_key is None and self.clarifai_api_key is None:
- self.clarifai_api_key = os.environ.get("CLARIFAI_API_KEY")
- elif api_key is not None:
- self.clarifai_api_key = api_key
-
- self.clarifai_models = models
- self.clarifai_workflow = workflow
- self.clarifai_probability = probability
- self.clarifai_full_match = full_match
- self.clarifai_check_video = check_video
-
- if proxy is not None:
- self.clarifai_proxy = "https://" + proxy
-
- return self
-
- def set_smart_hashtags(
- self,
- tags: list = None,
- limit: int = 3,
- sort: str = "top",
- log_tags: bool = True,
- ):
- """Generate smart hashtags based on https://displaypurposes.com/"""
- """ranking, banned and spammy tags are filtered out."""
-
- if tags is None:
- print("set_smart_hashtags is misconfigured")
- return
-
- for tag in tags:
- if python_version() > "3.5":
- # CI Travis alert for Python3.5 and apidisplaypurposes
- from apidisplaypurposes import displaypurposes
-
- myToken = displaypurposes.generate_api_token(tag, Settings.user_agent)
- head = {"User-Agent": Settings.user_agent, "api-token": myToken}
- req = requests.get(
- "https://apidisplaypurposes.com/tag/{}".format(tag), headers=head
- )
- else:
- # Old fashion request, must fail in Python <= 3.5
- req = requests.get("https://apidisplaypurposes.com/tag/{}".format(tag))
-
- data = json.loads(req.text)
-
- if data["tagExists"] is True:
- if sort == "top":
- # sort by ranking
- ordered_tags_by_rank = sorted(
- data["results"], key=lambda d: d["rank"], reverse=True
- )
- ranked_tags = ordered_tags_by_rank[:limit]
- for item in ranked_tags:
- # add smart hashtag to like list
- self.smart_hashtags.append(item["tag"])
-
- elif sort == "random":
- if len(data["results"]) < limit:
- random_tags = random.sample(
- data["results"], len(data["results"])
- )
- else:
- random_tags = random.sample(data["results"], limit)
- for item in random_tags:
- self.smart_hashtags.append(item["tag"])
-
- if log_tags is True:
- for item in self.smart_hashtags:
- print("[smart hashtag generated: {}]".format(item))
- else:
- print("Too few results for #{} tag".format(tag))
-
- # delete duplicated tags
- self.smart_hashtags = list(set(self.smart_hashtags))
- return self
-
- def set_smart_location_hashtags(
- self, locations: list, radius: int = 10, limit: int = 3, log_tags: bool = True
- ):
- """Generate smart hashtags based on https://apidisplaypurposes.com/map"""
- if locations is None:
- self.logger.error("set_smart_location_hashtags is misconfigured")
- return self
-
- for location in locations:
- lat, lon = get_cord_location(self.browser, location)
-
- bbox = get_bounding_box(
- lat, lon, logger=self.logger, half_side_in_miles=radius
- )
- bbox_url = "{},{},{},{}&zoom={}".format(
- bbox["lon_min"],
- bbox["lat_min"],
- bbox["lon_max"],
- bbox["lat_max"],
- radius,
- )
- url = "https://apidisplaypurposes.com/local/?bbox={}".format(bbox_url)
-
- req = requests.get(url)
- data = json.loads(req.text)
- if int(data["count"]) == 0:
- self.logger.warning("Too few results for {} location".format(location))
- continue
-
- count = limit if limit < data["count"] else data["count"]
- i = 0
- while i < count:
- self.smart_location_hashtags.append(data["tags"][i]["tag"])
- i += 1
-
- self.smart_location_hashtags = list(set(self.smart_location_hashtags))
-
- if log_tags is True:
- self.logger.info(
- "[smart location hashtag generated: {}]\n".format(
- self.smart_location_hashtags
- )
- )
-
- return self
-
- def set_mandatory_language(
- self, enabled: bool = False, character_set: list = ["LATIN"]
- ):
- """Restrict the description of the image to a character set"""
-
- if self.aborting:
- return self
-
- char_set = []
-
- if not isinstance(character_set, list):
- character_set = [character_set]
-
- for chr_set in character_set:
- if chr_set not in [
- "LATIN",
- "GREEK",
- "CYRILLIC",
- "ARABIC",
- "HEBREW",
- "CJK",
- "HANGUL",
- "HIRAGANA",
- "KATAKANA",
- "THAI",
- "MATHEMATICAL",
- ]:
- self.logger.warning('Unkown character set! Treating as "LATIN".')
- ch_set_name = "LATIN"
- else:
- ch_set_name = chr_set
-
- if ch_set_name not in char_set:
- char_set.append(ch_set_name)
-
- self.mandatory_language = enabled
- self.mandatory_character = char_set
-
- return self
-
- def clarifai_check_img_for(
- self,
- tags: list = None,
- tags_skip: list = None,
- comment: bool = False,
- comments: list = None,
- ):
- """Defines the tags the images should be checked for"""
- if self.aborting:
- return self
-
- if tags is None and not self.clarifai_img_tags:
- self.use_clarifai = False
- elif tags:
- self.clarifai_img_tags.append((tags, comment, comments))
- self.clarifai_img_tags_skip = tags_skip or []
-
- return self
-
- def query_clarifai(self):
- """Method for querying Clarifai using parameters set in
- clarifai_check_img_for"""
- return check_image(
- self.browser,
- self.clarifai_api_key,
- self.clarifai_img_tags,
- self.clarifai_img_tags_skip,
- self.logger,
- self.clarifai_models,
- self.clarifai_workflow,
- self.clarifai_probability,
- self.clarifai_full_match,
- self.clarifai_check_video,
- proxy=self.clarifai_proxy,
- )
-
- def follow_commenters(
- self,
- usernames: list,
- amount: int = 10,
- daysold: int = 365,
- max_pic: int = 50,
- sleep_delay: int = 600,
- interact: bool = False,
- ):
- """Follows users' commenters"""
-
- if self.aborting:
- return self
-
- message = "Starting to follow commenters.."
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- if not isinstance(usernames, list):
- usernames = [usernames]
-
- followed_all = 0
- followed_new = 0
-
- # hold the current global values for differentiating at the end
- already_followed_init = self.already_followed
- not_valid_users_init = self.not_valid_users
- liked_init = self.liked_img
- already_liked_init = self.already_liked
- commented_init = self.commented
- inap_img_init = self.inap_img
-
- relax_point = random.randint(7, 14) # you can use some plain value
- # `10` instead of this quietly randomized score
- self.quotient_breach = False
-
- for username in usernames:
- if self.quotient_breach:
- break
-
- self.logger.info(
- "Following commenters of '{}' from {} pictures in last {} "
- "days...\nScrapping wall..".format(username, max_pic, daysold)
- )
- commenters = extract_information(
- self.browser, username, daysold, max_pic, self.logger
- )
-
- if len(commenters) > 0:
- self.logger.info("Going to follow top {} users.\n".format(amount))
- sleep(1)
- # This way of iterating will prevent sleep interference
- # between functions
- random.shuffle(commenters)
- for commenter in commenters[:amount]:
- if self.quotient_breach:
- self.logger.warning(
- "--> Follow quotient reached its peak!"
- "\t~leaving Follow-Commenters activity\n"
- )
- break
-
- with self.feature_in_feature("follow_by_list", True):
- followed = self.follow_by_list(
- commenter, self.follow_times, sleep_delay, interact
- )
- if followed > 0:
- followed_all += 1
- followed_new += 1
- self.logger.info("Total Follow: {}\n".format(str(followed_all)))
- # Take a break after a good following
- if followed_new >= relax_point:
- delay_random = random.randint(
- ceil(sleep_delay * 0.85), ceil(sleep_delay * 1.14)
- )
- sleep_time = (
- "{} seconds".format(delay_random)
- if delay_random < 60
- else "{} minutes".format(
- truncate_float(delay_random / 60, 2)
- )
- )
- self.logger.info(
- "------=> Followed {} new users ~sleeping "
- "about {}".format(followed_new, sleep_time)
- )
- sleep(delay_random)
- relax_point = random.randint(7, 14)
- followed_new = 0
- pass
-
- else:
- self.logger.info("Noone commented, noone to follow.\n")
-
- sleep(1)
-
- self.logger.info("Finished following Commenters!\n")
-
- # find the feature-wide action sizes by taking a difference
- already_followed = self.already_followed - already_followed_init
- not_valid_users = self.not_valid_users - not_valid_users_init
- liked = self.liked_img - liked_init
- already_liked = self.already_liked - already_liked_init
- commented = self.commented - commented_init
- inap_img = self.inap_img - inap_img_init
-
- # print results
- self.logger.info("Followed: {}".format(followed_all))
- self.logger.info("Already followed: {}".format(already_followed))
- self.logger.info("Not valid users: {}".format(not_valid_users))
-
- if interact is True:
- print("")
- # print results out of interactions
- self.logger.info("Liked: {}".format(liked))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Inappropriate: {}".format(inap_img))
-
- return self
-
- def follow_likers(
- self,
- usernames: list,
- photos_grab_amount: int = 3,
- follow_likers_per_photo: int = 3,
- randomize: bool = True,
- sleep_delay: int = 600,
- interact: bool = False,
- ):
- """Follows users' likers"""
- if self.aborting:
- return self
-
- message = "Starting to follow likers.."
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- if not isinstance(usernames, list):
- usernames = [usernames]
-
- if photos_grab_amount > 12:
- self.logger.info(
- "Sorry, you can only grab likers from first 12 photos for "
- "given username now.\n"
- )
- photos_grab_amount = 12
-
- followed_all = 0
- followed_new = 0
-
- # hold the current global values for differentiating at the end
- already_followed_init = self.already_followed
- not_valid_users_init = self.not_valid_users
- liked_init = self.liked_img
- already_liked_init = self.already_liked
- commented_init = self.commented
- inap_img_init = self.inap_img
-
- relax_point = random.randint(7, 14) # you can use some plain value
- # `10` instead of this quitely randomized score
- self.quotient_breach = False
-
- for username in usernames:
- if self.quotient_breach:
- break
-
- photo_urls = get_photo_urls_from_profile(
- self.browser, username, photos_grab_amount, randomize, self.logger
- )
- sleep(1)
- if not isinstance(photo_urls, list):
- photo_urls = [photo_urls]
-
- for photo_url in photo_urls:
- if self.quotient_breach:
- break
-
- likers = users_liked(
- self.browser, photo_url, follow_likers_per_photo, self.logger
- )
- # This way of iterating will prevent sleep interference
- # between functions
- random.shuffle(likers)
-
- for liker in likers[:follow_likers_per_photo]:
- if self.quotient_breach:
- self.logger.warning(
- "--> Follow quotient reached its peak!"
- "\t~leaving Follow-Likers activity\n"
- )
- break
-
- with self.feature_in_feature("follow_by_list", True):
- followed = self.follow_by_list(
- liker, self.follow_times, sleep_delay, interact
- )
- if followed > 0:
- followed_all += 1
- followed_new += 1
- self.logger.info("Total Follow: {}\n".format(str(followed_all)))
- # Take a break after a good following
- if followed_new >= relax_point:
- delay_random = random.randint(
- ceil(sleep_delay * 0.85), ceil(sleep_delay * 1.14)
- )
- sleep_time = (
- "{} seconds".format(delay_random)
- if delay_random < 60
- else "{} minutes".format(
- truncate_float(delay_random / 60, 2)
- )
- )
- self.logger.info(
- "------=> Followed {} new users ~sleeping "
- "about {}".format(followed_new, sleep_time)
- )
- sleep(delay_random)
- relax_point = random.randint(7, 14)
- followed_new = 0
- pass
-
- self.logger.info("Finished following Likers!\n")
-
- # find the feature-wide action sizes by taking a difference
- already_followed = self.already_followed - already_followed_init
- not_valid_users = self.not_valid_users - not_valid_users_init
- liked = self.liked_img - liked_init
- already_liked = self.already_liked - already_liked_init
- commented = self.commented - commented_init
- inap_img = self.inap_img - inap_img_init
-
- # print results
- self.logger.info("Followed: {}".format(followed_all))
- self.logger.info("Already followed: {}".format(already_followed))
- self.logger.info("Not valid users: {}".format(not_valid_users))
-
- if interact is True:
- print("")
- # print results out of interactions
- self.logger.info("Liked: {}".format(liked))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Inappropriate: {}".format(inap_img))
-
- return self
-
- def follow_by_list(
- self,
- followlist: list,
- times: int = 1,
- sleep_delay: int = 600,
- interact: bool = False,
- ):
- """Allows to follow by any scrapped list"""
- if not isinstance(followlist, list):
- followlist = [followlist]
-
- if self.aborting:
- self.logger.info(">>> self aborting prevented")
- # return self
-
- # standalone means this feature is started by the user
- standalone = (
- True if "follow_by_list" not in self.internal_usage.keys() else False
- )
- # skip validation in case of it is already accomplished
- users_validated = (
- True
- if not standalone and not self.internal_usage["follow_by_list"]["validate"]
- else False
- )
-
- self.follow_times = times or 0
-
- followed_all = 0
- followed_new = 0
- already_followed = 0
- not_valid_users = 0
-
- # hold the current global values for differentiating at the end
- liked_init = self.liked_img
- already_liked_init = self.already_liked
- commented_init = self.commented
- inap_img_init = self.inap_img
-
- relax_point = random.randint(7, 14) # you can use some plain value
- # `10` instead of this quitely randomized score
- self.quotient_breach = False
-
- for acc_to_follow in followlist:
- if self.jumps["consequent"]["follows"] >= self.jumps["limit"]["follows"]:
- self.logger.warning(
- "--> Follow quotient reached its peak!\t~leaving "
- "Follow-By-Tags activity\n"
- )
- # reset jump counter before breaking the loop
- self.jumps["consequent"]["follows"] = 0
- # turn on `quotient_breach` to break the internal iterators
- # of the caller
- self.quotient_breach = True if not standalone else False
- break
-
- if follow_restriction(
- "read", acc_to_follow, self.follow_times, self.logger
- ):
- print("")
- continue
-
- if not users_validated:
- # Verify if the user should be followed
- validation, details = self.validate_user_call(acc_to_follow)
- if validation is not True or acc_to_follow == self.username:
- self.logger.info("--> Not a valid user: {}".format(details))
- not_valid_users += 1
- continue
-
- # Take a break after a good following
- if followed_new >= relax_point:
- delay_random = random.randint(
- ceil(sleep_delay * 0.85), ceil(sleep_delay * 1.14)
- )
- sleep_time = (
- "{} seconds".format(delay_random)
- if delay_random < 60
- else "{} minutes".format(truncate_float(delay_random / 60, 2))
- )
- self.logger.info(
- "Followed {} new users ~sleeping about {}\n".format(
- followed_new, sleep_time
- )
- )
- sleep(delay_random)
- followed_new = 0
- relax_point = random.randint(7, 14)
- pass
-
- if not follow_restriction(
- "read", acc_to_follow, self.follow_times, self.logger
- ):
- follow_state, msg = follow_user(
- self.browser,
- "profile",
- self.username,
- acc_to_follow,
- None,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
- sleep(random.randint(1, 3))
-
- if follow_state is True:
- followed_all += 1
- followed_new += 1
- # reset jump counter after a successful follow
- self.jumps["consequent"]["follows"] = 0
-
- if standalone: # print only for external usage (
- # internal callers have their printers)
- self.logger.info("Total Follow: {}\n".format(str(followed_all)))
-
- # Check if interaction is expected
- if interact and self.do_like:
- do_interact = (
- random.randint(0, 100) <= self.user_interact_percentage
- )
- # Do interactions if any
- if do_interact and self.user_interact_amount > 0:
- # store original value of `self.do_follow`
- original_do_follow = self.do_follow
- # disable following temporarily
- # cos the user is already followed
- self.do_follow = False
-
- # disable revalidating user in interact_by_users
- with self.feature_in_feature("interact_by_users", False):
- self.interact_by_users(
- acc_to_follow,
- self.user_interact_amount,
- self.user_interact_random,
- self.user_interact_media,
- )
-
- # revert back to original `self.do_follow` value
- self.do_follow = original_do_follow
-
- elif msg == "already followed":
- already_followed += 1
-
- elif msg == "jumped":
- # will break the loop after certain consecutive jumps
- self.jumps["consequent"]["follows"] += 1
-
- sleep(1)
-
- if standalone: # print only for external usage (internal callers
- # have their printers)
- self.logger.info("Finished following by List!\n")
- # print summary
- self.logger.info("Followed: {}".format(followed_all))
- self.logger.info("Already followed: {}".format(already_followed))
- self.logger.info("Not valid users: {}".format(not_valid_users))
-
- if interact is True:
- print("")
- # find the feature-wide action sizes by taking a difference
- liked = self.liked_img - liked_init
- already_liked = self.already_liked - already_liked_init
- commented = self.commented - commented_init
- inap_img = self.inap_img - inap_img_init
-
- # print the summary out of interactions
- self.logger.info("Liked: {}".format(liked))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Inappropriate: {}".format(inap_img))
-
- # always sum up general objects regardless of the request size
- self.followed += followed_all
- self.already_followed += already_followed
- self.not_valid_users += not_valid_users
-
- return followed_all
-
- def set_relationship_bounds(
- self,
- enabled: bool = False,
- potency_ratio: float = None,
- delimit_by_numbers: bool = None,
- min_posts: int = None,
- max_posts: int = None,
- max_followers: int = None,
- max_following: int = None,
- min_followers: int = None,
- min_following: int = None,
- ):
- """Sets the potency ratio and limits to the provide an efficient
- activity between the targeted masses"""
-
- self.potency_ratio = potency_ratio if enabled is True else None
- self.delimit_by_numbers = delimit_by_numbers if enabled is True else None
-
- self.max_followers = max_followers
- self.min_followers = min_followers
-
- self.max_following = max_following
- self.min_following = min_following
-
- self.min_posts = min_posts if enabled is True else None
- self.max_posts = max_posts if enabled is True else None
-
- def validate_user_call(self, user_name: str):
- """Short call of validate_username() function"""
- validation, details = validate_username(
- self.browser,
- user_name,
- self.username,
- self.ignore_users,
- self.blacklist,
- self.potency_ratio,
- self.delimit_by_numbers,
- self.max_followers,
- self.max_following,
- self.min_followers,
- self.min_following,
- self.min_posts,
- self.max_posts,
- self.skip_private,
- self.skip_private_percentage,
- self.skip_public,
- self.skip_public_percentage,
- self.skip_no_profile_pic,
- self.skip_no_profile_pic_percentage,
- self.skip_business,
- self.skip_non_business,
- self.skip_business_percentage,
- self.skip_business_categories,
- self.dont_skip_business_categories,
- self.skip_bio_keyword,
- self.mandatory_bio_keywords,
- self.logger,
- self.logfolder,
- )
- return validation, details
-
- def fetch_smart_comments(self, is_video: bool, temp_comments: list):
- if temp_comments:
- # Use clarifai related comments only!
- comments = temp_comments
- elif is_video:
- comments = self.comments + self.video_comments
- else:
- comments = self.comments + self.photo_comments
-
- return comments
-
- def set_skip_users(
- self,
- skip_private: bool = True,
- private_percentage: int = 100,
- skip_public: bool = False,
- public_percentage: int = 100,
- skip_no_profile_pic: bool = False,
- no_profile_pic_percentage: int = 100,
- skip_business: bool = False,
- business_percentage: int = 100,
- skip_business_categories: list = [],
- dont_skip_business_categories: list = [],
- skip_non_business: bool = False,
- skip_bio_keyword: list = [],
- mandatory_bio_keywords: list = [],
- ):
-
- self.skip_business = skip_business
- self.skip_private = skip_private
- self.skip_no_profile_pic = skip_no_profile_pic
- self.skip_business_percentage = business_percentage
- self.skip_no_profile_pic_percentage = no_profile_pic_percentage
- self.skip_private_percentage = private_percentage
- self.skip_non_business = skip_non_business
- self.skip_bio_keyword = skip_bio_keyword
- self.mandatory_bio_keywords = mandatory_bio_keywords
- self.skip_public = skip_public
- self.skip_public_percentage = public_percentage
- if skip_business:
- self.skip_business_categories = skip_business_categories
- if len(skip_business_categories) == 0:
- self.dont_skip_business_categories = dont_skip_business_categories
- else:
- if len(dont_skip_business_categories) != 0:
- self.logger.warning(
- "Both skip_business_categories and "
- "dont_skip_business categories provided in "
- "skip_business feature,"
- + "will skip only the categories listed in "
- "skip_business_categories parameter"
- )
- # dont_skip_business_categories = [] Setted by default
- # in init
-
- def set_delimit_liking(
- self, enabled: bool = False, max_likes: int = None, min_likes: int = None
- ):
-
- self.delimit_liking = True if enabled is True else False
- self.max_likes = max_likes
- self.min_likes = min_likes
-
- def set_delimit_commenting(
- self,
- enabled: bool = False,
- max_comments: int = None,
- min_comments: int = None,
- comments_mandatory_words: list = [],
- ):
-
- self.delimit_commenting = True if enabled is True else False
- self.max_comments = max_comments
- self.min_comments = min_comments
-
- # comment only when the image description contain at least one of
- # those words
- self.comments_mandatory_words = comments_mandatory_words
-
- def set_simulation(self, enabled: bool = True, percentage: int = 100):
- """Sets aside simulation parameters"""
- if enabled not in [True, False]:
- self.logger.info(
- "Invalid simulation parameter! Please use correct syntax "
- "with accepted values."
- )
-
- elif enabled is False:
- self.simulation["enabled"] = False
-
- else:
- percentage = 0 if percentage is None else percentage
- self.simulation = {"enabled": True, "percentage": percentage}
-
- def like_by_locations(
- self,
- locations: list = None,
- amount: int = 50,
- media: str = None,
- skip_top_posts: bool = True,
- randomize: bool = False,
- ):
- """Likes (default) 50 images per given locations"""
- if self.aborting:
- return self
-
- liked_img = 0
- already_liked = 0
- inap_img = 0
- commented = 0
- followed = 0
- not_valid_users = 0
-
- locations = locations or []
- self.quotient_breach = False
-
- if randomize is True:
- random.shuffle(locations)
-
- for index, location in enumerate(locations):
- if self.quotient_breach:
- break
-
- self.logger.info("Location [{}/{}]".format(index + 1, len(locations)))
- self.logger.info("--> {}".format(location.encode("utf-8")))
-
- try:
- links = get_links_for_location(
- self.browser, location, amount, self.logger, media, skip_top_posts
- )
- except NoSuchElementException as exc:
- self.logger.warning(
- "Error occurred while getting images from location: {} "
- "~maybe too few images exist\n\t{}\n".format(
- location, str(exc).encode("utf-8")
- )
- )
- continue
-
- for i, link in enumerate(links):
- if self.jumps["consequent"]["likes"] >= self.jumps["limit"]["likes"]:
- self.logger.warning(
- "--> Like quotient reached its peak!\t~leaving "
- "Like-By-Locations activity\n"
- )
- self.quotient_breach = True
- # reset jump counter after a breach report
- self.jumps["consequent"]["likes"] = 0
- break
-
- self.logger.info("Like# [{}/{}]".format(i + 1, len(links)))
- self.logger.info(link)
-
- try:
- inappropriate, user_name, is_video, reason, scope = check_link(
- self.browser,
- link,
- self.dont_like,
- self.mandatory_words,
- self.mandatory_language,
- self.is_mandatory_character,
- self.mandatory_character,
- self.check_character_set,
- self.ignore_if_contains,
- self.logger,
- )
-
- if not inappropriate and self.delimit_liking:
- self.liking_approved = verify_liking(
- self.browser, self.max_likes, self.min_likes, self.logger
- )
-
- if not inappropriate and self.liking_approved:
- # validate user
- validation, details = self.validate_user_call(user_name)
-
- if validation is not True:
- self.logger.info("--> Not a valid user: {}".format(details))
- not_valid_users += 1
- continue
- else:
- web_address_navigator(self.browser, link)
-
- # try to like
- like_state, msg = like_image(
- self.browser,
- user_name,
- self.blacklist,
- self.logger,
- self.logfolder,
- liked_img,
- )
-
- if like_state is True or self.do_comment_liked_photo:
- if self.do_comment_liked_photo:
- already_liked += 1
- else:
- liked_img += 1
- # reset jump counter after a successful like
- self.jumps["consequent"]["likes"] = 0
-
- checked_img = True
- temp_comments = []
-
- commenting = (
- random.randint(0, 100) <= self.comment_percentage
- )
- following = random.randint(0, 100) <= self.follow_percentage
-
- if self.use_clarifai and (following or commenting):
- try:
- (
- checked_img,
- temp_comments,
- clarifai_tags,
- ) = self.query_clarifai()
-
- except Exception as err:
- self.logger.error(
- "Image check error: {}".format(err)
- )
-
- # comments
- if (
- self.do_comment
- and user_name not in self.dont_include
- and checked_img
- and commenting
- ):
- comments = self.comments + (
- self.video_comments
- if is_video
- else self.photo_comments
- )
- success = process_comments(
- comments,
- temp_comments,
- self.delimit_commenting,
- self.max_comments,
- self.min_comments,
- self.comments_mandatory_words,
- self.username,
- user_name, # Comments with target user
- self.blacklist,
- self.browser,
- link,
- self.logger,
- self.logfolder,
- )
-
- if success:
- commented += 1
- else:
- self.logger.info("--> Not commented")
- sleep(1)
-
- # following
- if (
- self.do_follow
- and user_name not in self.dont_include
- and checked_img
- and following
- and not follow_restriction(
- "read", user_name, self.follow_times, self.logger
- )
- ):
-
- follow_state, msg = follow_user(
- self.browser,
- "post",
- self.username,
- user_name,
- None,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
- if follow_state is True:
- followed += 1
-
- else:
- self.logger.info("--> Not following")
- sleep(1)
-
- elif msg == "already liked":
- already_liked += 1
-
- elif msg == "block on likes":
- break
-
- elif msg == "jumped":
- # will break the loop after certain consecutive
- # jumps
- self.jumps["consequent"]["likes"] += 1
-
- else:
- self.logger.info(
- "--> Image not liked: {}".format(reason.encode("utf-8"))
- )
- inap_img += 1
-
- except NoSuchElementException as err:
- self.logger.error("Invalid Page: {}".format(err))
-
- self.logger.info("Location: {}".format(location.encode("utf-8")))
- self.logger.info("Liked: {}".format(liked_img))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Followed: {}".format(followed))
- self.logger.info("Inappropriate: {}".format(inap_img))
- self.logger.info("Not valid users: {}\n".format(not_valid_users))
-
- self.followed += followed
- self.liked_img += liked_img
- self.already_liked += already_liked
- self.commented += commented
- self.inap_img += inap_img
- self.not_valid_users += not_valid_users
-
- return self
-
- def comment_by_locations(
- self,
- locations: list = None,
- amount: int = 50,
- media: str = None,
- skip_top_posts: bool = True,
- ):
- """Likes (default) 50 images per given locations"""
- if self.aborting:
- return self
-
- commented = 0
- followed = 0
- inap_img = 0
- not_valid_users = 0
- msg = None
- location = None
-
- locations = locations or []
- self.quotient_breach = False
-
- for index, location in enumerate(locations):
- if self.quotient_breach:
- break
-
- self.logger.info("Location [{}/{}]".format(index + 1, len(locations)))
- self.logger.info("--> {}".format(location.encode("utf-8")))
-
- try:
- links = get_links_for_location(
- self.browser, location, amount, self.logger, media, skip_top_posts
- )
- except NoSuchElementException:
- self.logger.warning("Too few images, skipping this location")
- continue
-
- for i, link in enumerate(links):
- if (
- self.jumps["consequent"]["comments"]
- >= self.jumps["limit"]["comments"]
- ):
- self.logger.warning(
- "--> Comment quotient reached its peak!\t~leaving "
- "Comment-By-Locations activity\n"
- )
- self.quotient_breach = True
- # reset jump counter after a breach report
- self.jumps["consequent"]["comments"] = 0
- break
-
- self.logger.info("Comment# [{}/{}]".format(i + 1, len(links)))
- self.logger.info(link)
-
- try:
- inappropriate, user_name, is_video, reason, scope = check_link(
- self.browser,
- link,
- self.dont_like,
- self.mandatory_words,
- self.mandatory_language,
- self.is_mandatory_character,
- self.mandatory_character,
- self.check_character_set,
- self.ignore_if_contains,
- self.logger,
- )
- if not inappropriate:
- # validate user
- validation, details = self.validate_user_call(user_name)
- if validation is not True:
- self.logger.info(details)
- not_valid_users += 1
- continue
- else:
- web_address_navigator(self.browser, link)
-
- # try to comment
- self.logger.info(
- "--> Image not liked: Likes are disabled for the "
- "'Comment-By-Locations' feature"
- )
-
- checked_img = True
- temp_comments = []
- commenting = random.randint(0, 100) <= self.comment_percentage
- following = random.randint(0, 100) <= self.follow_percentage
-
- if not commenting:
- self.logger.info(
- "--> Image not commented: skipping out of "
- "given comment percentage"
- )
- continue
-
- if self.use_clarifai:
- try:
- (
- checked_img,
- temp_comments,
- clarifai_tags,
- ) = self.query_clarifai()
-
- except Exception as err:
- self.logger.error("Image check error: {}".format(err))
-
- # comments
- if (
- self.do_comment
- and user_name not in self.dont_include
- and checked_img
- and commenting
- ):
- comments = self.comments + (
- self.video_comments if is_video else self.photo_comments
- )
-
- success = process_comments(
- comments,
- temp_comments,
- self.delimit_commenting,
- self.max_comments,
- self.min_comments,
- self.comments_mandatory_words,
- self.username,
- user_name, # Comments with target user
- self.blacklist,
- self.browser,
- link,
- self.logger,
- self.logfolder,
- )
- if success:
- commented += 1
- # reset jump counter after a
- # successful comment
- self.jumps["consequent"]["comments"] = 0
- # try to follow
- if (
- self.do_follow
- and user_name not in self.dont_include
- and checked_img
- and following
- and not follow_restriction(
- "read",
- user_name,
- self.follow_times,
- self.logger,
- )
- ):
- follow_state, msg = follow_user(
- self.browser,
- "post",
- self.username,
- user_name,
- None,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
- if follow_state is True:
- followed += 1
- else:
- self.logger.info("--> Not following")
- sleep(1)
-
- elif msg == "jumped":
- # will break the loop after certain
- # consecutive jumps
- self.jumps["consequent"]["comments"] += 1
-
- else:
- self.logger.info("--> Not commented")
- sleep(1)
-
- else:
- self.logger.info(
- "--> Image not commented: {}".format(reason.encode("utf-8"))
- )
- inap_img += 1
-
- except NoSuchElementException as err:
- self.logger.error("Invalid Page: {}".format(err))
-
- self.logger.info("Location: {}".format(location.encode("utf-8")))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Followed: {}".format(followed))
- self.logger.info("Inappropriate: {}".format(inap_img))
- self.logger.info("Not valid users: {}\n".format(not_valid_users))
-
- self.followed += followed
- self.not_valid_users += not_valid_users
-
- return self
-
- def like_by_tags(
- self,
- tags: list = None,
- use_random_tags: bool = False,
- amount: int = 50,
- skip_top_posts: bool = True,
- use_smart_hashtags: bool = False,
- use_smart_location_hashtags: bool = False,
- interact: bool = False,
- randomize: bool = False,
- media: str = None,
- ):
- """Likes (default) 50 images per given tag"""
- if self.aborting:
- return self
-
- liked_img = 0
- already_liked = 0
- inap_img = 0
- commented = 0
- followed = 0
- not_valid_users = 0
-
- # if smart hashtag is enabled
- if use_smart_hashtags is True and self.smart_hashtags != []:
- self.logger.info("Using smart hashtags")
- tags = self.smart_hashtags
- elif use_smart_location_hashtags is True and self.smart_location_hashtags != []:
- self.logger.info("Using smart location hashtags")
- tags = self.smart_location_hashtags
- else:
- # deletes white spaces in tags
- tags = [tag.strip() for tag in tags]
- tags = tags or []
- self.quotient_breach = False
-
- # if session includes like_by_tags, then randomize the tag list
- if use_random_tags is True:
- random.shuffle(tags)
- for i, tag in enumerate(tags):
- self.logger.info(
- "Tag list randomized: [{}/{}/{}]".format(i + 1, len(tags), tag)
- )
-
- for index, tag in enumerate(tags):
- if self.quotient_breach:
- break
-
- self.logger.info("Tag [{}/{}]".format(index + 1, len(tags)))
- self.logger.info("--> {}".format(tag.encode("utf-8")))
-
- try:
- links = get_links_for_tag(
- self.browser,
- tag,
- amount,
- skip_top_posts,
- randomize,
- media,
- self.logger,
- )
- except NoSuchElementException:
- self.logger.info("Too few images, skipping this tag")
- continue
-
- for i, link in enumerate(links):
- if self.jumps["consequent"]["likes"] >= self.jumps["limit"]["likes"]:
- self.logger.warning(
- "--> Like quotient reached its peak!\t~leaving "
- "Like-By-Tags activity\n"
- )
- self.quotient_breach = True
- # reset jump counter after a breach report
- self.jumps["consequent"]["likes"] = 0
- break
-
- self.logger.info("Like# [{}/{}]".format(i + 1, len(links)))
- self.logger.info(link)
-
- try:
- inappropriate, user_name, is_video, reason, scope = check_link(
- self.browser,
- link,
- self.dont_like,
- self.mandatory_words,
- self.mandatory_language,
- self.is_mandatory_character,
- self.mandatory_character,
- self.check_character_set,
- self.ignore_if_contains,
- self.logger,
- )
-
- if not inappropriate and self.delimit_liking:
- self.liking_approved = verify_liking(
- self.browser, self.max_likes, self.min_likes, self.logger
- )
-
- if not inappropriate and self.liking_approved:
- # validate user
- validation, details = self.validate_user_call(user_name)
- if validation is not True:
- self.logger.info(details)
- not_valid_users += 1
- continue
- else:
- web_address_navigator(self.browser, link)
-
- # try to like
- like_state, msg = like_image(
- self.browser,
- user_name,
- self.blacklist,
- self.logger,
- self.logfolder,
- liked_img,
- )
-
- if like_state is True or self.do_comment_liked_photo:
- if self.do_comment_liked_photo:
- already_liked += 1
- else:
- liked_img += 1
- # reset jump counter after a successful like
- self.jumps["consequent"]["likes"] = 0
-
- checked_img = True
- temp_comments = []
-
- commenting = (
- random.randint(0, 100) <= self.comment_percentage
- )
- following = random.randint(0, 100) <= self.follow_percentage
-
- if self.use_clarifai and (following or commenting):
- try:
- (
- checked_img,
- temp_comments,
- clarifai_tags,
- ) = self.query_clarifai()
-
- except Exception as err:
- self.logger.error(
- "Image check error: {}".format(err)
- )
-
- # comments
- if (
- self.do_comment
- and user_name not in self.dont_include
- and checked_img
- and commenting
- ):
- comments = self.comments + (
- self.video_comments
- if is_video
- else self.photo_comments
- )
- success = process_comments(
- comments,
- temp_comments,
- self.delimit_commenting,
- self.max_comments,
- self.min_comments,
- self.comments_mandatory_words,
- self.username,
- user_name, # Comments with target user
- self.blacklist,
- self.browser,
- link,
- self.logger,
- self.logfolder,
- )
-
- if success:
- commented += 1
- else:
- self.logger.info("--> Not commented")
- sleep(1)
-
- # following
- if (
- self.do_follow
- and user_name not in self.dont_include
- and checked_img
- and following
- and not follow_restriction(
- "read", user_name, self.follow_times, self.logger
- )
- ):
-
- follow_state, msg = follow_user(
- self.browser,
- "post",
- self.username,
- user_name,
- None,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
- if follow_state is True:
- followed += 1
- else:
- self.logger.info("--> Not following")
- sleep(1)
-
- # interactions (if any)
- if interact:
- self.logger.info(
- "--> User gonna be interacted: '{}'".format(
- user_name
- )
- )
-
- # disable revalidating user in like_by_users
- with self.feature_in_feature("like_by_users", False):
- self.like_by_users(
- user_name,
- self.user_interact_amount,
- self.user_interact_random,
- self.user_interact_media,
- )
-
- elif msg == "already liked":
- already_liked += 1
-
- elif msg == "block on likes":
- break
-
- elif msg == "jumped":
- # will break the loop after certain consecutive
- # jumps
- self.jumps["consequent"]["likes"] += 1
-
- else:
- self.logger.info(
- "--> Image not liked: {}".format(reason.encode("utf-8"))
- )
- inap_img += 1
-
- except NoSuchElementException as err:
- self.logger.error("Invalid Page: {}".format(err))
-
- self.logger.info("Tag: {}".format(tag.encode("utf-8")))
-
- self.logger.info("Liked: {}".format(liked_img))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Followed: {}".format(followed))
- self.logger.info("Inappropriate: {}".format(inap_img))
- self.logger.info("Not valid users: {}\n".format(not_valid_users))
-
- self.liked_img += liked_img
- self.already_liked += already_liked
- self.commented += commented
- self.followed += followed
- self.inap_img += inap_img
- self.not_valid_users += not_valid_users
-
- return self
-
- def like_by_users(
- self,
- usernames: list,
- amount: int = 10,
- randomize: bool = False,
- media: str = None,
- ):
- """Likes some amounts of images for each usernames"""
- if self.aborting:
- return self
-
- if not isinstance(usernames, list):
- usernames = [usernames]
-
- # standalone means this feature is started by the user
- standalone = (
- True if "like_by_users" not in self.internal_usage.keys() else False
- )
- # skip validation in case of it is already accomplished
- users_validated = (
- True
- if not standalone and not self.internal_usage["like_by_users"]["validate"]
- else False
- )
-
- username = None
- liked_img = 0
- total_liked_img = 0
- already_liked = 0
- inap_img = 0
- commented = 0
- followed = 0
- not_valid_users = 0
-
- usernames = usernames or []
- self.quotient_breach = False
-
- for index, username in enumerate(usernames):
- if self.quotient_breach:
- break
-
- self.logger.info("Username [{}/{}]".format(index + 1, len(usernames)))
- self.logger.info("--> {}".format(username.encode("utf-8")))
-
- following = random.randint(0, 100) <= self.follow_percentage
-
- if not users_validated:
- validation, details = self.validate_user_call(username)
- if not validation:
- self.logger.info("--> Not a valid user: {}".format(details))
- not_valid_users += 1
- continue
-
- try:
- links = get_links_for_username(
- self.browser,
- self.username,
- username,
- amount,
- self.logger,
- self.logfolder,
- randomize,
- media,
- )
-
- except NoSuchElementException:
- self.logger.error("Element not found, skipping this username")
- continue
-
- if (
- self.do_follow
- and username not in self.dont_include
- and following
- and not follow_restriction(
- "read", username, self.follow_times, self.logger
- )
- ):
- follow_state, msg = follow_user(
- self.browser,
- "profile",
- self.username,
- username,
- None,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
- if follow_state is True:
- followed += 1
- else:
- self.logger.info("--> Not following")
- sleep(1)
-
- if links is False:
- continue
-
- # Reset like counter for every username
- liked_img = 0
-
- for i, link in enumerate(links):
- # Check if target has reached
- if liked_img >= amount:
- self.logger.info("-------------")
- self.logger.info(
- "--> Total liked image reached it's "
- "amount given: {}".format(liked_img)
- )
- break
-
- if self.jumps["consequent"]["likes"] >= self.jumps["limit"]["likes"]:
- self.logger.warning(
- "--> Like quotient reached its peak!\t~leaving "
- "Like-By-Users activity\n"
- )
- self.quotient_breach = True
- # reset jump counter after a breach report
- self.jumps["consequent"]["likes"] = 0
- break
-
- self.logger.info("Post [{}/{}]".format(liked_img + 1, amount))
- self.logger.info(link)
-
- try:
- inappropriate, user_name, is_video, reason, scope = check_link(
- self.browser,
- link,
- self.dont_like,
- self.mandatory_words,
- self.mandatory_language,
- self.is_mandatory_character,
- self.mandatory_character,
- self.check_character_set,
- self.ignore_if_contains,
- self.logger,
- )
-
- if not inappropriate and self.delimit_liking:
- self.liking_approved = verify_liking(
- self.browser, self.max_likes, self.min_likes, self.logger
- )
-
- if not inappropriate and self.liking_approved:
- like_state, msg = like_image(
- self.browser,
- user_name,
- self.blacklist,
- self.logger,
- self.logfolder,
- total_liked_img,
- )
- if like_state is True or self.do_comment_liked_photo:
- if self.do_comment_liked_photo:
- already_liked += 1
- else:
- total_liked_img += 1
- liked_img += 1
- # reset jump counter after a successful like
- self.jumps["consequent"]["likes"] = 0
-
- checked_img = True
- temp_comments = []
-
- commenting = (
- random.randint(0, 100) <= self.comment_percentage
- )
-
- if self.use_clarifai and (following or commenting):
- try:
- (
- checked_img,
- temp_comments,
- clarifai_tags,
- ) = self.query_clarifai()
-
- except Exception as err:
- self.logger.error(
- "Image check error: {}".format(err)
- )
-
- # comments
- if (
- self.do_comment
- and user_name not in self.dont_include
- and checked_img
- and commenting
- ):
- comments = self.comments + (
- self.video_comments
- if is_video
- else self.photo_comments
- )
- success = process_comments(
- comments,
- temp_comments,
- self.delimit_commenting,
- self.max_comments,
- self.min_comments,
- self.comments_mandatory_words,
- self.username,
- user_name, # Comments with target user
- self.blacklist,
- self.browser,
- link,
- self.logger,
- self.logfolder,
- )
-
- if success:
- commented += 1
- else:
- self.logger.info("--> Not commented")
- sleep(1)
-
- elif msg == "already liked":
- already_liked += 1
-
- elif msg == "block on likes":
- break
-
- elif msg == "jumped":
- # will break the loop after certain consecutive
- # jumps
- self.jumps["consequent"]["likes"] += 1
-
- else:
- self.logger.info(
- "--> Image not liked: {}".format(reason.encode("utf-8"))
- )
- inap_img += 1
-
- except NoSuchElementException as err:
- self.logger.error("Invalid Page: {}".format(err))
-
- if liked_img < amount:
- self.logger.info("-------------")
- self.logger.info(
- "--> Given amount not fulfilled, image pool reached its end\n"
- )
-
- self.logger.info("User: {}".format(username.encode("utf-8")))
- self.logger.info("Liked: {}".format(total_liked_img))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Inappropriate: {}".format(inap_img))
- self.logger.info("Not valid users: {}\n".format(not_valid_users))
-
- self.liked_img += liked_img
- self.already_liked += already_liked
- self.commented += commented
- self.inap_img += inap_img
- self.not_valid_users += not_valid_users
-
- return self
-
- def interact_by_users(
- self,
- usernames: list,
- amount: int = 10,
- randomize: bool = False,
- media: str = None,
- ):
- """Likes some amounts of images for each usernames"""
- if self.aborting:
- return self
-
- message = "Starting to interact by users.."
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- if not isinstance(usernames, list):
- usernames = [usernames]
-
- # standalone means this feature is started by the user
- standalone = (
- True if "interact_by_users" not in self.internal_usage.keys() else False
- )
- # skip validation in case of it is already accomplished
- users_validated = (
- True
- if not standalone
- and not self.internal_usage["interact_by_users"]["validate"]
- else False
- )
-
- total_liked_img = 0
- already_liked = 0
- inap_img = 0
- commented = 0
- followed = 0
- already_followed = 0
- not_valid_users = 0
-
- self.quotient_breach = False
-
- for index, username in enumerate(usernames):
- if self.quotient_breach:
- # keep `quotient_breach` active to break the internal
- # iterators of the caller
- self.quotient_breach = True if not standalone else False
- break
-
- self.logger.info("Username [{}/{}]".format(index + 1, len(usernames)))
- self.logger.info("--> {}".format(username.encode("utf-8")))
-
- if not users_validated:
- validation, details = self.validate_user_call(username)
- if not validation:
- self.logger.info("--> not a valid user: {}".format(details))
- not_valid_users += 1
- continue
-
- track = "profile"
- # decision making
- # static conditions
- not_dont_include = username not in self.dont_include
- follow_restricted = follow_restriction(
- "read", username, self.follow_times, self.logger
- )
- counter = 0
- while True:
- following = (
- random.randint(0, 100) <= self.follow_percentage
- and self.do_follow
- and not_dont_include
- and not follow_restricted
- )
- commenting = (
- random.randint(0, 100) <= self.comment_percentage
- and self.do_comment
- and not_dont_include
- )
- liking = random.randint(0, 100) <= self.like_percentage
-
- story = (
- random.randint(0, 100) <= self.story_percentage and self.do_story
- )
-
- counter += 1
-
- # if we have only one image to like/comment
- if commenting and not liking and amount == 1:
- continue
-
- if following or commenting or liking or story:
- self.logger.info(
- "username actions: following={} commenting={} "
- "liking={} story={}".format(
- following, commenting, liking, story
- )
- )
- break
-
- # if for some reason we have no actions on this user
- if counter > 5:
- self.logger.info(
- "username={} could not get interacted".format(username)
- )
- break
-
- try:
- links = get_links_for_username(
- self.browser,
- self.username,
- username,
- amount,
- self.logger,
- self.logfolder,
- randomize,
- media,
- )
- except NoSuchElementException:
- self.logger.error("Element not found, skipping this username")
- continue
-
- if links is False:
- continue
-
- # Reset like counter for every username
- liked_img = 0
-
- for i, link in enumerate(links[:amount]):
- if self.jumps["consequent"]["likes"] >= self.jumps["limit"]["likes"]:
- self.logger.warning(
- "--> Like quotient reached its peak!\t~leaving "
- "Interact-By-Users activity\n"
- )
- self.quotient_breach = True
- # reset jump counter after a breach report
- self.jumps["consequent"]["likes"] = 0
- break
-
- # Check if target has reached
- if liked_img >= amount:
- self.logger.info("-------------")
- self.logger.info(
- "--> Total liked image reached it's "
- "amount given: {}".format(liked_img)
- )
- break
-
- self.logger.info("Post [{}/{}]".format(i + 1, len(links[:amount])))
- self.logger.info(link)
-
- try:
- inappropriate, user_name, is_video, reason, scope = check_link(
- self.browser,
- link,
- self.dont_like,
- self.mandatory_words,
- self.mandatory_language,
- self.is_mandatory_character,
- self.mandatory_character,
- self.check_character_set,
- self.ignore_if_contains,
- self.logger,
- )
- track = "post"
-
- if not inappropriate:
- # after first image we roll again
- if i > 0:
- liking = random.randint(0, 100) <= self.like_percentage
- commenting = (
- random.randint(0, 100) <= self.comment_percentage
- and self.do_comment
- and not_dont_include
- )
- story = (
- random.randint(0, 100) <= self.story_percentage
- and self.do_story
- )
-
- # like
- if self.do_like and liking and self.delimit_liking:
- self.liking_approved = verify_liking(
- self.browser,
- self.max_likes,
- self.min_likes,
- self.logger,
- )
-
- if self.do_like and liking and self.liking_approved:
- like_state, msg = like_image(
- self.browser,
- user_name,
- self.blacklist,
- self.logger,
- self.logfolder,
- total_liked_img,
- )
- if like_state is True or self.do_comment_liked_photo:
- if self.do_comment_liked_photo:
- already_liked += 1
- else:
- total_liked_img += 1
- liked_img += 1
- # reset jump counter after a successful like
- self.jumps["consequent"]["likes"] = 0
-
- # comment
- checked_img = True
- temp_comments = []
-
- if self.use_clarifai and commenting:
- try:
- (
- checked_img,
- temp_comments,
- clarifai_tags,
- ) = self.query_clarifai()
-
- except Exception as err:
- self.logger.error(
- "Image check error: {}".format(err)
- )
-
- if commenting and checked_img:
- comments = self.comments + (
- self.video_comments
- if is_video
- else self.photo_comments
- )
- success = process_comments(
- comments,
- temp_comments,
- self.delimit_commenting,
- self.max_comments,
- self.min_comments,
- self.comments_mandatory_words,
- self.username,
- user_name, # Comments with target user
- self.blacklist,
- self.browser,
- link,
- self.logger,
- self.logfolder,
- )
-
- if success:
- commented += 1
- else:
- self.logger.info("--> Not commented")
- sleep(1)
-
- elif msg == "already liked":
- already_liked += 1
-
- elif msg == "block on likes":
- break
-
- elif msg == "jumped":
- # will break the loop after certain
- # consecutive jumps
- self.jumps["consequent"]["likes"] += 1
-
- else:
- self.logger.info(
- "--> Image not liked: {}".format(reason.encode("utf-8"))
- )
- inap_img += 1
-
- except NoSuchElementException as err:
- self.logger.info("Invalid Page: {}".format(err))
-
- # follow
- if following and not (self.dont_follow_inap_post and inap_img > 0):
-
- follow_state, msg = follow_user(
- self.browser,
- track,
- self.username,
- username,
- None,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
-
- if follow_state is True:
- followed += 1
-
- elif msg == "already followed":
- already_followed += 1
-
- else:
- self.logger.info("--> Not following")
- sleep(1)
-
- # watch story if present
- if story:
- self.story_by_users([username])
-
- if liked_img < amount:
- self.logger.info("-------------")
- self.logger.info(
- "--> Given amount not fulfilled, image pool reached its end\n"
- )
-
- if len(usernames) > 1:
- # final words
- interacted_media_size = len(usernames) * amount - inap_img
- self.logger.info(
- "Finished interacting on total of {} images from {} users! xD\n".format(
- interacted_media_size, len(usernames)
- )
- )
-
- # print results
- self.logger.info("Liked: {}".format(total_liked_img))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Followed: {}".format(followed))
- self.logger.info("Already Followed: {}".format(already_followed))
- self.logger.info("Inappropriate: {}".format(inap_img))
- self.logger.info("Not valid users: {}\n".format(not_valid_users))
-
- self.liked_img += total_liked_img
- self.already_liked += already_liked
- self.commented += commented
- self.followed += followed
- self.already_followed += already_followed
- self.inap_img += inap_img
- self.not_valid_users += not_valid_users
-
- return self
-
- def interact_by_users_tagged_posts(
- self,
- usernames: list,
- amount: int = 10,
- randomize: bool = False,
- media: str = None,
- ):
- """Likes some amounts of tagged images for each usernames"""
- if self.aborting:
- return self
-
- if not isinstance(usernames, list):
- usernames = [usernames]
-
- # standalone means this feature is started by the user
- standalone = (
- True if "interact_by_users" not in self.internal_usage.keys() else False
- )
- # skip validation in case of it is already accomplished
- users_validated = (
- True
- if not standalone
- and not self.internal_usage["interact_by_users"]["validate"]
- else False
- )
-
- total_liked_img = 0
- already_liked = 0
- inap_img = 0
- commented = 0
- followed = 0
- already_followed = 0
- not_valid_users = 0
-
- self.quotient_breach = False
-
- for index, username in enumerate(usernames):
- if self.quotient_breach:
- # keep `quotient_breach` active to break the internal
- # iterators of the caller
- self.quotient_breach = True if not standalone else False
- break
-
- self.logger.info("Username [{}/{}]".format(index + 1, len(usernames)))
- self.logger.info("--> {}".format(username.encode("utf-8")))
-
- if not users_validated and username != self.username:
- validation, details = self.validate_user_call(username)
- if not validation:
- self.logger.info("--> not a valid user: {}".format(details))
- not_valid_users += 1
- continue
-
- # decision making
- # static conditions
- not_dont_include = username not in self.dont_include
- follow_restricted = follow_restriction(
- "read", username, self.follow_times, self.logger
- )
- counter = 0
- while True:
- following = (
- random.randint(0, 100) <= self.follow_percentage
- and self.do_follow
- and not_dont_include
- and not follow_restricted
- )
- commenting = (
- random.randint(0, 100) <= self.comment_percentage
- and self.do_comment
- and not_dont_include
- )
- liking = random.randint(0, 100) <= self.like_percentage
-
- counter += 1
-
- # if we have only one image to like/comment
- if commenting and not liking and amount == 1:
- continue
- if following or commenting or liking:
- self.logger.info(
- "username actions: following={} commenting={} "
- "liking={}".format(following, commenting, liking)
- )
- break
- # if for some reason we have no actions on this user
- if counter > 5:
- self.logger.info(
- "username={} could not get interacted".format(username)
- )
- break
-
- try:
- links = get_links_for_username(
- self.browser,
- self.username,
- username,
- amount,
- self.logger,
- self.logfolder,
- randomize,
- media,
- taggedImages=True,
- )
- except NoSuchElementException:
- self.logger.error("Element not found, skipping this username")
- continue
-
- if links is False:
- continue
-
- # Reset like counter for every username
- liked_img = 0
-
- for i, link in enumerate(links[:amount]):
- if self.jumps["consequent"]["likes"] >= self.jumps["limit"]["likes"]:
- self.logger.warning(
- "--> Like quotient reached its peak!\t~leaving "
- "Interact-By-Users activity\n"
- )
- self.quotient_breach = True
- # reset jump counter after a breach report
- self.jumps["consequent"]["likes"] = 0
- break
-
- # Check if target has reached
- if liked_img >= amount:
- self.logger.info("-------------")
- self.logger.info(
- "--> Total liked image reached it's "
- "amount given: {}".format(liked_img)
- )
- break
-
- self.logger.info(
- "Post [{}/{}]".format(liked_img + 1, len(links[:amount]))
- )
- self.logger.info(link)
-
- try:
- inappropriate, user_name, is_video, reason, scope = check_link(
- self.browser,
- link,
- self.dont_like,
- self.mandatory_words,
- self.mandatory_language,
- self.is_mandatory_character,
- self.mandatory_character,
- self.check_character_set,
- self.ignore_if_contains,
- self.logger,
- )
-
- if not inappropriate:
- # after first image we roll again
- if i > 0:
- liking = random.randint(0, 100) <= self.like_percentage
- commenting = (
- random.randint(0, 100) <= self.comment_percentage
- and self.do_comment
- and not_dont_include
- )
-
- # like
- if self.do_like and liking and self.delimit_liking:
- self.liking_approved = verify_liking(
- self.browser,
- self.max_likes,
- self.min_likes,
- self.logger,
- )
-
- if self.do_like and liking and self.liking_approved:
- like_state, msg = like_image(
- self.browser,
- user_name,
- self.blacklist,
- self.logger,
- self.logfolder,
- total_liked_img,
- )
- if like_state is True or self.do_comment_liked_photo:
- if self.do_comment_liked_photo:
- already_liked += 1
- else:
- total_liked_img += 1
- liked_img += 1
- # reset jump counter after a successful like
- self.jumps["consequent"]["likes"] = 0
-
- # comment
- checked_img = True
- temp_comments = []
-
- if self.use_clarifai and commenting:
- try:
- (
- checked_img,
- temp_comments,
- clarifai_tags,
- ) = self.query_clarifai()
-
- except Exception as err:
- self.logger.error(
- "Image check error: {}".format(err)
- )
-
- if commenting and checked_img:
- comments = self.comments + (
- self.video_comments
- if is_video
- else self.photo_comments
- )
- success = process_comments(
- comments,
- temp_comments,
- self.delimit_commenting,
- self.max_comments,
- self.min_comments,
- self.comments_mandatory_words,
- self.username,
- user_name, # Comments with target user
- self.blacklist,
- self.browser,
- link,
- self.logger,
- self.logfolder,
- )
-
- if success:
- commented += 1
- else:
- self.logger.info("--> Not commented")
- sleep(1)
-
- elif msg == "already liked":
- already_liked += 1
-
- elif msg == "block on likes":
- break
-
- elif msg == "jumped":
- # will break the loop after certain
- # consecutive jumps
- self.jumps["consequent"]["likes"] += 1
-
- else:
- self.logger.info(
- "--> Image not liked: {}".format(reason.encode("utf-8"))
- )
- inap_img += 1
-
- except NoSuchElementException as err:
- self.logger.info("Invalid Page: {}".format(err))
-
- # follow
- if following and not (self.dont_follow_inap_post and inap_img > 0):
-
- follow_state, msg = follow_user(
- self.browser,
- "profile",
- self.username,
- username,
- None,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
- if follow_state is True:
- followed += 1
-
- elif msg == "already followed":
- already_followed += 1
-
- else:
- self.logger.info("--> Not following")
- sleep(1)
-
- if liked_img < amount:
- self.logger.info("-------------")
- self.logger.info(
- "--> Given amount not fulfilled, image pool reached its end\n"
- )
-
- # final words
- interacted_media_size = len(usernames) * amount - inap_img
- self.logger.info(
- "Finished interacting on total of {} images from {} users! xD\n".format(
- interacted_media_size, len(usernames)
- )
- )
-
- # print results
- self.logger.info("Liked: {}".format(total_liked_img))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Followed: {}".format(followed))
- self.logger.info("Already Followed: {}".format(already_followed))
- self.logger.info("Inappropriate: {}".format(inap_img))
- self.logger.info("Not valid users: {}\n".format(not_valid_users))
-
- self.liked_img += total_liked_img
- self.already_liked += already_liked
- self.commented += commented
- self.followed += followed
- self.already_followed += already_followed
- self.inap_img += inap_img
- self.not_valid_users += not_valid_users
-
- return self
-
- def like_from_image(self, url: str, amount: int = 50, media: str = None):
- """Gets the tags from an image and likes 50 images for each tag"""
- if self.aborting:
- return self
-
- try:
- if not url:
- urls = self.browser.find_elements(
- By.XPATH, read_xpath(self.__class__.__name__, "main_article")
- )
- url = urls[0].get_attribute("href")
- self.logger.info("new url {}".format(url))
- tags = get_tags(self.browser, url)
- self.logger.info(tags)
- self.like_by_tags(tags, amount, media)
- except TypeError as err:
- self.logger.error("Sorry, an error occurred: {}".format(err))
- self.aborting = True
- return self
-
- return self
-
- def interact_user_followers(
- self, usernames: list, amount: int = 10, randomize: bool = False
- ):
- """
- Interact with the people that a given user is followed by.
-
- set_do_comment, set_do_follow and set_do_like are applicable.
-
- :param usernames: List of users to interact with their followers.
- :param amount: Amount of followers to interact with.
- :param randomize: If followers should be chosen randomly.
- """
-
- if self.aborting:
- return self
-
- if self.do_follow is not True and self.do_like is not True:
- self.logger.info(
- "Please enable following or liking in settings in order to "
- "do interactions."
- )
- return self
-
- elif self.user_interact_amount <= 0:
- self.logger.info(
- "Please choose an amount higher than zero in "
- "`set_user_interact` in order to do interactions."
- )
- return self
-
- if not isinstance(usernames, list):
- usernames = [usernames]
-
- interacted_all = 0
- not_valid_users = 0
- simulated_unfollow = 0
-
- # hold the current global values for differentiating at the end
- liked_init = self.liked_img
- already_liked_init = self.already_liked
- commented_init = self.commented
- followed_init = self.followed
- inap_img_init = self.inap_img
-
- self.quotient_breach = False
-
- for index, user in enumerate(usernames):
- if self.quotient_breach:
- break
-
- self.logger.info(
- "User '{}' [{}/{}]".format((user), index + 1, len(usernames))
- )
- try:
- person_list, simulated_list = get_given_user_followers(
- self.browser,
- self.username,
- user,
- amount,
- self.dont_include,
- randomize,
- self.blacklist,
- self.follow_times,
- self.simulation,
- self.jumps,
- self.logger,
- self.logfolder,
- )
-
- except (TypeError, RuntimeWarning) as err:
- if isinstance(err, RuntimeWarning):
- self.logger.warning(
- "Warning: {} , skipping to next user".format(err)
- )
- continue
-
- else:
- self.logger.error("Sorry, an error occurred: {}".format(err))
- self.aborting = True
- return self
-
- print("")
- self.logger.info(
- "Grabbed {} usernames from '{}'s `Followers` to do "
- "interaction.".format(len(person_list), user)
- )
-
- interacted_personal = 0
-
- for index, person in enumerate(person_list):
- if self.quotient_breach:
- self.logger.warning(
- "--> Like quotient reached its peak!"
- "\t~leaving Interact-User-Followers activity\n"
- )
- break
-
- self.logger.info(
- "User '{}' [{}/{}]".format((person), index + 1, len(person_list))
- )
-
- validation, details = self.validate_user_call(person)
- if not validation:
- self.logger.info(details)
- not_valid_users += 1
-
- if person in simulated_list:
- self.logger.warning(
- "--> Simulated Unfollow {}:"
- " unfollowing '{}' due to mismatching "
- "validation...".format(simulated_unfollow + 1, person)
- )
- unfollow_state, msg = unfollow_user(
- self.browser,
- "profile",
- self.username,
- person,
- None,
- None,
- self.relationship_data,
- self.logger,
- self.logfolder,
- )
- if unfollow_state:
- simulated_unfollow += 1
-
- continue
-
- # Do interactions if any
- do_interact = random.randint(0, 100) <= self.user_interact_percentage
-
- if not do_interact:
- self.logger.info(
- "Skipping user '{}' due to the interaction "
- "percentage of {}".format(person, self.user_interact_percentage)
- )
- continue
-
- else:
- interacted_all += 1
- interacted_personal += 1
-
- self.logger.info(
- "Interaction [{}/{}] | Total Interaction: {}".format(
- interacted_personal, len(person_list), interacted_all
- )
- )
-
- with self.feature_in_feature("interact_by_users", False):
- self.interact_by_users(
- person,
- self.user_interact_amount,
- self.user_interact_random,
- self.user_interact_media,
- )
- if self.aborting:
- return self
- sleep(1)
-
- # final words
- self.logger.info(
- "Finished interacting {} people from {} users' `Followers`! xD\n".format(
- interacted_all, len(usernames)
- )
- )
-
- # find the feature-wide action sizes by taking a difference
- liked = self.liked_img - liked_init
- already_liked = self.already_liked - already_liked_init
- commented = self.commented - commented_init
- followed = self.followed - followed_init
- inap_img = self.inap_img - inap_img_init
-
- # print results
- self.logger.info("Liked: {}".format(liked))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Followed: {}".format(followed))
- self.logger.info("Inappropriate: {}".format(inap_img))
- self.logger.info("Not valid users: {}\n".format(not_valid_users))
-
- self.not_valid_users += not_valid_users
-
- return self
-
- def interact_user_likers(
- self,
- usernames: list,
- posts_grab_amount: int = 3,
- interact_likers_per_post: int = 3,
- randomize: bool = False,
- ):
- """
- Interact with the likers of given user's posts.
-
- set_do_comment, set_do_follow and set_do_like are applicable.
-
- :param usernames: List of users with whose likers to interact.
- :param posts_grab_amount: Amount of posts to get the likers from per given user.
- :param interact_likers_per_post: Amount of likers to be interacted with per post.
- :param randomize: If followers should be chosen randomly.
- """
-
- if self.aborting:
- return self
-
- if self.do_follow is not True and self.do_like is not True:
- self.logger.info(
- "Please enable following or liking in settings in order to "
- "do interactions."
- )
- return self
-
- elif self.user_interact_amount <= 0:
- self.logger.info(
- "Please choose an amount higher than zero in "
- "`set_user_interact` in order to do interactions."
- )
- return self
-
- if not isinstance(usernames, list):
- usernames = [usernames]
-
- if posts_grab_amount > 12:
- self.logger.info(
- "Sorry, you can only grab likers from first 12 posts for "
- "given username now.\n"
- )
- posts_grab_amount = 12
-
- interacted_all = 0
- not_valid_users = 0
- simulated_unfollow = 0
-
- # hold the current global values for differentiating at the end
- liked_init = self.liked_img
- already_liked_init = self.already_liked
- commented_init = self.commented
- followed_init = self.followed
- inap_img_init = self.inap_img
-
- self.quotient_breach = False
-
- for index, username in enumerate(usernames):
- if self.quotient_breach:
- break
-
- self.logger.info(
- "User '{}' [{}/{}]".format((username), index + 1, len(usernames))
- )
- try:
- post_urls = get_photo_urls_from_profile(
- self.browser, username, posts_grab_amount, randomize, self.logger
- )
-
- if not isinstance(post_urls, list):
- post_urls = [post_urls]
-
- except (TypeError, RuntimeWarning) as err:
- if isinstance(err, RuntimeWarning):
- self.logger.warning(
- "Warning: {} , skipping to next user".format(err)
- )
- continue
-
- else:
- self.logger.error("Sorry, an error occurred: {}".format(err))
- self.aborting = True
- return self
-
- print("")
- self.logger.info(
- "Grabbed {} posts from '{}'s profile to do "
- "interaction.".format(len(post_urls), username)
- )
-
- interacted_personal = 0
-
- for post_index, post_url in enumerate(post_urls):
- if self.quotient_breach:
- break
-
- likers = users_liked(
- self.browser, post_url, interact_likers_per_post, self.logger
- )
- # This way of iterating will prevent sleep interference
- # between functions
- random.shuffle(likers)
-
- self.logger.info(
- "Post '{}' [{}/{}]".format(
- (post_url), post_index + 1, len(post_urls)
- )
- )
-
- for liker_index, person in enumerate(likers):
- if self.quotient_breach:
- self.logger.warning(
- "--> Like quotient reached its peak!"
- "\t~leaving Interact-Likers activity\n"
- )
- break
-
- self.logger.info(
- "Liker '{}' [{}/{}]".format(
- (person), liker_index + 1, len(likers)
- )
- )
-
- validation, details = self.validate_user_call(person)
- if not validation:
- self.logger.info(details)
- not_valid_users += 1
-
- continue
-
- # Do interactions if any
- do_interact = (
- random.randint(0, 100) <= self.user_interact_percentage
- )
-
- if not do_interact:
- self.logger.info(
- "Skipping user '{}' due to the interaction "
- "percentage of {}".format(
- person, self.user_interact_percentage
- )
- )
- continue
-
- else:
- interacted_all += 1
- interacted_personal += 1
-
- self.logger.info(
- "Interaction [{}/{}] | Total Interaction: {}".format(
- interacted_personal, len(likers), interacted_all
- )
- )
-
- with self.feature_in_feature("interact_by_users", False):
- self.interact_by_users(
- person,
- self.user_interact_amount,
- self.user_interact_random,
- self.user_interact_media,
- )
- if self.aborting:
- return self
- sleep(1)
-
- # final words
- self.logger.info(
- "Finished interacting {} people from {} users' `Followers`! xD\n".format(
- interacted_all, len(usernames)
- )
- )
-
- # find the feature-wide action sizes by taking a difference
- liked = self.liked_img - liked_init
- already_liked = self.already_liked - already_liked_init
- commented = self.commented - commented_init
- followed = self.followed - followed_init
- inap_img = self.inap_img - inap_img_init
-
- # print results
- self.logger.info("Liked: {}".format(liked))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Followed: {}".format(followed))
- self.logger.info("Inappropriate: {}".format(inap_img))
- self.logger.info("Not valid users: {}\n".format(not_valid_users))
-
- self.not_valid_users += not_valid_users
-
- return self
-
- def interact_user_following(
- self, usernames: list, amount: int = 10, randomize: bool = False
- ):
-
- if self.aborting:
- return self
-
- if self.do_follow is not True and self.do_like is not True:
- self.logger.info(
- "Please enable following or liking in settings"
- " in order to do interactions."
- )
- return self
-
- elif self.user_interact_amount <= 0:
- self.logger.info(
- "Please choose an amount higher than zero in"
- " `set_user_interact` in order to do interactions."
- )
- return self
-
- if not isinstance(usernames, list):
- usernames = [usernames]
-
- interacted_all = 0
- not_valid_users = 0
- simulated_unfollow = 0
-
- # hold the current global values for differentiating at the end
- liked_init = self.liked_img
- already_liked_init = self.already_liked
- commented_init = self.commented
- followed_init = self.followed
- inap_img_init = self.inap_img
-
- self.quotient_breach = False
-
- for index, user in enumerate(usernames):
- if self.quotient_breach:
- break
-
- self.logger.info(
- "User '{}' [{}/{}]".format((user), index + 1, len(usernames))
- )
- try:
- person_list, simulated_list = get_given_user_following(
- self.browser,
- self.username,
- user,
- amount,
- self.dont_include,
- randomize,
- self.blacklist,
- self.follow_times,
- self.simulation,
- self.jumps,
- self.logger,
- self.logfolder,
- )
-
- except (TypeError, RuntimeWarning) as err:
- if isinstance(err, RuntimeWarning):
- self.logger.warning(
- "Warning: {} , skipping to next user".format(err)
- )
- continue
-
- else:
- self.logger.error("Sorry, an error occurred: {}".format(err))
- self.aborting = True
- return self
-
- print("")
- self.logger.info(
- "Grabbed {} usernames from '{}'s `Following` to do "
- "interaction.".format(len(person_list), user)
- )
- interacted_personal = 0
-
- for index, person in enumerate(person_list):
- if self.quotient_breach:
- self.logger.warning(
- "--> Like quotient reached its peak!"
- "\t~leaving Interact-User-Following activity\n"
- )
- break
-
- self.logger.info(
- "User '{}' [{}/{}]".format((person), index + 1, len(person_list))
- )
-
- validation, details = self.validate_user_call(person)
- if validation is not True:
- self.logger.info(details)
- not_valid_users += 1
-
- if person in simulated_list:
- self.logger.warning(
- "--> Simulated Unfollow {}:"
- " unfollowing '{}' due to mismatching "
- "validation...".format(simulated_unfollow + 1, person)
- )
-
- unfollow_state, msg = unfollow_user(
- self.browser,
- "profile",
- self.username,
- person,
- None,
- None,
- self.relationship_data,
- self.logger,
- self.logfolder,
- )
- if unfollow_state is True:
- simulated_unfollow += 1
-
- continue
-
- # Do interactions if any
- do_interact = random.randint(0, 100) <= self.user_interact_percentage
-
- if do_interact is False:
- self.logger.info(
- "Skipping user '{}' due to"
- " the interaction percentage of {}".format(
- person, self.user_interact_percentage
- )
- )
- continue
-
- else:
- interacted_all += 1
- interacted_personal += 1
-
- self.logger.info(
- "Interaction [{}/{}] | Total Interaction: {}".format(
- interacted_personal, len(person_list), interacted_all
- )
- )
-
- with self.feature_in_feature("interact_by_users", False):
- self.interact_by_users(
- person,
- self.user_interact_amount,
- self.user_interact_random,
- self.user_interact_media,
- )
- if self.aborting:
- return self
- sleep(1)
-
- # final words
- self.logger.info(
- "Finished interacting {} people"
- " from {} users' `Following`! xD\n".format(interacted_all, len(usernames))
- )
-
- # find the feature-wide action sizes by taking a difference
- liked = self.liked_img - liked_init
- already_liked = self.already_liked - already_liked_init
- commented = self.commented - commented_init
- followed = self.followed - followed_init
- inap_img = self.inap_img - inap_img_init
-
- # print results
- self.logger.info("Liked: {}".format(liked))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Followed: {}".format(followed))
- self.logger.info("Inappropriate: {}".format(inap_img))
- self.logger.info("Not valid users: {}\n".format(not_valid_users))
-
- self.not_valid_users += not_valid_users
-
- return self
-
- def follow_user_followers(
- self,
- usernames: list,
- amount: int = 10,
- randomize: bool = False,
- interact: bool = False,
- sleep_delay: int = 600,
- ):
- """Follow the `Followers` of given users"""
- if self.aborting:
- return self
-
- message = "Starting to follow user `Followers`.."
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- if not isinstance(usernames, list):
- usernames = [usernames]
-
- followed_all = 0
- followed_new = 0
- not_valid_users = 0
-
- # below, you can use some static value `10` instead of random ones..
- relax_point = random.randint(7, 14)
-
- # hold the current global values for differentiating at the end
- already_followed_init = self.already_followed
- liked_init = self.liked_img
- already_liked_init = self.already_liked
- commented_init = self.commented
- inap_img_init = self.inap_img
-
- self.quotient_breach = False
-
- for index, user in enumerate(usernames):
- if self.quotient_breach:
- break
-
- self.logger.info(
- "User '{}' [{}/{}]".format((user), index + 1, len(usernames))
- )
-
- try:
- person_list, simulated_list = get_given_user_followers(
- self.browser,
- self.username,
- user,
- amount,
- self.dont_include,
- randomize,
- self.blacklist,
- self.follow_times,
- self.simulation,
- self.jumps,
- self.logger,
- self.logfolder,
- )
-
- except (TypeError, RuntimeWarning) as err:
- if isinstance(err, RuntimeWarning):
- self.logger.warning(
- "Warning: {} , skipping to next user".format(err)
- )
- continue
-
- else:
- self.logger.error("Sorry, an error occurred: {}".format(err))
- self.aborting = True
- return self
-
- print("")
- self.logger.info(
- "Grabbed {} usernames from '{}'s `Followers` to do following\n".format(
- len(person_list), user
- )
- )
-
- followed_personal = 0
- simulated_unfollow = 0
-
- for index, person in enumerate(person_list):
- if self.quotient_breach:
- self.logger.warning(
- "--> Follow quotient reached its peak!"
- "\t~leaving Follow-User-Followers activity\n"
- )
- break
-
- self.logger.info(
- "Ongoing Follow [{}/{}]: now following '{}'...".format(
- index + 1, len(person_list), person
- )
- )
-
- validation, details = self.validate_user_call(person)
- if validation is not True:
- self.logger.info(details)
- not_valid_users += 1
-
- if person in simulated_list:
- self.logger.warning(
- "--> Simulated Unfollow {}: unfollowing"
- " '{}' due to mismatching validation...\n".format(
- simulated_unfollow + 1, person
- )
- )
-
- unfollow_state, msg = unfollow_user(
- self.browser,
- "profile",
- self.username,
- person,
- None,
- None,
- self.relationship_data,
- self.logger,
- self.logfolder,
- )
- if unfollow_state is True:
- simulated_unfollow += 1
- # skip this [non-validated] user
- continue
-
- # go ahead and follow, then interact (if any)
- with self.feature_in_feature("follow_by_list", False):
- followed = self.follow_by_list(
- person, self.follow_times, sleep_delay, interact
- )
- sleep(1)
-
- if followed > 0:
- followed_all += 1
- followed_new += 1
- followed_personal += 1
-
- self.logger.info(
- "Follow per user: {} | Total Follow: {}\n".format(
- followed_personal, followed_all
- )
- )
-
- # take a break after a good following
- if followed_new >= relax_point:
- delay_random = random.randint(
- ceil(sleep_delay * 0.85), ceil(sleep_delay * 1.14)
- )
- sleep_time = (
- "{} seconds".format(delay_random)
- if delay_random < 60
- else "{} minutes".format(truncate_float(delay_random / 60, 2))
- )
- self.logger.info(
- "------=> Followed {} new users ~sleeping about {}\n".format(
- followed_new, sleep_time
- )
- )
- sleep(delay_random)
- relax_point = random.randint(7, 14)
- followed_new = 0
-
- # final words
- self.logger.info(
- "Finished following {} users' `Followers`! xD\n".format(len(usernames))
- )
- # find the feature-wide action sizes by taking a difference
- already_followed = self.already_followed - already_followed_init
- inap_img = self.inap_img - inap_img_init
- liked = self.liked_img - liked_init
- already_liked = self.already_liked - already_liked_init
- commented = self.commented - commented_init
-
- # print results
- self.logger.info("Followed: {}".format(followed_all))
- self.logger.info("Already followed: {}".format(already_followed))
- self.logger.info("Not valid users: {}".format(not_valid_users))
-
- if interact is True:
- print("")
- # print results out of interactions
- self.logger.info("Liked: {}".format(liked))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Inappropriate: {}".format(inap_img))
-
- self.not_valid_users += not_valid_users
-
- return self
-
- def follow_user_following(
- self,
- usernames: list,
- amount: int = 10,
- randomize: bool = False,
- interact: bool = False,
- sleep_delay: int = 600,
- ):
- """Follow the `Following` of given users"""
- if self.aborting:
- return self
-
- message = "Starting to follow user `Following`.."
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- if not isinstance(usernames, list):
- usernames = [usernames]
-
- followed_all = 0
- followed_new = 0
- not_valid_users = 0
-
- # hold the current global values for differentiating at the end
- already_followed_init = self.already_followed
- liked_init = self.liked_img
- already_liked_init = self.already_liked
- commented_init = self.commented
- inap_img_init = self.inap_img
-
- # below, can use a static value instead of from random range..
- relax_point = random.randint(7, 14)
- self.quotient_breach = False
-
- for index, user in enumerate(usernames):
- if self.quotient_breach:
- break
-
- self.logger.info(
- "User '{}' [{}/{}]".format((user), index + 1, len(usernames))
- )
- try:
- person_list, simulated_list = get_given_user_following(
- self.browser,
- self.username,
- user,
- amount,
- self.dont_include,
- randomize,
- self.blacklist,
- self.follow_times,
- self.simulation,
- self.jumps,
- self.logger,
- self.logfolder,
- )
-
- except (TypeError, RuntimeWarning) as err:
- if isinstance(err, RuntimeWarning):
- self.logger.warning(
- "Warning: {} , skipping to next user".format(err)
- )
- continue
-
- else:
- self.logger.error("Sorry, an error occurred: {}".format(err))
- self.aborting = True
- return self
-
- print("")
- self.logger.info(
- "Grabbed {} usernames from '{}'s `Following` to do following\n".format(
- len(person_list), user
- )
- )
-
- followed_personal = 0
- simulated_unfollow = 0
-
- for index, person in enumerate(person_list):
- if self.quotient_breach:
- self.logger.warning(
- "--> Follow quotient reached its peak!"
- "\t~leaving Follow-User-Following activity\n"
- )
- break
-
- self.logger.info(
- "Ongoing Follow [{}/{}]: now following '{}'...".format(
- index + 1, len(person_list), person
- )
- )
-
- validation, details = self.validate_user_call(person)
- if validation is not True:
- self.logger.info(details)
- not_valid_users += 1
-
- if person in simulated_list:
- self.logger.warning(
- "--> Simulated Unfollow {}:"
- " unfollowing '{}' due to mismatching "
- "validation...\n".format(simulated_unfollow + 1, person)
- )
-
- unfollow_state, msg = unfollow_user(
- self.browser,
- "profile",
- self.username,
- person,
- None,
- None,
- self.relationship_data,
- self.logger,
- self.logfolder,
- )
- if unfollow_state is True:
- simulated_unfollow += 1
- # skip the [non-validated] user
- continue
-
- # go ahead and follow, then interact (if any)
- with self.feature_in_feature("follow_by_list", False):
- followed = self.follow_by_list(
- person, self.follow_times, sleep_delay, interact
- )
- sleep(1)
-
- if followed > 0:
- followed_all += 1
- followed_new += 1
- followed_personal += 1
-
- self.logger.info(
- "Follow per user: {} | Total Follow: {}\n".format(
- followed_personal, followed_all
- )
- )
-
- # take a break after a good following
- if followed_new >= relax_point:
- delay_random = random.randint(
- ceil(sleep_delay * 0.85), ceil(sleep_delay * 1.14)
- )
- sleep_time = (
- "{} seconds".format(delay_random)
- if delay_random < 60
- else "{} minutes".format(truncate_float(delay_random / 60, 2))
- )
- self.logger.info(
- "------=> Followed {} new users ~sleeping about {}\n".format(
- followed_new, sleep_time
- )
- )
- sleep(delay_random)
- relax_point = random.randint(7, 14)
- followed_new = 0
-
- # final words
- self.logger.info(
- "Finished following {} users' `Following`! xD\n".format(len(usernames))
- )
-
- # find the feature-wide action sizes by taking a difference
- already_followed = self.already_followed - already_followed_init
- inap_img = self.inap_img - inap_img_init
- liked = self.liked_img - liked_init
- already_liked = self.already_liked - already_liked_init
- commented = self.commented - commented_init
-
- # print results
- self.logger.info("Followed: {}".format(followed_all))
- self.logger.info("Already followed: {}".format(already_followed))
- self.logger.info("Not valid users: {}".format(not_valid_users))
-
- if interact is True:
- print("")
- # print results out of interactions
- self.logger.info("Liked: {}".format(liked))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Inappropriate: {}".format(inap_img))
-
- self.not_valid_users += not_valid_users
-
- return self
-
- def unfollow_users(
- self,
- amount: int = 10,
- custom_list_enabled: bool = False,
- custom_list: list = [],
- custom_list_param: str = "all",
- instapy_followed_enabled: bool = False,
- instapy_followed_param: str = "all",
- nonFollowers: bool = False,
- allFollowing: bool = False,
- style: str = "FIFO",
- unfollow_after: int = None,
- delay_followbackers: int = 0, # 864000 = 10 days, 0 = don't delay
- sleep_delay: int = 600,
- ):
- """Unfollows (default) 10 users from your following list"""
-
- if self.aborting:
- return self
-
- message = "Starting to unfollow users.."
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- if unfollow_after is not None:
- if not python_version().startswith(("2.7", "3")):
- self.logger.warning(
- "`unfollow_after` parameter is not"
- " available for Python versions below 2.7"
- )
- unfollow_after = None
-
- self.automatedFollowedPool = set_automated_followed_pool(
- self.username,
- unfollow_after,
- self.logger,
- self.logfolder,
- delay_followbackers,
- )
-
- try:
- unfollowed = unfollow(
- self.browser,
- self.username,
- amount,
- (custom_list_enabled, custom_list, custom_list_param),
- (instapy_followed_enabled, instapy_followed_param),
- nonFollowers,
- allFollowing,
- style,
- self.automatedFollowedPool,
- self.relationship_data,
- self.dont_include,
- self.white_list,
- sleep_delay,
- self.jumps,
- delay_followbackers,
- self.logger,
- self.logfolder,
- )
- self.logger.info("--> Total people unfollowed : {}\n".format(unfollowed))
- self.unfollowed += unfollowed
-
- except Exception as exc:
- if isinstance(exc, RuntimeWarning):
- self.logger.warning("Warning: {} , stopping unfollow_users".format(exc))
- return self
-
- else:
- self.logger.error("Sorry, an error occurred: {}".format(exc))
- self.aborting = True
- return self
-
- return self
-
- def remove_follow_requests(self, amount: int = 200, sleep_delay: int = 600):
- """Remove user unaccepted follow requests"""
-
- if self.aborting:
- return self
-
- message = "Starting to get follow requests.."
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- follow_requests = get_follow_requests(
- self.browser, amount, sleep_delay, self.logger, self.logfolder
- )
-
- unfollow_count = 0
-
- for person in follow_requests:
- self.logger.warning(
- "--> Unfollow {}/{}:"
- " Removing request for: '{}' ".format(
- unfollow_count + 1, len(follow_requests), person
- )
- )
-
- unfollow_state, msg = unfollow_user(
- self.browser,
- "profile",
- self.username,
- person,
- None,
- None,
- self.relationship_data,
- self.logger,
- self.logfolder,
- )
-
- if unfollow_state is True:
- unfollow_count += 1
- self.unfollowed += 1
-
- return self
-
- def like_by_feed(self, amount, randomize, unfollow, interact):
- """
- Like the users feed
-
- :param amount: Specifies how many total likes you want to perform
- :param randomize: randomly skips posts to be liked on your feed
- :param unfollow: unfollows the author of a post which was considered inappropriate
- :param interact: visits the author's profile page of a
- """
-
- if self.aborting:
- return self
-
- for _ in self.like_by_feed_generator(amount, randomize, unfollow, interact):
- pass
-
- return self
-
- def like_by_feed_generator(
- self,
- amount: int = 50,
- randomize: bool = False,
- unfollow: bool = False,
- interact: bool = False,
- ):
- """
- Like the users feed
-
- :param amount: Specifies how many total likes you want to perform
- :param randomize: randomly skips posts to be liked on your feed
- :param unfollow: unfollows the author of a post which was considered inappropriate
- :param interact: visits the author's profile page of a
- """
-
- if self.aborting:
- return
-
- liked_img = 0
- already_liked = 0
- inap_img = 0
- inap_unfollow = 0
- commented = 0
- followed = 0
- skipped_img = 0
- num_of_search = 0
- not_valid_users = 0
- link_not_found_loop_error = 0
-
- history = []
- self.quotient_breach = False
-
- while liked_img < amount:
- if self.quotient_breach:
- break
-
- try:
- # Gets another load of links to be tested
- links = get_links_from_feed(
- self.browser, amount, num_of_search, self.logger
- )
-
- if len(links) > 0:
- link_not_found_loop_error = 0
-
- if len(links) == 0:
- link_not_found_loop_error += 1
- if link_not_found_loop_error >= 10:
- self.logger.warning(
- "Loop error, 0 links"
- " for 10 times consecutively, exit loop"
- )
- break
-
- except NoSuchElementException:
- self.logger.warning("Too few images, aborting")
- self.aborting = True
- return
-
- num_of_search += 1
-
- for _, link in enumerate(links):
- if liked_img == amount:
- break
-
- if self.jumps["consequent"]["likes"] >= self.jumps["limit"]["likes"]:
- self.logger.warning(
- "--> Like quotient reached its peak!"
- "\t~leaving Like-By-Feed activity\n"
- )
- self.quotient_breach = True
- # reset jump counter after a breach report
- self.jumps["consequent"]["likes"] = 0
- break
-
- if randomize and random.choice([True, False]):
- # Just inform that this post is randomly skipped
- self.logger.info("Post randomly skipped...")
- skipped_img += 1
- continue
- else:
- if link in history:
- self.logger.info(
- "This link has already been visited: {}".format(link)
- )
- continue
- else:
- self.logger.info("New link found...")
- history.append(link)
- self.logger.info(
- "[{} posts liked /{} amount]".format(liked_img, amount)
- )
- self.logger.info(link)
-
- try:
- (
- inappropriate,
- user_name,
- is_video,
- reason,
- scope,
- ) = check_link(
- self.browser,
- link,
- self.dont_like,
- self.mandatory_words,
- self.mandatory_language,
- self.is_mandatory_character,
- self.mandatory_character,
- self.check_character_set,
- self.ignore_if_contains,
- self.logger,
- )
-
- if not inappropriate and self.delimit_liking:
- self.liking_approved = verify_liking(
- self.browser,
- self.max_likes,
- self.min_likes,
- self.logger,
- )
- if not inappropriate and self.liking_approved:
- # validate user
- validation, details = self.validate_user_call(user_name)
- if validation is not True:
- self.logger.info(details)
- not_valid_users += 1
- continue
- else:
- web_address_navigator(self.browser, link)
-
- # try to like
- like_state, msg = like_image(
- self.browser,
- user_name,
- self.blacklist,
- self.logger,
- self.logfolder,
- liked_img,
- )
-
- if like_state is True or self.do_comment_liked_photo:
- if self.do_comment_liked_photo:
- already_liked += 1
- else:
- liked_img += 1
- # reset jump counter after a successful like
- self.jumps["consequent"]["likes"] = 0
-
- checked_img = True
- temp_comments = []
-
- commenting = (
- random.randint(0, 100)
- <= self.comment_percentage
- )
- following = (
- random.randint(0, 100) <= self.follow_percentage
- )
-
- if self.use_clarifai and (following or commenting):
- try:
- (
- checked_img,
- temp_comments,
- clarifai_tags,
- ) = self.query_clarifai()
-
- except Exception as err:
- self.logger.error(
- "Image check error: {}".format(err)
- )
-
- # comments
- if (
- self.do_comment
- and user_name not in self.dont_include
- and checked_img
- and commenting
- ):
- comments = self.comments + (
- self.video_comments
- if is_video
- else self.photo_comments
- )
- success = process_comments(
- comments,
- temp_comments,
- self.delimit_commenting,
- self.max_comments,
- self.min_comments,
- self.comments_mandatory_words,
- self.username,
- user_name, # Comments with target user
- self.blacklist,
- self.browser,
- link,
- self.logger,
- self.logfolder,
- )
-
- if success:
- commented += 1
- else:
- self.logger.info("--> Not commented")
- sleep(1)
-
- # following
- if (
- self.do_follow
- and user_name not in self.dont_include
- and checked_img
- and following
- and not follow_restriction(
- "read",
- user_name,
- self.follow_times,
- self.logger,
- )
- ):
- follow_state, msg = follow_user(
- self.browser,
- "post",
- self.username,
- user_name,
- None,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
- if follow_state is True:
- followed += 1
- else:
- self.logger.info("--> Not following")
- sleep(1)
-
- # interactions (if any)
- if interact:
- self.logger.info(
- "--> User gonna be interacted: "
- "'{}'".format(user_name)
- )
-
- self.like_by_users(
- user_name,
- self.user_interact_amount,
- self.user_interact_random,
- self.user_interact_media,
- )
- # :P
- yield self
-
- elif msg == "already liked":
- already_liked += 1
-
- elif msg == "block on likes":
- break
-
- elif msg == "jumped":
- # will break the loop after
- # certain consecutive jumps
- self.jumps["consequent"]["likes"] += 1
-
- elif inappropriate:
- inap_img += 1
- self.logger.info(
- "--> Image not liked: {}".format(
- reason.encode("utf-8")
- )
- )
-
- if "Inappropriate" in reason and unfollow:
- # example of unfollowing
- # directly from a post page (faster)
- self.logger.warning(
- "--> Ongoing Unfollow {}: unfollowing"
- " '{}' due to inappropriate content...".format(
- inap_unfollow + 1, user_name
- )
- )
-
- unfollow_state, msg = unfollow_user(
- self.browser,
- "post",
- self.username,
- user_name,
- None,
- None,
- self.relationship_data,
- self.logger,
- self.logfolder,
- )
-
- if unfollow_state is True:
- inap_unfollow += 1
-
- except NoSuchElementException as err:
- self.logger.error("Invalid Page: {}".format(err))
-
- self.logger.info("Liked: {}".format(liked_img))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Followed: {}".format(followed))
- self.logger.info("Inappropriate: {}".format(inap_img))
- self.logger.info("Not valid users: {}".format(not_valid_users))
- self.logger.info("Randomly Skipped: {}\n".format(skipped_img))
-
- self.liked_img += liked_img
- self.already_liked += already_liked
- self.commented += commented
- self.followed += followed
- self.inap_img += inap_img
- self.not_valid_users += not_valid_users
-
- return
-
- def set_dont_unfollow_active_users(
- self, enabled: bool = False, posts: int = 4, boundary: int = 500
- ):
- """Prevents unfollow followers who have liked one of
- your latest X posts"""
-
- if self.aborting:
- return
-
- # do nothing
- if not enabled:
- return
-
- # list of users who liked our media
- active_users = get_active_users(
- self.browser, self.username, posts, boundary, self.logger
- )
-
- # include active user to not unfollow list
- self.dont_include.update(active_users)
-
- def set_blacklist(self, enabled: bool, campaign: str):
- """
- Enable/disable blacklist. If enabled, adds users to a blacklist
- after interact with and adds users to dont_include list
- """
-
- if enabled is False:
- self.dont_include = self.white_list
- return
-
- self.blacklist["enabled"] = True
- self.blacklist["campaign"] = campaign
-
- try:
- with open("{}blacklist.csv".format(self.logfolder), "r") as blacklist:
- reader = csv.DictReader(blacklist)
- for row in reader:
- if row["campaign"] == campaign:
- self.dont_include.add(row["username"])
- # except:
- except Exception:
- self.logger.info("Campaign {} first run".format(campaign))
-
- def grab_followers(
- self,
- username: str = None,
- amount: int = None,
- live_match: bool = False,
- store_locally: bool = True,
- verified_only: bool = False,
- ):
- """
- Gets and returns `followers` information of given user
- in desired amount, also, saves locally
- """
-
- message = "Starting to get the `Followers` data.."
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- if username is None:
- self.logger.warning(
- "Please provide a username to grab `Followers` data"
- " ~e.g. your own username or somebody else's"
- )
- return self
-
- elif amount is None:
- self.logger.warning("Please put amount to grab `Followers` data")
- return self
-
- elif amount != "full" and (
- type(amount) != int or ((type(amount) == int and amount <= 0))
- ):
- self.logger.info(
- "Please provide a valid amount bigger than"
- " zero (0) to grab `Followers` data"
- )
- return self
-
- # Get `followers` data
- grabbed_followers = get_followers(
- self.browser,
- self.username,
- username,
- amount,
- self.relationship_data,
- live_match,
- store_locally,
- self.logger,
- self.logfolder,
- verified_only,
- )
- return grabbed_followers
-
- def grab_following(
- self,
- username: str = None,
- amount: int = None,
- live_match: bool = False,
- store_locally: bool = True,
- ):
- """
- Gets and returns `following` information of given user
- in desired amount, also, saves locally
- """
-
- message = "Starting to get the `Following` data.."
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- if username is None:
- self.logger.warning(
- "Please provide a username to grab `Following` data"
- " ~e.g. your own username or somebody else's"
- )
- return self
-
- elif amount is None:
- self.logger.warning("Please put amount to grab `Following` data")
- return self
-
- elif amount != "full" and (
- type(amount) != int or ((type(amount) == int and amount <= 0))
- ):
- self.logger.info(
- "Please provide a valid amount bigger than"
- " zero (0) to grab `Following` data"
- )
- return self
-
- # get `following` data
- grabbed_following = get_following(
- self.browser,
- self.username,
- username,
- amount,
- self.relationship_data,
- live_match,
- store_locally,
- self.logger,
- self.logfolder,
- )
- return grabbed_following
-
- def pick_unfollowers(
- self,
- username: str = None,
- compare_by: str = "latest",
- compare_track: str = "first",
- live_match: bool = False,
- store_locally: bool = True,
- print_out: bool = True,
- ):
- """
- Compares the `followers` stored in a latest local
- copy against either lively generated data or previous
- local copy and returns absent followers
- """
-
- message = "Starting to pick Unfollowers of {}..".format(username)
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- # get all and active Unfollowers
- all_unfollowers, active_unfollowers = get_unfollowers(
- self.browser,
- self.username,
- username,
- compare_by,
- compare_track,
- self.relationship_data,
- live_match,
- store_locally,
- print_out,
- self.logger,
- self.logfolder,
- )
-
- return all_unfollowers, active_unfollowers
-
- def pick_nonfollowers(
- self, username: str = None, live_match: bool = False, store_locally: bool = True
- ):
- """Returns Nonfollowers data of a given user"""
-
- message = "Starting to pick Nonfollowers of {}..".format(username)
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- # get Nonfollowers
- nonfollowers = get_nonfollowers(
- self.browser,
- self.username,
- username,
- self.relationship_data,
- live_match,
- store_locally,
- self.logger,
- self.logfolder,
- )
-
- return nonfollowers
-
- def pick_fans(
- self, username: str = None, live_match: bool = False, store_locally: bool = True
- ):
- """
- Returns Fans data- all of the usernames who do follow
- the user WHOM user itself do not follow back
- """
-
- message = "Starting to pick Fans of {}..".format(username)
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- # get Fans
- fans = get_fans(
- self.browser,
- self.username,
- username,
- self.relationship_data,
- live_match,
- store_locally,
- self.logger,
- self.logfolder,
- )
-
- return fans
-
- def pick_mutual_following(
- self, username: str = None, live_match: bool = False, store_locally: bool = True
- ):
- """
- Returns Mutual Following data- all of the usernames who
- do follow the user WHOM user itself also do follow back
- """
-
- message = "Starting to pick Mutual Following of {}..".format(username)
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- # get Mutual Following
- mutual_following = get_mutual_following(
- self.browser,
- self.username,
- username,
- self.relationship_data,
- live_match,
- store_locally,
- self.logger,
- self.logfolder,
- )
-
- return mutual_following
-
- def end(self, threaded_session: bool = False):
- """Closes the current session"""
-
- Settings.InstaPy_is_running = False
- close_browser(self.browser, threaded_session, self.logger)
-
- with interruption_handler(threaded=threaded_session):
- # close virtual display
- if self.nogui:
- self.display.stop()
-
- # write useful information
- dump_follow_restriction(self.username, self.logger, self.logfolder)
- dump_record_activity(self.username, self.logger, self.logfolder)
-
- with open("{}followed.txt".format(self.logfolder), "a") as followFile:
- followFile.write(
- "{:%Y-%m-%d %H:%M} {}\n".format(datetime.now(), self.followed or 0)
- )
-
- # output live stats before leaving
- self.live_report()
-
- message = "Session ended!"
- highlight_print(self.username, message, "end", "info", self.logger)
- print("\n\n")
-
- def follow_by_locations(
- self,
- locations: list = [],
- amount: int = 50,
- media: str = None,
- skip_top_posts: bool = True,
- ):
- if self.aborting:
- return self
-
- inap_img = 0
- followed = 0
- not_valid_users = 0
-
- locations = locations
- self.quotient_breach = False
-
- for index, location in enumerate(locations):
- if self.quotient_breach:
- break
-
- self.logger.info("Location [{}/{}]".format(index + 1, len(locations)))
- self.logger.info("--> {}".format(location.encode("utf-8")))
-
- try:
- links = get_links_for_location(
- self.browser, location, amount, self.logger, media, skip_top_posts
- )
- except NoSuchElementException:
- self.logger.warning("Too few images, skipping this location")
- continue
-
- for i, link in enumerate(links):
- if (
- self.jumps["consequent"]["follows"]
- >= self.jumps["limit"]["follows"]
- ):
- self.logger.warning(
- "--> Follow quotient reached its peak!"
- "\t~leaving Follow-By-Locations activity\n"
- )
- self.quotient_breach = True
- # reset jump counter after a breach report
- self.jumps["consequent"]["follows"] = 0
- break
-
- self.logger.info("Follow# [{}/{}]".format(i + 1, len(links)))
- self.logger.info(link)
-
- try:
- inappropriate, user_name, is_video, reason, scope = check_link(
- self.browser,
- link,
- self.dont_like,
- self.mandatory_words,
- self.mandatory_language,
- self.is_mandatory_character,
- self.mandatory_character,
- self.check_character_set,
- self.ignore_if_contains,
- self.logger,
- )
-
- if not inappropriate:
- # validate user
- validation, details = self.validate_user_call(user_name)
- if validation is not True:
- self.logger.info(details)
- not_valid_users += 1
- continue
- else:
- web_address_navigator(self.browser, link)
-
- # try to follow
- follow_state, msg = follow_user(
- self.browser,
- "post",
- self.username,
- user_name,
- None,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
- if follow_state is True:
- followed += 1
- # reset jump counter after a successful follow
- self.jumps["consequent"]["follows"] = 0
-
- elif msg == "jumped":
- # will break the loop after certain consecutive
- # jumps
- self.jumps["consequent"]["follows"] += 1
-
- else:
- self.logger.info("--> User not followed: {}".format(reason))
- inap_img += 1
-
- except NoSuchElementException as err:
- self.logger.error("Invalid Page: {}".format(err))
-
- self.logger.info("Followed: {}".format(followed))
- self.logger.info("Inappropriate: {}".format(inap_img))
- self.logger.info("Not valid users: {}\n".format(not_valid_users))
-
- self.followed += followed
- self.inap_img += inap_img
- self.not_valid_users += not_valid_users
-
- return self
-
- def follow_by_tags(
- self,
- tags: list = [],
- amount: int = 50,
- skip_top_posts: bool = True,
- use_smart_hashtags: bool = False,
- use_smart_location_hashtags: bool = False,
- randomize: bool = False,
- media: str = None,
- interact: bool = False,
- ):
-
- if self.aborting:
- return self
-
- inap_img = 0
- followed = 0
- not_valid_users = 0
-
- # if smart hashtag is enabled
- if use_smart_hashtags is True and self.smart_hashtags != []:
- self.logger.info("Using smart hashtags")
- tags = self.smart_hashtags
- elif use_smart_location_hashtags is True and self.smart_location_hashtags != []:
- self.logger.info("Using smart location hashtags")
- tags = self.smart_location_hashtags
-
- # deletes white spaces in tags
- tags = [tag.strip() for tag in tags]
- tags = tags
- self.quotient_breach = False
-
- for index, tag in enumerate(tags):
- if self.quotient_breach:
- break
-
- self.logger.info("Tag [{}/{}]".format(index + 1, len(tags)))
- self.logger.info("--> {}".format(tag.encode("utf-8")))
-
- try:
- links = get_links_for_tag(
- self.browser,
- tag,
- amount,
- skip_top_posts,
- randomize,
- media,
- self.logger,
- )
- except NoSuchElementException:
- self.logger.info("Too few images, skipping this tag")
- continue
-
- for i, link in enumerate(links):
- if (
- self.jumps["consequent"]["follows"]
- >= self.jumps["limit"]["follows"]
- ):
- self.logger.warning(
- "--> Follow quotient reached its peak!"
- "\t~leaving Follow-By-Tags activity\n"
- )
- self.quotient_breach = True
- # reset jump counter after a breach report
- self.jumps["consequent"]["follows"] = 0
- break
-
- self.logger.info("Follow# [{}/{}]".format(i + 1, len(links)))
- self.logger.info(link)
-
- try:
- inappropriate, user_name, is_video, reason, scope = check_link(
- self.browser,
- link,
- self.dont_like,
- self.mandatory_words,
- self.mandatory_language,
- self.is_mandatory_character,
- self.mandatory_character,
- self.check_character_set,
- self.ignore_if_contains,
- self.logger,
- )
-
- if not inappropriate:
- # validate user
- validation, details = self.validate_user_call(user_name)
- if validation is not True:
- self.logger.info(details)
- not_valid_users += 1
- continue
- else:
- web_address_navigator(self.browser, link)
-
- # try to follow
- follow_state, msg = follow_user(
- self.browser,
- "post",
- self.username,
- user_name,
- None,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
- if follow_state is True:
- followed += 1
- # reset jump counter after a successful follow
- self.jumps["consequent"]["follows"] = 0
-
- # Check if interaction is expected
- if interact and self.do_like:
- do_interact = (
- random.randint(0, 100)
- <= self.user_interact_percentage
- )
- # Do interactions if any
- if do_interact and self.user_interact_amount > 0:
- # store the original value
- original_do_follow = self.do_follow
- # disable following temporarily
- self.do_follow = False
- self.interact_by_users(
- user_name,
- self.user_interact_amount,
- self.user_interact_random,
- self.user_interact_media,
- )
- # back original `self.do_follow` value
- self.do_follow = original_do_follow
- elif msg == "jumped":
- # will break the loop after certain consecutive
- # jumps
- self.jumps["consequent"]["follows"] += 1
-
- else:
- self.logger.info("--> User not followed: {}".format(reason))
- inap_img += 1
-
- except NoSuchElementException as err:
- self.logger.error("Invalid Page: {}".format(err))
-
- self.logger.info("Followed: {}".format(followed))
- self.logger.info("Inappropriate: {}".format(inap_img))
- self.logger.info("Not valid users: {}\n".format(not_valid_users))
-
- self.followed += followed
- self.inap_img += inap_img
- self.not_valid_users += not_valid_users
-
- return self
-
- def interact_by_URL(
- self, urls: list = [], randomize: bool = False, interact: bool = False
- ):
- """Interact on posts at given URLs"""
-
- if self.aborting:
- return self
-
- message = "Starting to interact by given URLs.."
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- if not isinstance(urls, list):
- urls = [urls]
-
- if randomize is True:
- random.shuffle(urls)
-
- liked_img = 0
- already_liked = 0
- inap_img = 0
- commented = 0
- followed = 0
- not_valid_users = 0
-
- for index, url in enumerate(urls):
- if self.jumps["consequent"]["likes"] >= self.jumps["limit"]["likes"]:
- self.logger.warning(
- "--> Like quotient reached its peak!"
- "\t~leaving Interact-By-URL activity\n"
- )
- # reset jump counter before breaking the loop
- self.jumps["consequent"]["likes"] = 0
- # we have not used `quotient_breach` here
- # cos this method has just one iterator
- break
-
- if "https://www.instagram.com/p/" not in url:
- url = "https://www.instagram.com/p/" + url
-
- self.logger.info("URL [{}/{}]".format(index + 1, len(urls)))
- self.logger.info("--> {}".format(url.encode("utf-8")))
-
- try:
- inappropriate, user_name, is_video, reason, scope = check_link(
- self.browser,
- url,
- self.dont_like,
- self.mandatory_words,
- self.mandatory_language,
- self.is_mandatory_character,
- self.mandatory_character,
- self.check_character_set,
- self.ignore_if_contains,
- self.logger,
- )
-
- if not inappropriate and self.delimit_liking:
- self.liking_approved = verify_liking(
- self.browser, self.max_likes, self.min_likes, self.logger
- )
-
- if not inappropriate and self.liking_approved:
- # validate user
- validation, details = self.validate_user_call(user_name)
- if validation is not True:
- self.logger.info(details)
- not_valid_users += 1
- continue
- else:
- web_address_navigator(self.browser, url)
-
- # try to like
- like_state, msg = like_image(
- self.browser,
- user_name,
- self.blacklist,
- self.logger,
- self.logfolder,
- liked_img,
- )
-
- if like_state is True or self.do_comment_liked_photo:
- if self.do_comment_liked_photo:
- already_liked += 1
- else:
- liked_img += 1
- # reset jump counter after a successful like
- self.jumps["consequent"]["likes"] = 0
-
- checked_img = True
- temp_comments = []
-
- commenting = random.randint(0, 100) <= self.comment_percentage
- following = random.randint(0, 100) <= self.follow_percentage
-
- if self.use_clarifai and (following or commenting):
- try:
- (
- checked_img,
- temp_comments,
- clarifai_tags,
- ) = self.query_clarifai()
-
- except Exception as err:
- self.logger.error("Image check error: {}".format(err))
-
- # comments
- if (
- self.do_comment
- and user_name not in self.dont_include
- and checked_img
- and commenting
- ):
- comments = self.comments + (
- self.video_comments if is_video else self.photo_comments
- )
- success = process_comments(
- comments,
- temp_comments,
- self.delimit_commenting,
- self.max_comments,
- self.min_comments,
- self.comments_mandatory_words,
- self.username,
- user_name, # Comments with target user
- self.blacklist,
- self.browser,
- url,
- self.logger,
- self.logfolder,
- )
-
- if success:
- commented += 1
- else:
- self.logger.info("--> Not commented")
- sleep(1)
-
- if (
- self.do_follow
- and user_name not in self.dont_include
- and checked_img
- and following
- and not follow_restriction(
- "read", user_name, self.follow_times, self.logger
- )
- ):
- follow_state, msg = follow_user(
- self.browser,
- "post",
- self.username,
- user_name,
- None,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
-
- if follow_state is True:
- followed += 1
- else:
- self.logger.info("--> Not following")
- sleep(1)
-
- # check if interaction is expected
- if interact is True:
- do_interact = (
- random.randint(0, 100) <= self.user_interact_percentage
- )
- # do interactions if any
- if do_interact and self.user_interact_amount > 0:
- self.interact_by_users(
- user_name,
- self.user_interact_amount,
- self.user_interact_random,
- self.user_interact_media,
- )
-
- elif msg == "already liked":
- already_liked += 1
-
- elif msg == "block on likes":
- break
-
- elif msg == "jumped":
- # will break the loop after certain consecutive jumps
- self.jumps["consequent"]["likes"] += 1
-
- else:
- self.logger.info(
- "--> Image not liked: {}".format(reason.encode("utf-8"))
- )
- inap_img += 1
-
- except NoSuchElementException as err:
- self.logger.error("Invalid Page: {}".format(err))
-
- self.logger.info("Liked: {}".format(liked_img))
- self.logger.info("Already Liked: {}".format(already_liked))
- self.logger.info("Commented: {}".format(commented))
- self.logger.info("Followed: {}".format(followed))
- self.logger.info("Inappropriate: {}".format(inap_img))
- self.logger.info("Not valid users: {}\n".format(not_valid_users))
-
- self.liked_img += liked_img
- self.already_liked += already_liked
- self.commented += commented
- self.followed += followed
- self.inap_img += inap_img
- self.not_valid_users += not_valid_users
-
- return self
-
- def set_quota_supervisor(
- self,
- enabled: bool = False,
- sleep_after: list = [],
- sleepyhead: bool = False,
- stochastic_flow: bool = False,
- notify_me: bool = False,
- peak_likes_hourly: int = None,
- peak_likes_daily: int = None,
- peak_comments_hourly: int = None,
- peak_comments_daily: int = None,
- peak_follows_hourly: int = None,
- peak_follows_daily: int = None,
- peak_unfollows_hourly: int = None,
- peak_unfollows_daily: int = None,
- peak_server_calls_hourly: int = None,
- peak_server_calls_daily: int = None,
- ):
- """
- Sets aside QS configuration ANY time in a session
- """
-
- # take a reference of the global configuration
- configuration = Settings.QS_config
-
- peaks = {
- "likes": {"hourly": peak_likes_hourly, "daily": peak_likes_daily},
- "comments": {"hourly": peak_comments_hourly, "daily": peak_comments_daily},
- "follows": {"hourly": peak_follows_hourly, "daily": peak_follows_daily},
- "unfollows": {
- "hourly": peak_unfollows_hourly,
- "daily": peak_unfollows_daily,
- },
- "server_calls": {
- "hourly": peak_server_calls_hourly,
- "daily": peak_server_calls_daily,
- },
- }
-
- if not isinstance(sleep_after, list):
- sleep_after = [sleep_after]
-
- rt = time.time()
- latesttime = {"hourly": rt, "daily": rt}
- orig_peaks = deepcopy(peaks) # original peaks always remain static
- stochasticity = {
- "enabled": stochastic_flow,
- "latesttime": latesttime,
- "original_peaks": orig_peaks,
- }
-
- if platform.startswith("win32") and python_version() < "2.7.15":
- # UPDATE ME: remove this block once plyer is
- # verified to work on [very] old versions of Python 2
- notify_me = False
-
- # update QS configuration with the fresh settings
- configuration.update(
- {
- "state": enabled,
- "sleep_after": sleep_after,
- "sleepyhead": sleepyhead,
- "stochasticity": stochasticity,
- "notify": notify_me,
- "peaks": peaks,
- }
- )
-
- @contextmanager
- def feature_in_feature(self, feature, validate_users):
- """
- Use once a host feature calls a guest
- feature WHERE guest needs special behaviour(s)
- """
-
- try:
- # add the guest which is gonna be used by the host :)
- self.internal_usage[feature] = {"validate": validate_users}
- yield
-
- finally:
- # remove the guest just after using it
- self.internal_usage.pop(feature)
-
- def live_report(self):
- """Report live sessional statistics"""
-
- print("")
-
- stats = [
- self.liked_img,
- self.already_liked,
- self.commented,
- self.followed,
- self.already_followed,
- self.unfollowed,
- self.stories_watched,
- self.reels_watched,
- self.inap_img,
- self.not_valid_users,
- ]
-
- if self.following_num and self.followed_by:
- owner_relationship_info = (
- "On session start was FOLLOWING {} users"
- " & had {} FOLLOWERS".format(self.following_num, self.followed_by)
- )
- else:
- owner_relationship_info = ""
-
- sessional_run_time = self.run_time()
- run_time_info = (
- "{} seconds".format(sessional_run_time)
- if sessional_run_time < 60
- else "{} minutes".format(truncate_float(sessional_run_time / 60, 2))
- if sessional_run_time < 3600
- else "{} hours".format(truncate_float(sessional_run_time / 60 / 60, 2))
- )
- run_time_msg = "[Session lasted {}]".format(run_time_info)
-
- if any(stat for stat in stats):
- self.logger.info(
- "Sessional Live Report:\n"
- "\t|> LIKED {} images | ALREADY LIKED: {}\n"
- "\t|> COMMENTED on {} images\n"
- "\t|> FOLLOWED {} users | ALREADY FOLLOWED: {}\n"
- "\t|> UNFOLLOWED {} users\n"
- "\t|> LIKED {} comments\n"
- "\t|> REPLIED to {} comments\n"
- "\t|> INAPPROPRIATE images: {}\n"
- "\t|> NOT VALID users: {}\n"
- "\t|> WATCHED {} story(ies) | WATCHED {} reel(s)\n"
- "\n{}\n{}".format(
- self.liked_img,
- self.already_liked,
- self.commented,
- self.followed,
- self.already_followed,
- self.unfollowed,
- self.liked_comments,
- self.replied_to_comments,
- self.inap_img,
- self.not_valid_users,
- self.stories_watched,
- self.reels_watched,
- owner_relationship_info,
- run_time_msg,
- )
- )
- else:
- self.logger.info(
- "Sessional Live Report:\n"
- "\t|> No any statistics to show\n"
- "\n{}\n{}".format(owner_relationship_info, run_time_msg)
- )
-
- def set_do_reply_to_comments(self, enabled: bool = False, percentage: int = 0):
- """Define if the comments on posts should be replied"""
-
- self.do_reply_to_comments = enabled
- self.reply_to_comments_percent = percentage
-
- return self
-
- def set_comment_replies(self, replies: list = [], media: str = None):
- """Set the replies to comments"""
-
- if not replies:
- self.logger.info("Please, provide some comment replies for use next time.")
- self.comment_replies = None
- self.photo_comment_replies = None
- self.video_comment_replies = None
-
- return self
-
- if media in [MEDIA_PHOTO, MEDIA_VIDEO]:
- attr = "{}_comment_replies".format(media.lower())
- setattr(self, attr, replies)
-
- else:
- if media is not None:
- self.logger.warning(
- "Unknown media type set at comment replies! Treating as 'any'."
- )
-
- self.comment_replies = replies
-
- def set_use_meaningcloud(
- self,
- enabled: bool = False,
- license_key: str = None,
- polarity: str = "P",
- agreement: str = None,
- subjectivity: str = None,
- confidence: bool = 100,
- ):
- """Set MeaningCloud Sentiment Analysis API configuration"""
-
- if license_key is None:
- license_key = os.environ.get("MEANINGCLOUD_LIC_KEY")
-
- if polarity.upper() not in ["P", "P+", "NEU", "N", "N+"]:
- self.logger.info(
- "Oh no! Please provide a valid polarity "
- "score tag for MeaningCloud"
- "\t~service will not operate"
- )
- polarity = None
-
- if enabled and license_key and polarity:
- Settings.meaningcloud_config.update(
- enabled=enabled,
- license_key=license_key,
- score_tag=polarity.upper(),
- agreement=agreement.upper() if agreement else None,
- subjectivity=subjectivity.upper() if subjectivity else None,
- confidence=int(confidence) if confidence else None,
- )
-
- else:
- # turn off MeaningCloud service if not enabled or wrongly
- # configured
- Settings.meaningcloud_config.update(enabled=False)
-
- def set_use_yandex(
- self,
- enabled: bool = False,
- API_key: str = None,
- match_language: bool = False,
- language_code: str = "en",
- ):
- """Set Yandex Translate API configuration"""
-
- if API_key is None:
- API_key = os.environ.get("YANDEX_API_KEY")
-
- if enabled and API_key:
- Settings.yandex_config.update(enabled=enabled, API_key=API_key)
-
- if match_language is True and language_code:
- supported_langs = yandex_supported_languages()
-
- if not supported_langs or language_code.lower() not in supported_langs:
- msg = (
- "Oh no! Failed to get the list of supported"
- " languages by Yandex Translate :("
- if not supported_langs
- else "Oh no! The language with '{}' code is not"
- " supported by Yandex Translate :/".format(language_code)
- )
- self.logger.info("{}\t~text language won't be matched".format(msg))
- match_language = False
-
- Settings.yandex_config.update(
- match_language=match_language if language_code else False,
- language_code=language_code.lower() if language_code else None,
- )
-
- else:
- # turn off Yandex service if not enabled or wrongly configured
- Settings.yandex_config.update(enabled=False)
-
- def interact_by_comments(
- self,
- usernames: list = None,
- posts_amount: int = 10,
- comments_per_post: int = 1,
- reply: bool = False,
- interact: bool = False,
- randomize: bool = False,
- media: str = None,
- ):
- """
- Like comments of people on posts, reply to them
- and also interact with those commenters
- """
- if self.aborting:
- return self
- message = "Starting to interact by comments.."
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- if not isinstance(usernames, list):
- usernames = [usernames]
-
- if media not in [MEDIA_PHOTO, MEDIA_VIDEO, None]:
- self.logger.warning(
- "Unknown media type- '{}' set at"
- " Interact-By-Comments!\t~treating as any..".format(media)
- )
- media = None
-
- # hold the current global values for differentiating at the end
- liked_init = self.liked_img
- already_liked_init = self.already_liked
- liked_comments_init = self.liked_comments
- commented_init = self.commented
- replied_to_comments_init = self.replied_to_comments
- followed_init = self.followed
- already_followed_init = self.already_followed
- inap_img_init = self.inap_img
- not_valid_users_init = self.not_valid_users
-
- overall_posts_count = 0
- self.quotient_breach = False
- like_failures_tracker = {
- "consequent": {"post_likes": 0, "comment_likes": 0},
- "limit": {"post_likes": 5, "comment_likes": 10},
- }
-
- leave_msg = "\t~leaving Interact-By-Comments activity\n"
-
- # start the interaction!
- for s, username in enumerate(usernames):
- if self.quotient_breach:
- break
-
- message = "User: [{}/{}]".format(s + 1, len(usernames))
- highlight_print(
- self.username, message, "user iteration", "info", self.logger
- )
-
- if username != self.username:
- validation, details = self.validate_user_call(username)
- if validation is not True:
- self.logger.info("--> Not a valid user: {}".format(details))
- self.not_valid_users += 1
- continue
-
- per_user_liked_comments = 0
- per_user_replied_to_comments = 0
- per_user_used_replies = []
-
- try:
- links = get_links_for_username(
- self.browser,
- self.username,
- username,
- posts_amount,
- self.logger,
- self.logfolder,
- randomize,
- media,
- )
- except NoSuchElementException:
- self.logger.error("Element not found, skipping this user.")
- continue
-
- if links is False:
- continue
-
- else:
- if randomize:
- random.shuffle(links)
- links = links[:posts_amount]
- overall_posts_count += len(links)
-
- for i, link in enumerate(links):
- if self.quotient_breach:
- break
-
- elif (
- self.jumps["consequent"]["comments"]
- >= self.jumps["limit"]["comments"]
- ):
- self.logger.warning(
- "--> Comment quotient reached its peak!{}".format(leave_msg)
- )
- self.quotient_breach = True
- # reset jump counter after a breach report
- self.jumps["consequent"]["comments"] = 0
- break
-
- elif (
- like_failures_tracker["consequent"]["post_likes"]
- >= like_failures_tracker["limit"]["post_likes"]
- ):
- self.logger.warning(
- "--> Too many failures to like posts!{}".format(leave_msg)
- )
- # this example shows helpful usage of
- # quotient breach outside QS needs..
- self.quotient_breach = True
- break
-
- message = "Post: [{}/{}]".format(i + 1, len(links))
- highlight_print(
- self.username, message, "post iteration", "info", self.logger
- )
-
- (inappropriate, user_name, is_video, reason, scope) = check_link(
- self.browser,
- link,
- self.dont_like,
- self.mandatory_words,
- self.mandatory_language,
- self.is_mandatory_character,
- self.mandatory_character,
- self.check_character_set,
- self.ignore_if_contains,
- self.logger,
- )
-
- if inappropriate:
- self.logger.info(
- "--> Post not interacted. {}\n".format(reason.encode("utf-8"))
- )
- self.inap_img += 1
- continue
-
- # go go!
- per_post_liked_comments = 0
- per_post_replied_to_comments = 0
- per_post_interacted_commenters = []
-
- # get comments (if any)
- comment_data = get_comments_on_post(
- self.browser,
- self.username,
- username,
- comments_per_post,
- link,
- self.ignore_users,
- randomize,
- self.logger,
- )
- if not comment_data:
- self.logger.info("No interaction did happen.\n")
- continue
-
- # like the post before interacting on comments
- image_like_state, msg = like_image(
- self.browser,
- user_name,
- self.blacklist,
- self.logger,
- self.logfolder,
- self.liked_img,
- )
- if image_like_state is True:
- like_failures_tracker["consequent"]["post_likes"] = 0
- self.liked_img += 1
-
- elif msg == "already liked":
- self.already_liked += 1
-
- elif msg == "block on likes":
- break
-
- else:
- self.logger.info(
- "Can't interact by comments unless"
- " the post is liked! :(\t~skipping this post\n"
- )
- like_failures_tracker["consequent"]["post_likes"] += 1
- continue
-
- # perfect! now going to work with comments...
- for commenter, comment in comment_data:
- if per_post_liked_comments >= comments_per_post:
- break
-
- elif (
- like_failures_tracker["consequent"]["comment_likes"]
- >= like_failures_tracker["limit"]["comment_likes"]
- ):
- self.logger.warning(
- "--> Too many failures to like comments!{}".format(
- leave_msg
- )
- )
- # this example shows helpful usage of
- # quotient breach outside QS needs..
- self.quotient_breach = True
- break
-
- # verify the comment content by sentiment analysis &
- # language detection if enabled
- text_analysis_state = text_analysis(comment, "comment", self.logger)
- if text_analysis_state is False:
- # comment is inappropriate to be liked [and replied]
- continue
-
- # like the comment
- comment_like_state, msg = like_comment(
- self.browser, comment, self.logger
- )
- if comment_like_state is not True:
- like_failures_tracker["consequent"]["comment_likes"] += 1
- continue
-
- else:
- per_post_interacted_commenters.append(commenter)
- self.liked_comments += 1
- per_user_liked_comments += 1
- per_post_liked_comments += 1
- like_failures_tracker["consequent"]["comment_likes"] = 0
-
- # send a reply to the comment if is appropriate
- if (
- self.do_reply_to_comments
- and reply
- and text_analysis_state is True
- ):
- do_reply_to_comment = (
- self.reply_to_comments_percent >= random.randint(0, 100)
- )
-
- comment_replies_base = self.comment_replies + (
- self.video_comment_replies
- if is_video
- else self.photo_comment_replies
- )
- # dismiss the already used replies per each user
- comment_replies_base = [
- reply
- for reply in comment_replies_base
- if reply not in per_user_used_replies
- ]
-
- if do_reply_to_comment and comment_replies_base:
- chosen_reply = random.choice(comment_replies_base)
- # mention the commenter to make a reply :)
- reply_msg = ["@{} {}".format(commenter, chosen_reply)]
-
- reply_to_comment_state, msg = comment_image(
- self.browser,
- commenter,
- reply_msg,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
-
- if reply_to_comment_state is True:
- per_user_used_replies.extend(chosen_reply)
- self.replied_to_comments += 1
- self.commented += 1
- per_user_replied_to_comments += 1
- per_post_replied_to_comments += 1
- # reset jump counter after a successful
- # comment
- self.jumps["consequent"]["comments"] = 0
-
- elif msg == "jumped":
- # will break the loop after
- # certain consecutive jumps
- self.jumps["consequent"]["comments"] += 1
-
- post_No_ending = (
- "st"
- if str(i + 1).endswith("1")
- else "nd"
- if str(i + 1).endswith("2")
- else "rd"
- if str(i + 1).endswith("3")
- else "th"
- if str(i + 1).endswith("4")
- else ""
- )
- post_No = "{}{}".format(str(i + 1), post_No_ending)
-
- # quick log after interacting on a post
- print("")
- self.logger.info(
- "Finished interacting on {} post's comments!".format(post_No)
- )
- self.logger.info("\tLiked comments: {}".format(per_post_liked_comments))
- self.logger.info(
- "\tReplied to comments: {}\n".format(per_post_replied_to_comments)
- )
-
- # standalone interaction with commenters whose
- # comment was liked on the post
- if interact and per_post_interacted_commenters:
- with self.feature_in_feature("interact_by_users", True):
- self.interact_by_users(
- per_post_interacted_commenters,
- self.user_interact_amount,
- self.user_interact_random,
- self.user_interact_media,
- )
-
- # quick log after interacting with a user
- print("")
- self.logger.info(
- "Finished interacting on {} posts' comments of '{}'!".format(
- len(links), username
- )
- )
- self.logger.info("\tLiked comments: {}".format(per_user_liked_comments))
- self.logger.info(
- "\tReplied to comments: {}\n".format(per_user_replied_to_comments)
- )
-
- # full log after finishing whole work
- self.logger.info(
- "Finished interacting on {} posts' comments from {} users!".format(
- overall_posts_count, len(usernames)
- )
- )
-
- # find the feature-wide action sizes by taking a difference
- liked_img = self.liked_img - liked_init
- already_liked = self.already_liked - already_liked_init
- liked_comments = self.liked_comments - liked_comments_init
- replied_to_comments = self.replied_to_comments - replied_to_comments_init
- commented = (self.commented - commented_init) - replied_to_comments
- followed = self.followed - followed_init
- already_followed = self.already_followed - already_followed_init
- inap_img = self.inap_img - inap_img_init
- not_valid_users = self.not_valid_users - not_valid_users_init
-
- if self.liked_comments:
- # output results
- self.logger.info("\tLiked comments: {}".format(liked_comments))
- self.logger.info("\tReplied to comments: {}".format(replied_to_comments))
- self.logger.info("\tLiked posts: {}".format(liked_img))
- self.logger.info("\tAlready liked posts: {}".format(already_liked))
- self.logger.info("\tCommented posts: {}".format(commented))
- self.logger.info("\tFollowed users: {}".format(followed))
- self.logger.info("\tAlready followed users: {}".format(already_followed))
- self.logger.info("\tInappropriate posts: {}".format(inap_img))
- self.logger.info("\tNot valid users: {}".format(not_valid_users))
-
- def is_mandatory_character(self, uchr):
- if self.aborting:
- return self
- try:
- return self.check_letters[uchr]
- except KeyError:
- return self.check_letters.setdefault(
- uchr,
- any(
- mandatory_char in unicodedata.name(uchr)
- for mandatory_char in self.mandatory_character
- ),
- )
-
- def run_time(self):
- """Get the time session lasted in seconds"""
-
- real_time = time.time()
- run_time = real_time - self.start_time
- run_time = truncate_float(run_time, 2)
-
- return run_time
-
- def check_character_set(self, unistr):
- self.check_letters = {}
- if self.aborting:
- return self
- return all(
- self.is_mandatory_character(uchr) for uchr in unistr if uchr.isalpha()
- )
-
- def accept_follow_requests(self, amount: int = 100, sleep_delay: int = 1):
- """Accept pending follow requests from activity feed"""
-
- if self.aborting:
- return self
-
- message = "Starting to get follow requests.."
- highlight_print(self.username, message, "feature", "info", self.logger)
-
- accepted = 0
- while accepted < amount:
-
- feed_link = "https://www.instagram.com/accounts/activity/?followRequests=1"
- web_address_navigator(self.browser, feed_link)
-
- requests_to_confirm = self.browser.find_elements(
- By.XPATH, "//button[text()='Confirm']"
- )
-
- if len(requests_to_confirm) == 0:
- self.logger.info("There are no follow requests in activity feed")
- break
-
- for request in requests_to_confirm:
- request.click()
- sleep(sleep_delay)
- accepted += 1
- if accepted >= amount:
- self.logger.info(
- "Reached accepted accounts limit of {} requests".format(amount)
- )
- break
- # catch if the list cannot be accessed, there are more followers under the hood or
- # because another element obscures it...
- scroll_down(self.browser)
-
- self.logger.info("Accepted {} follow requests".format(accepted))
-
- return self
-
- def join_pods(self, topic: str = "general", engagement_mode: str = "normal"):
- """Join pods"""
- if topic not in self.allowed_pod_topics:
- self.logger.error(
- "You have entered an invalid topic for pods, allowed topics are : {}. Exiting...".format(
- self.allowed_pod_topics
- )
- )
- return self
-
- if engagement_mode not in self.allowed_pod_engagement_modes:
- self.logger.error(
- "You have entered an invalid engagement_mode for pods, allowed engagement_modes are : {}. Exiting...".format(
- self.allowed_pod_engagement_modes
- )
- )
- return self
-
- if self.comments is not None and len(self.comments) < 10:
- self.logger.error(
- "You have too few comments, please set at least 10 distinct comments to avoid looking suspicious."
- )
- return self
-
- user_link = "https://www.instagram.com/{}/".format(self.username)
- web_address_navigator(self.browser, user_link)
- try:
- pod_posts = get_recent_posts_from_pods(topic, self.logger)
- self.logger.info("Downloaded pod_posts : {}".format(pod_posts))
-
- sleep(2)
- post_link_elems = self.browser.find_elements(
- By.XPATH, "//a[contains(@href, '/p/')]"
- )
- post_links = []
- post_link = None
-
- for post_link_elem in post_link_elems:
- try:
- post_link = post_link_elem.get_attribute("href")
- post_links.append(post_link)
- except Exception as e:
- self.logger.error(
- "Can not get href for {} - {}".format(post_link, e)
- )
- continue
-
- post_links = list(set(post_links))
- my_recent_post_ids = []
- for post_link in post_links:
- try:
- web_address_navigator(self.browser, post_link)
- sleep(2)
- time_element = self.browser.find_element(By.XPATH, "//div/a/time")
- post_datetime_str = time_element.get_attribute("datetime")
- post_datetime = datetime.strptime(
- post_datetime_str, "%Y-%m-%dT%H:%M:%S.%fZ"
- )
- postid = post_link.split("/")[4]
- self.logger.info(
- "Post: {}, Instaposted at: {}".format(postid, post_datetime)
- )
- share_restricted = share_with_pods_restriction(
- "read", postid, self.share_times, self.logger
- )
- if (
- datetime.now() - post_datetime < timedelta(hours=12, minutes=30)
- and not share_restricted
- ):
- my_recent_post_ids.append(postid)
- if share_my_post_with_pods(
- postid, topic, engagement_mode, self.logger
- ):
- share_with_pods_restriction(
- "write", postid, None, self.logger
- )
- except Exception as err:
- self.logger.error(
- "Failed for {} with Error {}".format(post_link, err)
- )
-
- if len(my_recent_post_ids) > 0:
- self.logger.info(
- "I have recent post(s): {}, so I will now help pod members actively.".format(
- my_recent_post_ids
- )
- )
- nposts = 200
- else:
- self.logger.info(
- "I don't have any recent post, so I will just help a few pod posts and move on."
- )
- nposts = 40
-
- if len(pod_posts) <= nposts:
- pod_posts = pod_posts
- else:
- pod_posts = random.sample(pod_posts, nposts)
-
- no_comments_posts, light_posts, normal_posts, heavy_posts = group_posts(
- pod_posts, self.logger
- )
-
- self.logger.error("no_comments_posts : {} ".format(no_comments_posts))
- self.logger.error("light_posts : {} ".format(light_posts))
- self.logger.error("normal_posts : {} ".format(normal_posts))
- self.logger.error("heavy_posts : {} ".format(heavy_posts))
-
- self.engage_with_posts(no_comments_posts, 0)
- self.engage_with_posts(light_posts, 10)
- self.engage_with_posts(normal_posts, 30)
- self.engage_with_posts(heavy_posts, 90)
-
- except Exception as err:
- self.logger.error(err)
-
- return self
-
- def engage_with_posts(self, pod_posts, modespecific_comment_percentage):
- for pod_post in pod_posts:
- try:
- pod_post_id = pod_post["postid"]
- post_link = "https://www.instagram.com/p/{}".format(pod_post_id)
- web_address_navigator(self.browser, post_link)
-
- inappropriate, user_name, is_video, reason, scope = check_link(
- self.browser,
- post_link,
- self.dont_like,
- self.mandatory_words,
- self.mandatory_language,
- self.is_mandatory_character,
- self.mandatory_character,
- self.check_character_set,
- self.ignore_if_contains,
- self.logger,
- )
-
- if user_name != self.username:
- follow_state, msg = follow_user(
- self.browser,
- "post",
- self.username,
- user_name,
- None,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
-
- self.dont_include.add(user_name)
-
- if not inappropriate and user_name != self.username:
- pods_like_percent = max(90, min(100, self.like_percentage))
- liking = random.randint(0, 100) <= pods_like_percent
- commenting = (
- random.randint(0, 100) <= modespecific_comment_percentage
- )
-
- if liking:
- like_state, msg = like_image(
- self.browser,
- user_name,
- self.blacklist,
- self.logger,
- self.logfolder,
- self.liked_img,
- )
-
- if like_state is True or self.do_comment_liked_photo:
- self.liked_img += 1
-
- elif msg == "block on likes":
- break
-
- commenting_restricted = comment_restriction(
- "read", pod_post_id, self.comment_times, self.logger
- )
-
- if commenting and not commenting_restricted:
- comments = self.fetch_smart_comments(is_video, temp_comments=[])
-
- comment_state, msg = comment_image(
- self.browser,
- user_name,
- comments,
- self.blacklist,
- self.logger,
- self.logfolder,
- )
- if comment_state:
- comment_restriction("write", pod_post_id, None, self.logger)
-
- except Exception as err:
- self.logger.error("Failed for {} with Error {}".format(pod_post, err))
-
- def story_by_tags(self, tags: list = None):
- """Watch stories for specific tag(s)"""
- if self.aborting:
- return self
-
- if tags is None:
- self.logger.info("No Tags set")
- else:
- # iterate over available tags
- for index, tag in enumerate(tags):
- # Quota Supervisor peak check
- if self.quotient_breach:
- break
-
- # inform user whats happening
- if len(tags) > 1:
- self.logger.info("Tag [{}/{}]".format(index + 1, len(tags)))
- self.logger.info(
- "Loading stories with Tag --> {}".format(tag.encode("utf-8"))
- )
-
- try:
- reels = watch_story(
- self.browser, tag, self.logger, "tag", self.story_simulate
- )
- except NoSuchElementException:
- self.logger.info("No stories skipping this tag")
- continue
- if reels > 0:
- self.stories_watched += 1
- self.reels_watched += reels
-
- def story_by_users(self, users: list = None):
- """Watch stories for specific user(s)"""
- if self.aborting:
- return self
-
- if users is None:
- self.logger.info("No users passed to story_by_users")
- else:
- # iterate over available users
- for index, user in enumerate(users):
- # Quota Supervisor peak check
- if self.quotient_breach:
- break
-
- # inform user whats happening
- if len(users) > 1:
- self.logger.info("User [{}/{}]".format(index + 1, len(users)))
- self.logger.info(
- "Loading stories with User --> {}".format(user.encode("utf-8"))
- )
-
- try:
- reels = watch_story(
- self.browser, user, self.logger, "user", self.story_simulate
- )
- except NoSuchElementException:
- self.logger.info("No stories skipping this user")
- continue
- if reels > 0:
- self.stories_watched += 1
- self.reels_watched += reels
-
- def target_list(self, file):
- """Extracts target list from text file"""
- target_list = file_handling(file)
-
- if "FileNotFoundError" in target_list:
- self.logger.warning("No such file or directory: " + file + "\n")
- return []
-
- return target_list
diff --git a/instapy/like_util.py b/instapy/like_util.py
deleted file mode 100644
index 72f9367f3..000000000
--- a/instapy/like_util.py
+++ /dev/null
@@ -1,1003 +0,0 @@
-""" Module that handles the like features """
-# import built-in & third-party modules
-import random
-import re
-from re import findall
-
-# import exceptions
-from selenium.common.exceptions import (
- NoSuchElementException,
- StaleElementReferenceException,
- WebDriverException,
-)
-from selenium.webdriver.common.by import By
-
-# import InstaPy modules
-from .comment_util import open_comment_section
-from .constants import (
- MEDIA_ALL_TYPES,
- MEDIA_CAROUSEL,
- MEDIA_IGTV,
- MEDIA_PHOTO,
- MEDIA_VIDEO,
-)
-from .event import Event
-from .follow_util import get_following_status
-from .quota_supervisor import quota_supervisor
-from .time_util import sleep
-from .util import (
- add_user_to_blacklist,
- click_element,
- evaluate_mandatory_words,
- explicit_wait,
- extract_text_from_element,
- format_number,
- get_action_delay,
- get_additional_data,
- get_number_of_posts,
- is_page_available,
- is_private_profile,
- update_activity,
- web_address_navigator,
-)
-from .xpath import read_xpath
-
-
-def get_links_from_feed(browser, amount, num_of_search, logger):
- """Fetches random number of links from feed and returns a list of links"""
-
- feeds_link = "https://www.instagram.com/"
-
- # Check URL of the webpage, if it already is in Feeds page, then do not
- # navigate to it again
- web_address_navigator(browser, feeds_link)
-
- for i in range(num_of_search + 1):
- browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
- update_activity(browser, state=None)
- sleep(2)
-
- # get links
- link_elems = browser.find_elements(
- By.XPATH, read_xpath(get_links_from_feed.__name__, "get_links")
- )
-
- total_links = len(link_elems)
- logger.info("Total of links feched for analysis: {}".format(total_links))
- links = []
- try:
- if link_elems:
- links = [link_elem.get_attribute("href") for link_elem in link_elems]
- logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~")
- for i, link in enumerate(links):
- print(i, link)
- logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~")
-
- except BaseException as e:
- logger.error("link_elems error \n\t{}".format(str(e).encode("utf-8")))
-
- return links
-
-
-def get_main_element(browser, link_elems, skip_top_posts):
- main_elem = None
-
- if not link_elems:
- main_elem = browser.find_element(
- By.XPATH, read_xpath(get_links_for_location.__name__, "top_elements")
- )
- else:
- if skip_top_posts:
- main_elem = browser.find_element(
- By.XPATH, read_xpath(get_links_for_location.__name__, "main_elem")
- )
- else:
- main_elem = browser.find_element(By.TAG_NAME, "main")
-
- return main_elem
-
-
-def get_links_for_location(
- browser, location, amount, logger, media=None, skip_top_posts=True
-):
- """
- Fetches the number of links specified by amount and returns a list of links
- """
-
- if media is None:
- # All known media types
- media = MEDIA_ALL_TYPES
- elif media == MEDIA_PHOTO:
- # Include posts with multiple images in it
- media = [MEDIA_PHOTO, MEDIA_CAROUSEL]
- else:
- # Make it an array to use it in the following part
- media = [media]
-
- location_link = "https://www.instagram.com/explore/locations/{}".format(location)
- web_address_navigator(browser, location_link)
-
- top_elements = browser.find_element(
- By.XPATH, read_xpath(get_links_for_location.__name__, "top_elements")
- )
- top_posts = top_elements.find_elements(By.TAG_NAME, "a")
- sleep(1)
-
- if skip_top_posts:
- main_elem = browser.find_element(
- By.XPATH, read_xpath(get_links_for_location.__name__, "main_elem")
- )
- else:
- main_elem = browser.find_element(By.TAG_NAME, "main")
-
- link_elems = main_elem.find_elements(By.TAG_NAME, "a")
- sleep(1)
-
- if not link_elems: # this location does not have `Top Posts` or it
- # really is empty..
- main_elem = browser.find_element(
- By.XPATH, get_links_for_location.__name__, "top_elements"
- )
- top_posts = []
- sleep(2)
-
- try:
- possible_posts = browser.execute_script(
- "return window._sharedData.entry_data."
- "LocationsPage[0].graphql.location.edge_location_to_media.count"
- )
-
- except WebDriverException:
- logger.info(
- "Failed to get the amount of possible posts in '{}' "
- "location".format(location)
- )
- possible_posts = None
-
- logger.info(
- "desired amount: {} | top posts [{}]: {} | possible posts: "
- "{}".format(
- amount,
- "enabled" if not skip_top_posts else "disabled",
- len(top_posts),
- possible_posts,
- )
- )
-
- if possible_posts is not None:
- possible_posts = (
- possible_posts if not skip_top_posts else possible_posts - len(top_posts)
- )
- amount = possible_posts if amount > possible_posts else amount
- # sometimes pages do not have the correct amount of posts as it is
- # written there, it may be cos of some posts is deleted but still
- # keeps counted for the location
-
- # Get links
- links = get_links(browser, location, logger, media, main_elem)
- filtered_links = len(links)
- try_again = 0
- sc_rolled = 0
- nap = 1.5
- put_sleep = 0
- try:
- while filtered_links in range(1, amount):
- if sc_rolled > 100:
- logger.info("Scrolled too much! ~ sleeping a bit :>")
- sleep(600)
- sc_rolled = 0
-
- for i in range(3):
- browser.execute_script(
- "window.scrollTo(0, document.body.scrollHeight);"
- )
- update_activity(browser, state=None)
- sc_rolled += 1
- sleep(nap) # if not slept, and internet speed is low,
- # instagram will only scroll one time, instead of many times
- # you sent scroll command...
-
- sleep(3)
- links.extend(get_links(browser, location, logger, media, main_elem))
-
- links_all = links # uniqify links while preserving order
- s = set()
- links = []
- for i in links_all:
- if i not in s:
- s.add(i)
- links.append(i)
-
- if len(links) == filtered_links:
- try_again += 1
- nap = 3 if try_again == 1 else 5
- logger.info(
- "Insufficient amount of links ~ trying again: {}".format(try_again)
- )
- sleep(3)
-
- if try_again > 2: # you can try again as much as you want
- # by changing this number
- if put_sleep < 1 and filtered_links <= 21:
- logger.info(
- "Cor! Did you send too many requests? ~let's rest some"
- )
- sleep(600)
- put_sleep += 1
-
- browser.execute_script("location.reload()")
- update_activity(browser, state=None)
- try_again = 0
- sleep(10)
-
- main_elem = get_main_element(
- browser, link_elems, skip_top_posts
- )
- else:
- logger.info(
- "'{}' location POSSIBLY has less images than "
- "desired:{} found:{}...".format(
- location, amount, len(links)
- )
- )
- break
- else:
- filtered_links = len(links)
- try_again = 0
- nap = 1.5
- except Exception:
- raise
-
- sleep(4)
-
- return links[:amount]
-
-
-def get_links_for_tag(browser, tag, amount, skip_top_posts, randomize, media, logger):
- """
- Fetches the number of links specified by amount and returns a list of links
- """
-
- if media is None:
- # All known media types
- media = MEDIA_ALL_TYPES
- elif media == MEDIA_PHOTO:
- # Include posts with multiple images in it
- media = [MEDIA_PHOTO, MEDIA_CAROUSEL]
- else:
- # Make it an array to use it in the following part
- media = [media]
-
- tag = tag[1:] if tag[:1] == "#" else tag
-
- tag_link = "https://www.instagram.com/explore/tags/{}".format(tag)
- web_address_navigator(browser, tag_link)
-
- top_elements = browser.find_element(
- By.XPATH, read_xpath(get_links_for_tag.__name__, "top_elements")
- )
- top_posts = top_elements.find_elements(By.TAG_NAME, "a")
- sleep(1)
-
- if skip_top_posts:
- main_elem = browser.find_element(
- By.XPATH, read_xpath(get_links_for_tag.__name__, "main_elem")
- )
- else:
- main_elem = browser.find_element(By.TAG_NAME, "main")
- link_elems = main_elem.find_elements(By.TAG_NAME, "a")
- sleep(1)
-
- if not link_elems: # this tag does not have `Top Posts` or it really is
- # empty..
- main_elem = browser.find_element(
- By.XPATH, read_xpath(get_links_for_tag.__name__, "top_elements")
- )
- top_posts = []
- sleep(2)
-
- try:
- possible_posts = browser.execute_script(
- "return window._sharedData.entry_data."
- "TagPage[0].graphql.hashtag.edge_hashtag_to_media.count"
- )
-
- except WebDriverException:
- try:
- possible_posts = browser.find_element(
- By.XPATH, read_xpath(get_links_for_tag.__name__, "possible_post")
- ).text
- if possible_posts:
- possible_posts = format_number(possible_posts)
-
- else:
- logger.info(
- "Failed to get the amount of possible posts in '{}' tag "
- "~empty string".format(tag)
- )
- possible_posts = None
-
- except NoSuchElementException:
- logger.info(
- "Failed to get the amount of possible posts in {} tag".format(tag)
- )
- possible_posts = None
-
- if skip_top_posts:
- amount = amount + 9
-
- logger.info(
- "desired amount: {} | top posts [{}]: {} | possible posts: "
- "{}".format(
- amount,
- "enabled" if not skip_top_posts else "disabled",
- len(top_posts),
- possible_posts,
- )
- )
-
- if possible_posts is not None:
- amount = possible_posts if amount > possible_posts else amount
- # sometimes pages do not have the correct amount of posts as it is
- # written there, it may be cos of some posts is deleted but still keeps
- # counted for the tag
-
- # Get links
- links = get_links(browser, tag, logger, media, main_elem)
- filtered_links = len(links)
- try_again = 0
- sc_rolled = 0
- nap = 1.5
- put_sleep = 0
- try:
- while filtered_links in range(1, amount):
- if sc_rolled > 100:
- logger.info("Scrolled too much! ~ sleeping a bit :>")
- sleep(600)
- sc_rolled = 0
-
- for i in range(3):
- browser.execute_script(
- "window.scrollTo(0, document.body.scrollHeight);"
- )
- update_activity(browser, state=None)
- sc_rolled += 1
- sleep(nap) # if not slept, and internet speed is low,
- # instagram will only scroll one time, instead of many times
- # you sent scroll command...
-
- sleep(3)
- links.extend(get_links(browser, tag, logger, media, main_elem))
-
- links_all = links # uniqify links while preserving order
- s = set()
- links = []
- for i in links_all:
- if i not in s:
- s.add(i)
- links.append(i)
-
- if len(links) == filtered_links:
- try_again += 1
- nap = 3 if try_again == 1 else 5
- logger.info(
- "Insufficient amount of links ~ trying again: {}".format(try_again)
- )
- sleep(3)
-
- if try_again > 2: # you can try again as much as you want
- # by changing this number
- if put_sleep < 1 and filtered_links <= 21:
- logger.info(
- "Cor! Did you send too many requests? ~let's rest some"
- )
- sleep(600)
- put_sleep += 1
-
- browser.execute_script("location.reload()")
- update_activity(browser, state=None)
- try_again = 0
- sleep(10)
-
- main_elem = get_main_element(
- browser, link_elems, skip_top_posts
- )
- else:
- logger.info(
- "'{}' tag POSSIBLY has less images than "
- "desired:{} found:{}...".format(tag, amount, len(links))
- )
- break
- else:
- filtered_links = len(links)
- try_again = 0
- nap = 1.5
- except Exception:
- raise
-
- sleep(4)
-
- if skip_top_posts:
- del links[0:9]
-
- if randomize is True:
- random.shuffle(links)
-
- return links[:amount]
-
-
-def get_links_for_username(
- browser,
- username,
- person,
- amount,
- logger,
- logfolder,
- randomize=False,
- media=None,
- taggedImages=False,
-):
- """
- Fetches the number of links specified by amount and returns a list of links
- """
-
- if media is None:
- # All known media types
- media = MEDIA_ALL_TYPES
- elif media == MEDIA_PHOTO:
- # Include posts with multiple images in it
- media = [MEDIA_PHOTO, MEDIA_CAROUSEL]
- else:
- # Make it an array to use it in the following part
- media = [media]
-
- logger.info("Getting {} image list...".format(person))
-
- user_link = "https://www.instagram.com/{}/".format(person)
- if taggedImages:
- user_link = user_link + "tagged/"
-
- # if private user, we can get links only if we following
- following_status, _ = get_following_status(
- browser, "profile", username, person, None, logger, logfolder
- )
-
- # Check URL of the webpage, if it already is user's profile page,
- # then do not navigate to it again
- web_address_navigator(browser, user_link)
-
- if not is_page_available(browser, logger):
- logger.error(
- "Instagram error: The link you followed may be broken, or the "
- "page may have been removed..."
- )
- return False
-
- # if following_status is None:
- # browser.wait_for_valid_connection(browser, username, logger)
-
- # if following_status == 'Follow':
- # browser.wait_for_valid_authorization(browser, username, logger)
-
- is_private = is_private_profile(browser, logger, following_status == "Following")
-
- if (
- is_private is None
- or (is_private is True and following_status not in ["Following", True])
- or (following_status == "Blocked")
- ):
- logger.info(
- "This user is private and we are not following. '{}':'{}'".format(
- is_private, following_status
- )
- )
- return False
-
- # Get links
- links = []
- main_elem = browser.find_element(By.TAG_NAME, "article")
- posts_count = get_number_of_posts(browser)
- attempt = 0
-
- if posts_count is not None and amount > posts_count:
- logger.info(
- "You have requested to get {} posts from {}'s profile page but"
- " there only {} posts available :D".format(amount, person, posts_count)
- )
- amount = posts_count
-
- while len(links) < amount:
- initial_links = links
- browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
- # update server calls after a scroll request
- update_activity(browser, state=None)
- sleep(0.66)
-
- # using `extend` or `+=` results reference stay alive which affects
- # previous assignment (can use `copy()` for it)
- main_elem = browser.find_element(By.TAG_NAME, "article")
- links = links + get_links(browser, person, logger, media, main_elem)
- links = sorted(set(links), key=links.index)
-
- if len(links) == len(initial_links):
- if attempt >= 7:
- logger.info(
- "There are possibly less posts than {} in {}'s profile "
- "page!".format(amount, person)
- )
- break
- else:
- attempt += 1
- else:
- attempt = 0
-
- if randomize is True:
- random.shuffle(links)
-
- return links[:amount]
-
-
-def get_media_edge_comment_string(media):
- """AB test (Issue 3712) alters the string for media edge, this resolves it"""
- options = ["edge_media_to_comment", "edge_media_preview_comment"]
- for option in options:
- try:
- media[option]
- except KeyError:
- continue
- return option
-
-
-def check_link(
- browser,
- post_link,
- dont_like,
- mandatory_words,
- mandatory_language,
- mandatory_character,
- is_mandatory_character,
- check_character_set,
- ignore_if_contains,
- logger,
-):
- """
- Check the given link if it is appropriate
-
- :param browser: The selenium webdriver instance
- :param post_link:
- :param dont_like: hashtags of inappropriate phrases
- :param mandatory_words: words of appropriate phrases
- :param ignore_if_contains:
- :param logger: the logger instance
- :return: tuple of
- boolean: True if inappropriate,
- string: the username,
- boolean: True if it is video media,
- string: the message if inappropriate else 'None',
- string: set the scope of the return value
- """
-
- # Check URL of the webpage, if it already is post's page, then do not
- # navigate to it again
- web_address_navigator(browser, post_link)
-
- # Check if the Post is Valid/Exists
- post_page = get_additional_data(browser)
-
- if post_page is None:
- logger.warning("Unavailable Page: {}".format(post_link.encode("utf-8")))
- return True, None, None, "Unavailable Page", "Failure"
-
- # Gets the description of the post's link and checks for the dont_like tags
- graphql = "graphql" in post_page
- location_name = None
-
- if graphql:
- media = post_page["graphql"]["shortcode_media"]
- is_video = media["is_video"]
- user_name = media["owner"]["username"]
- image_text = media["edge_media_to_caption"]["edges"]
- image_text = image_text[0]["node"]["text"] if image_text else None
- location = media["location"]
- location_name = location["name"] if location else None
- media_edge_string = get_media_edge_comment_string(media)
- # Gets all comments on media
- comments = (
- media[media_edge_string]["edges"]
- if media[media_edge_string]["edges"]
- else None
- )
- owner_comments = ""
- # Concat all owner comments
- if comments is not None:
- for comment in comments:
- if comment["node"]["owner"]["username"] == user_name:
- owner_comments = owner_comments + "\n" + comment["node"]["text"]
-
- else:
- logger.info("post_page: {}".format(post_page))
- media = post_page[0]["shortcode_media"]
- is_video = media["is_video"]
- user_name = media["owner"]["username"]
- image_text = media["caption"]
- owner_comments = browser.execute_script(
- """
- latest_comments = window._sharedData.entry_data.PostPage[
- 0].media.comments.nodes;
- if (latest_comments === undefined) {
- latest_comments = Array();
- owner_comments = latest_comments
- .filter(item => item.user.username == arguments[0])
- .map(item => item.text)
- .reduce((item, total) => item + '\\n' + total, '');
- return owner_comments;}
- else {
- return null;}
- """,
- user_name,
- )
-
- if owner_comments == "":
- owner_comments = None
-
- # Append owner comments to description as it might contain further tags
- if image_text is None:
- image_text = owner_comments
-
- elif owner_comments:
- image_text = image_text + "\n" + owner_comments
-
- # If the image still has no description gets the first comment
- if image_text is None:
- if graphql:
- media_edge_string = get_media_edge_comment_string(media)
- image_text = media[media_edge_string]["edges"]
- image_text = image_text[0]["node"]["text"] if image_text else None
-
- else:
- image_text = media["comments"]["nodes"]
- image_text = image_text[0]["text"] if image_text else None
-
- if image_text is None:
- image_text = "No description"
-
- logger.info("Image from: {}".format(user_name.encode("utf-8")))
- logger.info("Image link: {}".format(post_link.encode("utf-8")))
- logger.info("Description: {}".format(image_text.encode("utf-8")))
-
- # Check if mandatory character set, before adding the location to the text
- if mandatory_language:
- if not check_character_set(image_text):
- return (
- True,
- user_name,
- is_video,
- "Mandatory language not fulfilled",
- "Not mandatory language",
- )
-
- # Append location to image_text so we can search through both in one go
- if location_name:
- logger.info("Location: {}".format(location_name.encode("utf-8")))
- image_text = image_text + "\n" + location_name
-
- if mandatory_words:
- if not evaluate_mandatory_words(image_text, mandatory_words):
- return (
- True,
- user_name,
- is_video,
- "Mandatory words not fulfilled",
- "Not mandatory likes",
- )
-
- image_text_lower = [x.lower() for x in image_text]
- ignore_if_contains_lower = [x.lower() for x in ignore_if_contains]
- if any((word in image_text_lower for word in ignore_if_contains_lower)):
- return False, user_name, is_video, "None", "Pass"
-
- dont_like_regex = []
-
- for dont_likes in dont_like:
- if dont_likes.startswith("#"):
- dont_like_regex.append(dont_likes + r"([^\d\w]|$)")
- elif dont_likes.startswith("["):
- dont_like_regex.append("#" + dont_likes[1:] + r"[\d\w]+([^\d\w]|$)")
- elif dont_likes.startswith("]"):
- dont_like_regex.append(r"#[\d\w]+" + dont_likes[1:] + r"([^\d\w]|$)")
- else:
- dont_like_regex.append(r"#[\d\w]*" + dont_likes + r"[\d\w]*([^\d\w]|$)")
-
- for dont_likes_regex in dont_like_regex:
- quash = re.search(dont_likes_regex, image_text, re.IGNORECASE)
- if quash:
- quashed = (
- (((quash.group(0)).split("#")[1]).split(" ")[0])
- .split("\n")[0]
- .encode("utf-8")
- ) # dismiss possible space and newlines
- iffy = (
- (re.split(r"\W+", dont_likes_regex))[3]
- if dont_likes_regex.endswith("*([^\\d\\w]|$)")
- else (re.split(r"\W+", dont_likes_regex))[1] # 'word' without format
- if dont_likes_regex.endswith("+([^\\d\\w]|$)")
- else (re.split(r"\W+", dont_likes_regex))[3] # '[word'
- if dont_likes_regex.startswith("#[\\d\\w]+")
- else (re.split(r"\W+", dont_likes_regex))[1] # ']word'
- ) # '#word'
- inapp_unit = 'Inappropriate! ~ contains "{}"'.format(
- quashed if iffy == quashed else '" in "'.join([str(iffy), str(quashed)])
- )
- return True, user_name, is_video, inapp_unit, "Undesired word"
-
- return False, user_name, is_video, "None", "Success"
-
-
-def like_image(browser, username, blacklist, logger, logfolder, total_liked_img):
- """Likes the browser opened image"""
- # check action availability
- if quota_supervisor("likes") == "jump":
- return False, "jumped"
-
- media = "Image" # by default
- like_xpath = read_xpath(like_image.__name__, "like")
- unlike_xpath = read_xpath(like_image.__name__, "unlike")
- play_xpath = read_xpath(like_image.__name__, "play")
-
- play_elem = browser.find_elements(By.XPATH, play_xpath)
- if len(play_elem) == 1:
- # This is because now IG is not only Images, User can share Images and
- # Videos in one post at the same time, it could be Image -> Video or
- # Video -> Image so we will try to Like the post like one object.
- media = "Video"
- comment = read_xpath(open_comment_section.__name__, "comment_elem")
- element = browser.find_element(By.XPATH, comment)
-
- # Now, move until 'Comment' section to determine the status of post
- # Notice that some videos comes from TikTok and could have larger size
- # c'est la vie...
- logger.info("--> Found 'Play' button for a video, trying to like it")
- browser.execute_script("arguments[0].scrollIntoView(true);", element)
-
- # find first for like element
- like_elem = browser.find_elements(By.XPATH, like_xpath)
-
- if len(like_elem) == 1:
- # sleep real quick right before clicking the element
- sleep(2)
- logger.info("--> {}...".format(media))
-
- like_elem = browser.find_elements(By.XPATH, like_xpath)
- if len(like_elem) > 0:
- click_element(browser, like_elem[0])
- # check now we have unlike instead of like
- liked_elem = browser.find_elements(By.XPATH, unlike_xpath)
-
- if len(liked_elem) == 1:
- logger.info("--> {} liked!".format(media))
- Event().liked(username)
- update_activity(
- browser, action="likes", state=None, logfolder=logfolder, logger=logger
- )
-
- if blacklist["enabled"] is True:
- action = "liked"
- add_user_to_blacklist(
- username, blacklist["campaign"], action, logger, logfolder
- )
-
- # get the post-like delay time to sleep
- naply = get_action_delay("like")
- sleep(naply)
-
- # after liking an image we do check if liking activity was blocked
- if not verify_liked_image(browser, logger):
- return False, "block on likes"
-
- return True, "success"
-
- else:
- # if like not seceded wait for 2 min
- logger.info(
- "--> {} was not able to get liked! maybe blocked?".format(media)
- )
- sleep(120)
-
- else:
- liked_elem = browser.find_elements(By.XPATH, unlike_xpath)
- if len(liked_elem) == 1:
- logger.info("--> {} already liked!".format(media))
- return False, "already liked"
-
- logger.info("--> Invalid Like Element!")
-
- return False, "invalid element"
-
-
-def verify_liked_image(browser, logger):
- """Check for a ban on likes using the last liked image"""
-
- browser.refresh()
- unlike_xpath = read_xpath(like_image.__name__, "unlike")
- like_elem = browser.find_elements(By.XPATH, unlike_xpath)
-
- if len(like_elem) == 1:
- return True
- else:
- logger.warning("--> Image was NOT liked! You have a BLOCK on likes!")
- return False
-
-
-def get_tags(browser, url):
- """Gets all the tags of the given description in the url"""
-
- # Check URL of the webpage, if it already is the one to be navigated,
- # then do not navigate to it again
- web_address_navigator(browser, url)
-
- additional_data = get_additional_data(browser)
- image_text = additional_data["graphql"]["shortcode_media"]["edge_media_to_caption"][
- "edges"
- ][0]["node"]["text"]
-
- if not image_text:
- image_text = ""
-
- tags = findall(r"#\w*", image_text)
-
- return tags
-
-
-def get_links(browser, page, logger, media, element):
- links = []
- post_href = None
-
- try:
- # Get image links in scope from hashtag, location and other pages
- link_elems = element.find_elements(By.XPATH, '//a[starts-with(@href, "/p/")]')
- sleep(random.randint(2, 5))
-
- if link_elems:
- for link_elem in link_elems:
- try:
- post_href = link_elem.get_attribute("href")
- post_elem = element.find_elements(
- By.XPATH,
- "//a[@href='/p/" + post_href.split("/")[-2] + "/']/child::div",
- )
-
- if len(post_elem) == 1 and MEDIA_PHOTO in media:
- logger.info("Found media type: {}".format(MEDIA_PHOTO))
- links.append(post_href)
-
- if len(post_elem) == 2:
- logger.info(
- "Found media type: {} - {} - {}".format(
- MEDIA_CAROUSEL, MEDIA_VIDEO, MEDIA_IGTV
- )
- )
- # If you see "Cannot detect post media type. Skip https://www.instagram.com/p/CFvUn0gpaMZ/"
- # consider updating the @class,'CzVzU', new format types could be added
- # Media types from constants.py must be updated here, otherwise the links
- # cannot be categorized.
- post_category = element.find_element(
- By.XPATH,
- "//a[@href='/p/"
- + post_href.split("/")[-2]
- + "/']/div[contains(@class,'CzVzU')]/child::*/*[name()='svg']",
- ).get_attribute("aria-label")
-
- logger.info("Post category: {}".format(post_category))
-
- if post_category in media:
- links.append(post_href)
-
- except WebDriverException:
- # If "post_href" is None skip the logger to avoid confusion,
- # the links that are not empty will be catched into the next
- # loop. Other case, the "post_href" is not empty and needs
- # to be displayed to the STDOUT for further review.
- if post_href:
- logger.info(
- "Cannot detect post media type. Skip {}".format(post_href)
- )
- else:
- logger.info("'{}' page does not contain a picture".format(page))
-
- except BaseException as e:
- logger.error("link_elems error \n\t{}".format(str(e).encode("utf-8")))
-
- # This block is intended to provide more information to the InstaPy user, they would like to
- # know why the Links cannot be "[Un]Liked", I would like to say that first check if the Media
- # Type is new, second check if the xpath has been updated and finally verify the acct is not
- # under a cold-down stage.
- # If the user can use the link outside InstaPy, they would know IG targeted the acct as
- # automated.
- for i, link in enumerate(links):
- logger.info("Links retrieved:: [{}/{}]".format(i + 1, link))
-
- return links
-
-
-def verify_liking(browser, maximum, minimum, logger):
- """Get the amount of existing existing likes and compare it against maximum
- & minimum values defined by user"""
-
- post_page = get_additional_data(browser)
- likes_count = post_page["graphql"]["shortcode_media"]["edge_media_preview_like"][
- "count"
- ]
-
- if not likes_count:
- likes_count = 0
-
- if maximum is not None and likes_count > maximum:
- logger.info(
- "Not liked this post! ~more likes exist off maximum limit at "
- "{}".format(likes_count)
- )
- return False
- elif minimum is not None and likes_count < minimum:
- logger.info(
- "Not liked this post! ~less likes exist off minimum limit "
- "at {}".format(likes_count)
- )
- return False
-
- return True
-
-
-def like_comment(browser, original_comment_text, logger):
- """Like the given comment"""
- comments_block_XPath = read_xpath(
- like_comment.__name__, "comments_block"
- ) # quite an efficient
- # location path
-
- try:
- comments_block = browser.find_elements(By.XPATH, comments_block_XPath)
- for comment_line in comments_block:
- comment_elem = comment_line.find_elements(By.TAG_NAME, "span")[0]
- comment = extract_text_from_element(comment_elem)
-
- if comment and (comment == original_comment_text):
- # find "Like" span (a direct child of Like button)
- span_like_elements = comment_line.find_elements(
- By.XPATH, read_xpath(like_comment.__name__, "span_like_elements")
- )
- if not span_like_elements:
- # this is most likely a liked comment
- return True, "success"
-
- # like the given comment
- span_like = span_like_elements[0]
- comment_like_button = span_like.find_element(
- By.XPATH, read_xpath(like_comment.__name__, "comment_like_button")
- )
- click_element(browser, comment_like_button)
-
- # verify if like succeeded by waiting until the like button
- # element goes stale..
- button_change = explicit_wait(
- browser, "SO", [comment_like_button], logger, 7, False
- )
-
- if button_change:
- logger.info("--> Liked the comment!")
- sleep(random.uniform(1, 2))
- return True, "success"
-
- else:
- logger.info("--> Unfortunately, comment was not liked.")
- sleep(random.uniform(0, 1))
- return False, "failure"
-
- except (NoSuchElementException, StaleElementReferenceException) as exc:
- logger.error(
- "Error occurred while liking a comment.\n\t{}".format(
- str(exc).encode("utf-8")
- )
- )
- return False, "error"
-
- return None, "unknown"
diff --git a/instapy/login_util.py b/instapy/login_util.py
deleted file mode 100644
index 4088dcc69..000000000
--- a/instapy/login_util.py
+++ /dev/null
@@ -1,706 +0,0 @@
-"""Module only used for the login part of the script"""
-# import built-in & third-party modules
-import json
-import os
-import pickle
-import random
-import socket
-
-# import exceptions
-from selenium.common.exceptions import (
- MoveTargetOutOfBoundsException,
- NoSuchElementException,
- WebDriverException,
-)
-from selenium.webdriver.common.action_chains import ActionChains
-from selenium.webdriver.common.by import By
-from selenium.webdriver.common.keys import Keys
-
-# import InstaPy modules
-from .time_util import sleep
-from .util import (
- check_authorization,
- click_element,
- explicit_wait,
- reload_webpage,
- update_activity,
- web_address_navigator,
-)
-from .xpath import read_xpath
-
-
-def bypass_suspicious_login(
- browser, logger, logfolder, bypass_security_challenge_using
-):
- """Bypass suspicious loggin attempt verification."""
-
- # close sign up Instagram modal if available
- dismiss_get_app_offer(browser, logger)
- dismiss_notification_offer(browser, logger)
- dismiss_this_was_me(browser)
-
- option = None
- if bypass_security_challenge_using == "sms":
- try:
- option = browser.find_element(
- By.XPATH,
- read_xpath(bypass_suspicious_login.__name__, "bypass_with_sms_option"),
- )
- except NoSuchElementException:
- logger.warning(
- "Unable to choose ({}) option to bypass the challenge".format(
- bypass_security_challenge_using.upper()
- )
- )
-
- if bypass_security_challenge_using == "email":
- try:
- option = browser.find_element(
- By.XPATH,
- read_xpath(
- bypass_suspicious_login.__name__, "bypass_with_email_option"
- ),
- )
- except NoSuchElementException:
- logger.warning(
- "Unable to choose ({}) option to bypass the challenge".format(
- bypass_security_challenge_using.upper()
- )
- )
-
- # click on your option
- (ActionChains(browser).move_to_element(option).click().perform())
- # next button click will miss the DOM reference for this element, so ->
- option_text = option.text
-
- # click on security code
- send_security_code_button = browser.find_element(
- By.XPATH,
- read_xpath(bypass_suspicious_login.__name__, "send_security_code_button"),
- )
- (ActionChains(browser).move_to_element(send_security_code_button).click().perform())
-
- # update server calls
- update_activity(browser, state=None)
-
- logger.info("Instagram detected an unusual login attempt")
- logger.info('Check Instagram App for "Suspicious Login attempt" prompt')
- logger.info("A security code was sent to your {}".format(option_text))
-
- security_code = None
- try:
- path = "{}state.json".format(logfolder)
- data = {}
- # check if file exists and has content
- if os.path.isfile(path) and os.path.getsize(path) > 0:
- # load JSON file
- with open(path, "r") as json_file:
- data = json.load(json_file)
-
- # update connection state
- security_code = data["challenge"]["security_code"]
- except Exception:
- logger.info("Security Code not present in {}state.json file".format(logfolder))
-
- if security_code is None:
- security_code = input("Type the security code here: ")
-
- security_code_field = browser.find_element(
- By.XPATH, read_xpath(bypass_suspicious_login.__name__, "security_code_field")
- )
-
- (
- ActionChains(browser)
- .move_to_element(security_code_field)
- .click()
- .send_keys(security_code)
- .perform()
- )
-
- # update server calls for both 'click' and 'send_keys' actions
- for _ in range(2):
- update_activity(browser, state=None)
-
- submit_security_code_button = browser.find_element(
- By.XPATH,
- read_xpath(bypass_suspicious_login.__name__, "submit_security_code_button"),
- )
-
- (
- ActionChains(browser)
- .move_to_element(submit_security_code_button)
- .click()
- .perform()
- )
-
- # update server calls
- update_activity(browser, state=None)
-
- try:
- sleep(3)
- # locate wrong security code message
- wrong_login = browser.find_element(
- By.XPATH, read_xpath(bypass_suspicious_login.__name__, "wrong_login")
- )
-
- if wrong_login is not None:
- wrong_login_msg = "Wrong security code! Please check the code Instagram sent you and try again."
- update_activity(
- browser,
- action=None,
- state=wrong_login_msg,
- logfolder=logfolder,
- logger=logger,
- )
- logger.warning(wrong_login_msg)
-
- except NoSuchElementException:
- # correct security code
- pass
-
-
-def check_browser(browser, logfolder, logger, proxy_address):
- # set initial state to offline
- update_activity(
- browser,
- action=None,
- state="trying to connect",
- logfolder=logfolder,
- logger=logger,
- )
-
- # check connection status
- try:
- logger.info("-- Connection Checklist [1/2] (Internet Connection Status)")
- browser.get("view-source:https://freegeoip.app/json")
- pre = browser.find_element(By.TAG_NAME, "pre").text
- current_ip_info = json.loads(pre)
- if (
- proxy_address is not None
- and socket.gethostbyname(proxy_address) != current_ip_info["ip"]
- ):
- logger.warning("- Proxy is set, but it's not working properly")
- logger.warning(
- '- Expected Proxy IP is "{}", and the current IP is "{}"'.format(
- proxy_address, current_ip_info["ip"]
- )
- )
- logger.warning("- Try again or disable the Proxy Address on your setup")
- logger.warning("- Aborting connection...")
- return False
- else:
- logger.info("- Internet Connection Status: ok")
- logger.info(
- '- Current IP is "{}" and it\'s from "{}/{}"'.format(
- current_ip_info["ip"],
- current_ip_info["country_name"],
- current_ip_info["country_code"],
- )
- )
- update_activity(
- browser,
- action=None,
- state="Internet connection is ok",
- logfolder=logfolder,
- logger=logger,
- )
- except Exception:
- logger.warning("- Internet Connection Status: error")
- update_activity(
- browser,
- action=None,
- state="There is an issue with the internet connection",
- logfolder=logfolder,
- logger=logger,
- )
- return False
-
- # check if hide-selenium extension is running
- logger.info("-- Connection Checklist [2/2] (Hide Selenium Extension)")
- webdriver = browser.execute_script("return window.navigator.webdriver")
- logger.info("- window.navigator.webdriver response: {}".format(webdriver))
- if webdriver:
- logger.warning("- Hide Selenium Extension: error")
- else:
- logger.info("- Hide Selenium Extension: ok")
-
- # everything is ok, then continue(True)
- return True
-
-
-def login_user(
- browser,
- username,
- password,
- logger,
- logfolder,
- proxy_address,
- security_code_to_phone,
- security_codes,
- want_check_browser,
-):
- """Logins the user with the given username and password"""
- assert username, "Username not provided"
- assert password, "Password not provided"
-
- # Hotfix - this check crashes more often than not -- plus in not necessary,
- # I can verify my own connection
- if want_check_browser:
- if not check_browser(browser, logfolder, logger, proxy_address):
- return False
-
- ig_homepage = "https://www.instagram.com"
- web_address_navigator(browser, ig_homepage)
-
- cookie_file = "{0}{1}_cookie.pkl".format(logfolder, username)
- cookie_loaded = None
- login_state = None
-
- # try to load cookie from username
- try:
- for cookie in pickle.load(open(cookie_file, "rb")):
- # SameSite = Strict, your cookie will only be sent in a
- # first-party context. In user terms, the cookie will only be sent
- # if the site for the cookie matches the site currently shown in
- # the browser's URL bar.
- if "sameSite" in cookie and cookie["sameSite"] == "None":
- cookie["sameSite"] = "Strict"
-
- browser.add_cookie(cookie)
-
- sleep(4)
- cookie_loaded = True
- logger.info("- Cookie file for user '{}' loaded...".format(username))
-
- # force refresh after cookie load or check_authorization() will FAIL
- reload_webpage(browser)
- sleep(4)
-
- # cookie has been LOADED, so the user SHOULD be logged in
- login_state = check_authorization(
- browser, username, "activity counts", logger, False
- )
- sleep(4)
-
- except (WebDriverException, OSError, IOError):
- # Just info the user, not an error
- logger.info("- Cookie file not found, creating cookie...")
-
- if login_state and cookie_loaded:
- # Cookie loaded and joined IG, dismiss following features if availables
- dismiss_notification_offer(browser, logger)
- dismiss_save_information(browser, logger)
- accept_igcookie_dialogue(browser, logger)
- return True
-
- # This fix comes from comment in #6060 If not necessary we can remove it
- accept_igcookie_dialogue(browser, logger)
-
- # if user is still not logged in, then there is an issue with the cookie
- # so go create a new cookie.
- if cookie_loaded:
- logger.warning(
- "- Issue with cookie for user '{}'. Creating new cookie...".format(username)
- )
-
- # Error could be faced due to " Cookie could not be loaded" or similar.
- # Session displayed we are in, but then a failure for the first
- # `login_elem` like the element is no longer attached to the DOM.
- # Saw this issue when session hasn't been used for a while; which means
- # "expiry" values in cookie are outdated.
- try:
- # Since having issues with the cookie a new one can be generated,
- # if cookie cannot be created or deleted stop execution.
- logger.info("- Deleting browser cookies...")
- browser.delete_all_cookies()
- browser.refresh()
- # Delete file from Filesystem if any issue with the cookie
- os.remove(cookie_file)
- sleep(random.randint(3, 5))
-
- except Exception as e:
- # NF: start
- if isinstance(e, WebDriverException):
- logger.exception(
- "Error occurred while deleting cookies from web browser!\n\t{}".format(
- str(e).encode("utf-8")
- )
- )
- return False
- # NF: end
-
- web_address_navigator(browser, ig_homepage)
-
- # Check if the first div is 'Create an Account' or 'Log In'
- try:
- login_elem = browser.find_element(
- By.XPATH, read_xpath(login_user.__name__, "login_elem")
- )
- except NoSuchElementException:
- logger.warning("Login A/B test detected! Trying another string...")
- try:
- login_elem = browser.find_element(
- By.XPATH,
- read_xpath(login_user.__name__, "login_elem_no_such_exception"),
- )
- except NoSuchElementException:
- logger.warning("Could not pass the login A/B test. Trying last string...")
- try:
- login_elem = browser.find_element(
- By.XPATH,
- read_xpath(login_user.__name__, "login_elem_no_such_exception_2"),
- )
- except NoSuchElementException as e:
- # NF: start
- logger.exception(
- "Login A/B test failed!\n\t{}".format(str(e).encode("utf-8"))
- )
- return False
- # NF: end
-
- if login_elem is not None:
- try:
- (ActionChains(browser).move_to_element(login_elem).click().perform())
- except MoveTargetOutOfBoundsException:
- login_elem.click()
-
- # update server calls
- update_activity(browser, state=None)
-
- # Enter username and password and logs the user in
- # Sometimes the element name isn't 'Username' and 'Password'
- # (valid for placeholder too)
-
- # wait until it navigates to the login page
- # 10/2020 -> "WebDriver:GetTitle" - {"value":"Instagram"}
- login_page_title = "Instagram"
- explicit_wait(browser, "TC", login_page_title, logger)
-
- # wait until the 'username' input element is located and visible
- input_username_XP = read_xpath(login_user.__name__, "input_username_XP")
- explicit_wait(browser, "VOEL", [input_username_XP, "XPath"], logger)
-
- # user
- input_username = browser.find_element(By.XPATH, input_username_XP)
-
- (
- ActionChains(browser)
- .move_to_element(input_username)
- .click()
- .send_keys(username)
- .perform()
- )
-
- # update server calls for both 'click' and 'send_keys' actions
- for _ in range(2):
- update_activity(browser, state=None)
-
- sleep(1)
-
- # password
- input_password = browser.find_element(
- By.XPATH, read_xpath(login_user.__name__, "input_password")
- )
-
- if not isinstance(password, str):
- password = str(password)
-
- (
- ActionChains(browser)
- .move_to_element(input_password)
- .click()
- .send_keys(password)
- .perform()
- )
-
- sleep(1)
-
- (
- ActionChains(browser)
- .move_to_element(input_password)
- .click()
- .send_keys(Keys.ENTER)
- .perform()
- )
-
- # update server calls for both 'click' and 'send_keys' actions
- for _ in range(4):
- update_activity(browser, state=None)
-
- # Check if account is protected with Two Factor Authentication
- two_factor_authentication(browser, logger, security_codes)
-
- # Dismiss following features if availables
- dismiss_get_app_offer(browser, logger)
- dismiss_notification_offer(browser, logger)
- dismiss_save_information(browser, logger)
-
- # IG: "Accept cookies from Instagram on this browser?"
- # They said that they're using cookies to help to personalize the content,
- # server relevant ads and provide safer experience.
- accept_igcookie_dialogue(browser, logger)
-
- # check for login error messages and display it in the logs
- if "instagram.com/challenge" in browser.current_url:
- # check if account is disabled by Instagram,
- # or there is an active challenge to solve
- try:
- account_disabled = browser.find_element(
- By.XPATH, read_xpath(login_user.__name__, "account_disabled")
- )
- logger.warning(account_disabled.text)
- update_activity(
- browser,
- action=None,
- state=account_disabled.text,
- logfolder=logfolder,
- logger=logger,
- )
- return False
- except NoSuchElementException:
- pass
-
- # in case the user doesnt have a phone number linked to the Instagram account
- try:
- browser.find_element(
- By.XPATH, read_xpath(login_user.__name__, "add_phone_number")
- )
- challenge_warn_msg = (
- "Instagram initiated a challenge before allow your account to login. "
- "At the moment there isn't a phone number linked to your Instagram "
- "account. Please, add a phone number to your account, and try again."
- )
- logger.warning(challenge_warn_msg)
- update_activity(
- browser,
- action=None,
- state=challenge_warn_msg,
- logfolder=logfolder,
- logger=logger,
- )
- return False
- except NoSuchElementException:
- pass
-
- # try to initiate security code challenge
- try:
- browser.find_element(
- By.XPATH, read_xpath(login_user.__name__, "suspicious_login_attempt")
- )
- update_activity(
- browser,
- action=None,
- state="Trying to solve suspicious attempt login",
- logfolder=logfolder,
- logger=logger,
- )
- bypass_suspicious_login(browser, logger, logfolder, security_code_to_phone)
- except NoSuchElementException:
- pass
-
- # check for wrong username or password message, and show it to the user
- try:
- error_alert = browser.find_element(
- By.XPATH, read_xpath(login_user.__name__, "error_alert")
- )
- logger.warning(error_alert.text)
- update_activity(
- browser,
- action=None,
- state=error_alert.text,
- logfolder=logfolder,
- logger=logger,
- )
- return False
- except NoSuchElementException:
- pass
-
- if "instagram.com/accounts/onetap" in browser.current_url:
- browser.get(ig_homepage)
-
- # wait until page fully load
- explicit_wait(browser, "PFL", [], logger, 5)
-
- # Check if user is logged-in (If there's two 'nav' elements)
- nav = browser.find_element(By.XPATH, read_xpath(login_user.__name__, "nav"))
- if nav is not None:
- # create cookie for username and save it
- cookies_list = browser.get_cookies()
-
- for cookie in cookies_list:
- if "sameSite" in cookie and cookie["sameSite"] == "None":
- cookie["sameSite"] = "Strict"
-
- try:
- # Open the cookie file to store the data
- with open(cookie_file, "wb") as cookie_f_handler:
- pickle.dump(cookies_list, cookie_f_handler)
-
- except pickle.PicklingError:
- # Next time, cookie will be created for the session so we are safe
- logger.warning("- Browser cookie list could not be saved to your local...")
-
- finally:
- return True
-
- else:
- return False
-
-
-def dismiss_get_app_offer(browser, logger):
- """Dismiss 'Get the Instagram App' page after a fresh login"""
- offer_elem = read_xpath(dismiss_get_app_offer.__name__, "offer_elem")
- dismiss_elem = read_xpath(dismiss_get_app_offer.__name__, "dismiss_elem")
-
- # wait a bit and see if the 'Get App' offer rises up
- offer_loaded = explicit_wait(
- browser, "VOEL", [offer_elem, "XPath"], logger, 5, False
- )
-
- if offer_loaded:
- dismiss_elem = browser.find_element(By.XPATH, dismiss_elem)
- click_element(browser, dismiss_elem)
-
-
-def dismiss_notification_offer(browser, logger):
- """Dismiss 'Turn on Notifications' offer on session start"""
- offer_elem_loc = read_xpath(dismiss_notification_offer.__name__, "offer_elem_loc")
- dismiss_elem_loc = read_xpath(
- dismiss_notification_offer.__name__, "dismiss_elem_loc"
- )
-
- # wait a bit and see if the 'Turn on Notifications' offer rises up
- offer_loaded = explicit_wait(
- browser, "VOEL", [offer_elem_loc, "XPath"], logger, 4, False
- )
-
- if offer_loaded:
- dismiss_elem = browser.find_element(By.XPATH, dismiss_elem_loc)
- click_element(browser, dismiss_elem)
-
-
-def dismiss_save_information(browser, logger):
- """Dismiss 'Save Your Login Info?' offer on session start"""
- # This question occurs when pkl doesn't exist
- offer_elem_loc = read_xpath(dismiss_save_information.__name__, "offer_elem_loc")
- dismiss_elem_loc = read_xpath(dismiss_save_information.__name__, "dismiss_elem_loc")
-
- offer_loaded = explicit_wait(
- browser, "VOEL", [offer_elem_loc, "XPath"], logger, 4, False
- )
-
- if offer_loaded:
- # When prompted chose "Not Now", we don't know if saving information
- # contributes or stimulate IG to target the acct, it would be better to
- # just pretend that we are using IG in different browsers.
- logger.info("- Do not save Login Info by now...")
- dismiss_elem = browser.find_element(By.XPATH, dismiss_elem_loc)
- click_element(browser, dismiss_elem)
-
-
-def dismiss_this_was_me(browser):
- try:
- # click on "This was me" button if challenge page was called
- this_was_me_button = browser.find_element(
- By.XPATH, read_xpath(dismiss_this_was_me.__name__, "this_was_me_button")
- )
- (ActionChains(browser).move_to_element(this_was_me_button).click().perform())
- # update server calls
- update_activity(browser, state=None)
- except NoSuchElementException:
- # no verification needed
- pass
-
-
-def two_factor_authentication(browser, logger, security_codes):
- """
- Check if account is protected with Two Factor Authentication codes
-
- Args:
- :browser: Web driver
- :logger: Library to log actions
- :security_codes: List of Two Factor Authentication codes, also named as Recovery Codes.
-
- Returns: None
- """
-
- # Wait until page is loaded after user and password were introduced
- sleep(random.randint(3, 5))
-
- if "two_factor" in browser.current_url:
-
- logger.info("- Two Factor Authentication is enabled...")
-
- # Chose one code from the security_codes list
- # 0000 is used if no codes were provided in constructor.
- code = random.choice(security_codes)
-
- try:
- # Check Security code is numeric
- int(code)
-
- verification_code = read_xpath(login_user.__name__, "verification_code")
- explicit_wait(browser, "VOEL", [verification_code, "XPath"], logger)
-
- security_code = browser.find_element(By.XPATH, verification_code)
-
- # Confirm blue button
- confirm = browser.find_element(
- By.XPATH, read_xpath(login_user.__name__, "confirm")
- )
-
- (
- ActionChains(browser)
- .move_to_element(security_code)
- .click()
- .send_keys(code)
- .perform()
- )
-
- sleep(random.randint(1, 3))
-
- (
- ActionChains(browser)
- .move_to_element(confirm)
- .click()
- .send_keys(Keys.ENTER)
- .perform()
- )
-
- # update server calls for both 'click' and 'send_keys' actions
- for _ in range(2):
- update_activity(browser, state=None)
-
- sleep(random.randint(1, 3))
-
- except NoSuchElementException as e:
- # Unable to login to Instagram!
- logger.warning(
- "- Secuirty code could not be written!\n\t{}".format(
- str(e).encode("utf-8")
- )
- )
- except ValueError:
- # Unable to login to Instagram!
- logger.warning("- Secuirty code provided is not a number")
- else:
- # Two Factor Authentication is not enabled or the security code has
- # already been entered in previous session.
- # Return None and login to Instagram!
- return
-
-
-def accept_igcookie_dialogue(browser, logger):
- """Presses 'Accept' button on IG cookie dialogue"""
-
- offer_elem_loc = read_xpath(accept_igcookie_dialogue.__name__, "accept_button")
-
- offer_loaded = explicit_wait(
- browser, "VOEL", [offer_elem_loc, "XPath"], logger, 4, False
- )
-
- if offer_loaded:
- logger.info("- Accepted IG cookies by default...")
- accept_elem = browser.find_element(By.XPATH, offer_elem_loc)
- click_element(browser, accept_elem)
diff --git a/instapy/monkey_patcher.py b/instapy/monkey_patcher.py
deleted file mode 100644
index bc509a86a..000000000
--- a/instapy/monkey_patcher.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from selenium.webdriver.common.action_chains import ActionChains
-
-
-def patch_move_to_element():
- """Patch move_to_element method in Class ActionChain"""
- ref_move_to_element = ActionChains.move_to_element
-
- def override_move_to_element(self, to_element):
- if "firefox" in self._driver.name:
- to_element.location_once_scrolled_into_view
- return self.__move_to_element(to_element)
-
- setattr(ActionChains, "__move_to_element", ref_move_to_element)
- setattr(ActionChains, "move_to_element", override_move_to_element)
-
-
-def patch_all():
- patch_move_to_element()
diff --git a/instapy/plugins/__init__.py b/instapy/plugins/__init__.py
deleted file mode 100644
index 860f0d5f3..000000000
--- a/instapy/plugins/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-# flake8: noqa
-"""plugins to the instapy library"""
-
-from .telegram_util import InstaPyTelegramBot
diff --git a/instapy/plugins/telegram_util.py b/instapy/plugins/telegram_util.py
deleted file mode 100644
index ce9d8f6d8..000000000
--- a/instapy/plugins/telegram_util.py
+++ /dev/null
@@ -1,379 +0,0 @@
-"""
-A fully functional TelegramBot to get info on an instapy run
-or to control the instapy bot
-
-you will need to create your token on the telegram app and speak with @botfather
-you will need to have a username (go to settings -> profile -> Username
-"""
-
-from ..util import truncate_float
-from telegram.ext import Updater
-from telegram.ext import CommandHandler
-from telegram.ext import MessageHandler
-from telegram.ext import Filters
-from telegram.error import (
- TelegramError,
- Unauthorized,
- BadRequest,
- TimedOut,
- ChatMigrated,
- NetworkError,
-)
-import logging
-import requests
-import os
-
-
-class InstaPyTelegramBot:
- """
- Class to handle the instapy telegram bot
- """
-
- def __init__(
- self,
- token="",
- telegram_username="",
- instapy_session=None,
- debug=True,
- proxy=None,
- ):
- # import pdb; pdb.set_trace()
- # private properties
- self.__logger = logging.getLogger()
- self.__chat_id = None
- self.__updater = None
- self.__context = None
-
- # public properties
- self.token = token
- self.telegram_username = telegram_username
- self.instapy_session = instapy_session
- self.debug = debug
- self.proxy = proxy
- # should be of type:
- # proxy = {
- # 'proxy_url': 'http://PROXY_HOST:PROXY_PORT/',
- # # Optional, if you need authentication:
- # 'username': 'PROXY_USER',
- # 'password': 'PROXY_PASS',
-
- # see if we have a pre-existing chat_id from another run
- if self.instapy_session is not None:
- try:
- telegramfile = open(
- "{}telegram_chat_id.txt".format(self.instapy_session.logfolder)
- )
- except OSError:
- self.__chat_id = None
- else:
- with telegramfile:
- self.__chat_id = telegramfile.read()
-
- # launch the telegram bot already if everything is ready at init
- if (
- (self.token != "")
- and (self.telegram_username != "")
- and (self.instapy_session is not None)
- ):
- self.telegram_bot()
-
- @property
- def debug(self):
- """
- the debug parameter
- :return:
- """
- return self._debug
-
- @debug.setter
- def debug(self, value):
- """
- sets the debug if needed
- :param debug:
- :return:
- """
- self._debug = value
- if self._debug is True:
- if self.__logger is None:
- self.__logger = logging.getLogger()
-
- self.__logger.setLevel(logging.DEBUG)
-
- def telegram_bot(self):
- """
- Function to initialize a telegram bot that you can talk to and control your InstaPy Bot
- :return:
- """
- if self.token == "":
- self.__logger.warning(
- "You need to set token for InstaPyTelegramBot to work"
- )
- return
- if self.telegram_username == "":
- self.__logger.warning(
- "You need to set telegram_username for InstaPyTelegramBot to work"
- )
- return
- if self.instapy_session is None:
- self.__logger.warning(
- "You need to set instapy_session for InstaPyTelegramBot to work"
- )
- return
-
- self._clean_web_hooks()
-
- if self.proxy is not None:
- updater = Updater(
- token=self.token,
- use_context=True,
- user_sig_handler=self.end,
- request_kwargs=self.proxy,
- )
- else:
- updater = Updater(
- token=self.token, use_context=True, user_sig_handler=self.end
- )
- self.__updater = updater
-
- dispatcher = updater.dispatcher
- self.__context = dispatcher
- dispatcher.add_error_handler(self._error_callback)
- start_handler = CommandHandler("start", self._start)
- dispatcher.add_handler(start_handler)
- report_handler = CommandHandler("report", self._report)
- dispatcher.add_handler(report_handler)
- report_handler = CommandHandler("stop", self._stop)
- dispatcher.add_handler(report_handler)
- unknown_handler = MessageHandler(Filters.command, self._unknown)
- dispatcher.add_handler(unknown_handler)
- updater.start_polling()
- if self.__chat_id is not None:
- # session was restored, send a message saying that instapy session is starting
- self.__context.bot.send_message(
- self.__chat_id, text="Telegram session restored, InstaPy starting\n"
- )
-
- def send_message(self, text=""):
- """
- function to be able to send messages from anywhere else in the instapy code
- :param text: the text of the message you want to send
- remember we cannot send_messages if we don't have the chat_id
- to get the chat_id, user has to send at little one /start to the bot
- :return:
- """
- if (self.__chat_id is None) and (self.__context is None):
- raise TelegramError
- else:
- self.__context.bot.send_message(chat_id=self.__chat_id, text=text)
-
- @staticmethod
- def telegram_delete_session(session):
- """
- function to force delete the telegram_chat_id.txt file that is in the logs folder
- :param session: the instapy session
- :return:
- """
- os.remove("{}telegram_chat_id.txt".format(session.logfolder))
-
- def _start(self, update, context):
- """
- basic /start function
- :param update:
- :param context:
- :return:
- """
- self.__chat_id = update.message.chat_id
- if self._check_authorized(update, context):
- with open(
- "{}telegram_chat_id.txt".format(self.instapy_session.logfolder), "w"
- ) as telegramfile:
- telegramfile.write(str(self.__chat_id))
-
- context.bot.send_message(
- chat_id=update.message.chat_id, text="Bot initialized successfully!\n"
- )
-
- def _report(self, update, context):
- """
- report live statistics
- :param update:
- :param context:
- :return:
- """
- self.__chat_id = update.message.chat_id
- if self._check_authorized(update, context):
- context.bot.send_message(
- chat_id=update.message.chat_id, text=self._live_report()
- )
-
- def _stop(self, update, context):
- """
- should stop the bot
- :param update:
- :param context:
- :return:
- """
- self.__chat_id = update.message.chat_id
- if self._check_authorized(update, context):
- self.instapy_session.aborting = True
- context.bot.send_message(
- chat_id=update.message.chat_id, text="InstaPy session abort set\n"
- )
-
- def _unknown(self, update, context):
- """
- trap all others commands as unknown
- :return:
- """
- if self._check_authorized(update, context):
- context.bot.send_message(
- chat_id=update.message.chat_id,
- text="Sorry I don't understand that command",
- )
- context.bot.send_message(
- chat_id=update.message.chat_id,
- text=" Recognized actions are:\n"
- + " - /start (initialize bot) \n"
- + " - /report (a live report from the bot)\n"
- + " - /stop (force stop the bot)\n",
- )
-
- def _check_authorized(self, update, context):
- """
- check if a user is authorized to use this bot
- :param update:
- :param context:
- :return:
- """
- if update.message.from_user.username != self.telegram_username:
- self.__logger.warning(
- "unauthorized access from {}".format(update.message.from_user)
- )
- context.bot.send_message(
- chat_id=update.message.chat_id,
- text="You are not authorized to use this service \n",
- )
- return False
- else:
- return True
-
- def _clean_web_hooks(self):
- """
- make sure no web_hooks are configured already otherwise telegram
- will respond 409
- :return:
- """
- r = requests.get(
- "https://api.telegram.org/bot{}/deleteWebhook".format(self.token)
- )
-
- if r.json()["ok"] is not True:
- self.__logger.warning("unable to remove webhook! Wrong token?")
-
- def _error_callback(self, update, error):
- try:
- raise error
- except Unauthorized:
- self.__logger.warning("TELEGRAM ERROR {} update={}".format(error, update))
- except BadRequest:
- # handle malformed requests - read more below!
- self.__logger.warning("TELEGRAM ERROR {} update={}".format(error, update))
- except TimedOut:
- # handle slow connection problems
- self.__logger.warning("TELEGRAM ERROR {} update={}".format(error, update))
- except NetworkError:
- # handle other connection problems
- self.__logger.warning("TELEGRAM ERROR {} update={}".format(error, update))
- except ChatMigrated as _:
- # the chat_id of a group has changed, use e.new_chat_id instead
- self.__logger.warning("TELEGRAM ERROR {} update={}".format(error, update))
- except TelegramError:
- self.__logger.warning("TELEGRAM ERROR {} update={}".format(error, update))
- # handle all other telegram related errors
-
- def _live_report(self):
- """
- adapted version of instapy live report function for showing up on a telegram message
- :return:
- """
- stats = [
- self.instapy_session.liked_img,
- self.instapy_session.already_liked,
- self.instapy_session.commented,
- self.instapy_session.followed,
- self.instapy_session.already_followed,
- self.instapy_session.unfollowed,
- self.instapy_session.stories_watched,
- self.instapy_session.reels_watched,
- self.instapy_session.inap_img,
- self.instapy_session.not_valid_users,
- ]
-
- sessional_run_time = self.instapy_session.run_time()
- run_time_info = (
- "{} seconds".format(sessional_run_time)
- if sessional_run_time < 60
- else "{} minutes".format(truncate_float(sessional_run_time / 60, 2))
- if sessional_run_time < 3600
- else "{} hours".format(truncate_float(sessional_run_time / 60 / 60, 2))
- )
- run_time_msg = "[Session lasted {}]".format(run_time_info)
-
- if any(stat for stat in stats):
- return (
- "Sessional Live Report:\n"
- "|> LIKED {} images\n"
- "|> ALREADY LIKED: {}\n"
- "|> COMMENTED on {} images\n"
- "|> FOLLOWED {} users\n"
- "|> ALREADY FOLLOWED: {}\n"
- "|> UNFOLLOWED {} users\n"
- "|> LIKED {} comments\n"
- "|> REPLIED to {} comments\n"
- "|> INAPPROPRIATE images: {}\n"
- "|> NOT VALID users: {}\n"
- "|> WATCHED {} story(ies)\n"
- "|> WATCHED {} reel(s)\n"
- "\n{}".format(
- self.instapy_session.liked_img,
- self.instapy_session.already_liked,
- self.instapy_session.commented,
- self.instapy_session.followed,
- self.instapy_session.already_followed,
- self.instapy_session.unfollowed,
- self.instapy_session.liked_comments,
- self.instapy_session.replied_to_comments,
- self.instapy_session.inap_img,
- self.instapy_session.not_valid_users,
- self.instapy_session.stories_watched,
- self.instapy_session.reels_watched,
- run_time_msg,
- )
- )
- else:
- return (
- "Sessional Live Report:\n"
- "|> No any statistics to show\n"
- "\n{}".format(run_time_msg)
- )
-
- def end(self):
- """
- tidy up things
- :return:
- """
- # keep the chat_id session for future reference
- # so we don't need to send a message each time InstaPy restart to the bot
- # and we can keep on getting messages when the sessions finishes
-
- # send one last message to the user reporting the session
- if (self.__chat_id is not None) and (self.__context is not None):
- self.__context.bot.send_message(
- chat_id=self.__chat_id, text=self._live_report()
- )
- self.__updater.stop()
- self.token = ""
- self.telegram_username = ""
- self.instapy_session = None
- self.__chat_id = None
- self.__context = None
diff --git a/instapy/pods_util.py b/instapy/pods_util.py
deleted file mode 100644
index 61807833d..000000000
--- a/instapy/pods_util.py
+++ /dev/null
@@ -1,221 +0,0 @@
-# import built-in & third-party modules
-import requests
-import sqlite3
-
-# import InstaPy modules
-from .settings import Settings
-from .database_engine import get_database
-
-# import exceptions
-
-
-def get_server_endpoint(topic):
- if topic == "fashion":
- return Settings.pods_fashion_server_endpoint
- elif topic == "food":
- return Settings.pods_food_server_endpoint
- elif topic == "travel":
- return Settings.pods_travel_server_endpoint
- elif topic == "sports":
- return Settings.pods_sports_server_endpoint
- elif topic == "entertainment":
- return Settings.pods_entertainment_server_endpoint
- else:
- return Settings.pods_server_endpoint
-
-
-def get_recent_posts_from_pods(topic, logger):
- """fetches all recent posts shared with pods"""
- params = {"topic": topic}
- r = requests.get(get_server_endpoint(topic) + "/getRecentPostsV1", params=params)
- try:
- logger.info("Downloaded postids from Pod {}:".format(topic))
- if r.status_code == 200:
- logger.info(r.json())
- return r.json()
- else:
- logger.error(r.text)
- return []
- except Exception as err:
- logger.error("Could not get postids from pod {} - {}".format(topic, err))
- return []
-
-
-def group_posts(posts, logger):
- no_comments_post_ids = []
- light_post_ids = []
- normal_post_ids = []
- heavy_post_ids = []
- for postobj in posts:
- try:
- if postobj["mode"] == "no_comments":
- no_comments_post_ids.append(postobj)
- elif postobj["mode"] == "light":
- light_post_ids.append(postobj)
- elif postobj["mode"] == "heavy":
- heavy_post_ids.append(postobj)
- else:
- normal_post_ids.append(postobj)
- except Exception as err:
- logger.error(
- "Failed with Error {}, please upgrade your instapy".format(err)
- )
- normal_post_ids.append(postobj)
- return no_comments_post_ids, light_post_ids, normal_post_ids, heavy_post_ids
-
-
-def share_my_post_with_pods(postid, topic, engagement_mode, logger):
- """share_my_post_with_pod"""
- params = {"postid": postid, "topic": topic, "mode": engagement_mode}
- r = requests.get(get_server_endpoint(topic) + "/publishMyLatestPost", params=params)
- try:
- logger.info("Publishing to Pods {}".format(postid))
- if r.status_code == 200:
- logger.info(r.text)
- return True
- else:
- logger.error(r.text)
- return False
- except Exception as err:
- logger.error(err)
- return False
-
-
-def share_with_pods_restriction(operation, postid, limit, logger):
- """Keep track of already shared posts"""
- conn = None
-
- try:
- # get a DB and start a connection
- db, id = get_database()
- conn = sqlite3.connect(db)
-
- with conn:
- conn.row_factory = sqlite3.Row
- cur = conn.cursor()
-
- cur.execute(
- "SELECT * FROM shareWithPodsRestriction WHERE profile_id=:id_var "
- "AND postid=:name_var",
- {"id_var": id, "name_var": postid},
- )
- data = cur.fetchone()
- share_data = dict(data) if data else None
-
- if operation == "write":
- if share_data is None:
- # write a new record
- cur.execute(
- "INSERT INTO shareWithPodsRestriction (profile_id, "
- "postid, times) VALUES (?, ?, ?)",
- (id, postid, 1),
- )
- else:
- # update the existing record
- share_data["times"] += 1
- sql = (
- "UPDATE shareWithPodsRestriction set times = ? WHERE "
- "profile_id=? AND postid = ?"
- )
- cur.execute(sql, (share_data["times"], id, postid))
-
- # commit the latest changes
- conn.commit()
-
- elif operation == "read":
- if share_data is None:
- return False
-
- elif share_data["times"] < limit:
- return False
-
- else:
- exceed_msg = "" if share_data["times"] == limit else "more than "
- logger.info(
- "--> {} has already been shared with pods {}{} times".format(
- postid, exceed_msg, str(limit)
- )
- )
- return True
-
- except Exception as exc:
- logger.error(
- "Dap! Error occurred with share Restriction:\n\t{}".format(
- str(exc).encode("utf-8")
- )
- )
-
- finally:
- if conn:
- # close the open connection
- conn.close()
-
-
-def comment_restriction(operation, postid, limit, logger):
- """Keep track of already shared posts"""
- conn = None
-
- try:
- # get a DB and start a connection
- db, id = get_database()
- conn = sqlite3.connect(db)
-
- with conn:
- conn.row_factory = sqlite3.Row
- cur = conn.cursor()
-
- cur.execute(
- "SELECT * FROM commentRestriction WHERE profile_id=:id_var "
- "AND postid=:name_var",
- {"id_var": id, "name_var": postid},
- )
- data = cur.fetchone()
- share_data = dict(data) if data else None
-
- if operation == "write":
- if share_data is None:
- # write a new record
- cur.execute(
- "INSERT INTO commentRestriction (profile_id, "
- "postid, times) VALUES (?, ?, ?)",
- (id, postid, 1),
- )
- else:
- # update the existing record
- share_data["times"] += 1
- sql = (
- "UPDATE commentRestriction set times = ? WHERE "
- "profile_id=? AND postid = ?"
- )
- cur.execute(sql, (share_data["times"], id, postid))
-
- # commit the latest changes
- conn.commit()
-
- elif operation == "read":
- if share_data is None:
- return False
-
- elif share_data["times"] < limit:
- return False
-
- else:
- exceed_msg = "" if share_data["times"] == limit else "more than "
- logger.info(
- "--> {} has been commented on {}{} times".format(
- postid, exceed_msg, str(limit)
- )
- )
- return True
-
- except Exception as exc:
- logger.error(
- "Dap! Error occurred with comment Restriction:\n\t{}".format(
- str(exc).encode("utf-8")
- )
- )
-
- finally:
- if conn:
- # close the open connection
- conn.close()
diff --git a/instapy/print_log_writer.py b/instapy/print_log_writer.py
deleted file mode 100644
index 6b1f7ecb3..000000000
--- a/instapy/print_log_writer.py
+++ /dev/null
@@ -1,97 +0,0 @@
-"""Module only used to log the number of followers to a file"""
-from datetime import datetime
-
-from .util import interruption_handler, getUserData
-from .util import web_address_navigator
-
-
-def get_log_time():
- """this method will keep same format for all recorded"""
- log_time = datetime.now().strftime("%Y-%m-%d %H:%M")
-
- return log_time
-
-
-def log_follower_num(browser, username, logfolder):
- """Prints and logs the current number of followers to
- a separate file"""
- user_link = "https://www.instagram.com/{}".format(username)
- web_address_navigator(browser, user_link)
-
- followed_by = getUserData("graphql.user.edge_followed_by.count", browser)
-
- with open("{}followerNum.txt".format(logfolder), "a") as numFile:
- numFile.write("{:%Y-%m-%d %H:%M} {}\n".format(datetime.now(), followed_by or 0))
-
- return followed_by
-
-
-def log_following_num(browser, username, logfolder):
- """Prints and logs the current number of followers to
- a separate file"""
- user_link = "https://www.instagram.com/{}".format(username)
- web_address_navigator(browser, user_link)
-
- following_num = getUserData("graphql.user.edge_follow.count", browser)
-
- with open("{}followingNum.txt".format(logfolder), "a") as numFile:
- numFile.write(
- "{:%Y-%m-%d %H:%M} {}\n".format(datetime.now(), following_num or 0)
- )
-
- return following_num
-
-
-def log_followed_pool(login, followed, logger, logfolder, logtime, user_id):
- """Prints and logs the followed to
- a separate file"""
- try:
- with open(
- "{0}{1}_followedPool.csv".format(logfolder, login), "a+"
- ) as followPool:
- with interruption_handler():
- followPool.write("{} ~ {} ~ {},\n".format(logtime, followed, user_id))
-
- except BaseException as e:
- logger.error("log_followed_pool error {}".format(str(e)))
-
- # We save all followed to a pool that will never be erase
- log_record_all_followed(login, followed, logger, logfolder, logtime, user_id)
-
-
-def log_uncertain_unfollowed_pool(login, person, logger, logfolder, logtime, user_id):
- """Prints and logs the uncertain unfollowed to
- a separate file"""
- try:
- with open(
- "{0}{1}_uncertain_unfollowedPool.csv".format(logfolder, login), "a+"
- ) as followPool:
- with interruption_handler():
- followPool.write("{} ~ {} ~ {},\n".format(logtime, person, user_id))
- except BaseException as e:
- logger.error("log_uncertain_unfollowed_pool error {}".format(str(e)))
-
-
-def log_record_all_unfollowed(login, unfollowed, logger, logfolder):
- """logs all unfollowed ever to
- a separate file"""
- try:
- with open(
- "{0}{1}_record_all_unfollowed.csv".format(logfolder, login), "a+"
- ) as followPool:
- with interruption_handler():
- followPool.write("{},\n".format(unfollowed))
- except BaseException as e:
- logger.error("log_record_all_unfollowed_pool error {}".format(str(e)))
-
-
-def log_record_all_followed(login, followed, logger, logfolder, logtime, user_id):
- """logs all followed ever to a pool that will never be erase"""
- try:
- with open(
- "{0}{1}_record_all_followed.csv".format(logfolder, login), "a+"
- ) as followPool:
- with interruption_handler():
- followPool.write("{} ~ {} ~ {},\n".format(logtime, followed, user_id))
- except BaseException as e:
- logger.error("log_record_all_followed_pool error {}".format(str(e)))
diff --git a/instapy/quota_supervisor.py b/instapy/quota_supervisor.py
deleted file mode 100644
index 985835df3..000000000
--- a/instapy/quota_supervisor.py
+++ /dev/null
@@ -1,424 +0,0 @@
-""" Realtime and sophisticated quota supervising mechanisms """
-import time as epoch_time
-from datetime import time, timedelta, date, datetime
-import random
-from sys import platform
-import sqlite3
-from plyer import notification
-from pkg_resources import resource_filename as get_pkg_resource_path
-
-from .time_util import sleep_actual
-from .time_util import get_time
-from .database_engine import get_database
-from .settings import Settings
-from .settings import Storage
-
-
-def quota_supervisor(job, update=False):
- """Supervise activity flow through action engines and take measures"""
- # --ACTION----------ENGINE--------------FILE--------------OPTION--- #
- # Like `like_image` [like_util.py] jump|sleep #
- # Comment `comment_image` [comment_util.py] jump|sleep #
- # Follow `follow_user` [unfollow_util.py] jump|sleep #
- # Unfollow `unfollow_user` [unfollow_util.py] jump|sleep #
- # *Server call `update_activity` [util.py] exit|sleep #
- # ----------------------------------------------------------------- #
-
- global configuration
- configuration = Settings.QS_config
-
- if configuration and configuration["state"] is True:
- # in-file global variables for the QS family
- global records, logger, this_minute, this_hour, today
-
- records = Storage.record_activity
- logger = Settings.logger
- this_minute, this_hour, today = get_time(["this_minute", "this_hour", "today"])
- if update: # update the action's record in global storage
- update_record(job)
-
- else: # inspect and control the action's availability
- quota_state = controller(job)
- return quota_state
-
-
-def controller(job):
- """Control and supervise"""
- if not records:
- load_records()
-
- sleep_after = configuration["sleep_after"]
- sleepyhead = configuration["sleepyhead"]
- notify = configuration["notify"]
- peaks = configuration["peaks"]
-
- if configuration["stochasticity"]["enabled"] is True:
- stochasticity(peaks)
-
- # inspect
- supervise, interval, target = inspector(job, peaks)
-
- if supervise:
- if (
- any(
- e in [job, job + ("_h" if interval == "hourly" else "_d")]
- for e in sleep_after
- )
- and target != "lc_extra"
- ):
- nap = remaining_time(sleepyhead, interval)
- send_message(job, "sleep", interval, nap)
-
- toast_notification(notify, "sleep", job, interval)
- sleep_actual(nap)
- toast_notification(notify, "wakeup", job, interval)
-
- else:
- if job == "server_calls":
- send_message(job, "exit", interval, None)
- toast_notification(notify, "exit", job, interval)
-
- logger.warning(
- "You're about to leave the session. " "InstaPy will exit soon!"
- )
- exit()
-
- else:
- send_message(job, "jump", interval, None)
- return "jump"
-
- return "available"
-
-
-def inspector(job, peaks):
- """Inspect action and return end result"""
- lc_extra_check_h, lc_extra_check_d = False, False
-
- hourly_peak = peaks[job]["hourly"]
- daily_peak = peaks[job]["daily"]
-
- # if like record exceeds its peak value, no comment will not also be sent
- if job == "comments":
- hourly_like_peak = peaks["likes"]["hourly"]
- daily_like_peak = peaks["likes"]["daily"]
-
- # interesting catch: use `>` instead of '>=' here :D
- if hourly_like_peak is not None:
- hourly_like_record = get_record("likes", "hourly")
- lc_extra_check_h = hourly_like_record > hourly_like_peak
-
- if daily_like_peak is not None:
- daily_like_record = get_record("likes", "daily")
- lc_extra_check_d = daily_like_record > daily_like_peak
-
- # inspect
- if hourly_peak is not None:
- hourly_record = get_record(job, "hourly")
-
- if hourly_record >= hourly_peak:
- return True, "hourly", "job"
-
- if daily_peak is not None:
- daily_record = get_record(job, "daily")
-
- if daily_record >= daily_peak:
- return True, "daily", "job"
-
- # extra like & comment inspection
- if lc_extra_check_h:
- return True, "hourly", "lc_extra"
-
- elif lc_extra_check_d:
- return True, "daily", "lc_extra"
-
- # inspection completed without a quotient breach
- return False, None, None
-
-
-def stochasticity(peaks):
- """Generate casually chosen arbitrary peak values based on originals
- set by the user"""
- # in future, stochasticity percentage can be added to th QS parameters
- # for users to define
- stoch_percent = random.randint(70, 85) # over 70, below 85 would be good
-
- orig_peaks = configuration["stochasticity"]["original_peaks"]
- latesttime = configuration["stochasticity"]["latesttime"]
- latesttime_h = latesttime["hourly"]
- latesttime_d = latesttime["daily"]
- realtime = epoch_time.time()
-
- # renew peak values at relative range just after an hour
- hourly_cycle = (realtime - latesttime_h) >= 3750
- # about ~one day (most people will not reach 86400 seconds, so, smaller
- # is better)
- daily_cycle = (realtime - latesttime_d) >= 27144
-
- if hourly_cycle or daily_cycle:
- # simplify 2 (possible) STEPs into 1 sequenced loop
- while hourly_cycle or daily_cycle:
- interval = "hourly" if hourly_cycle else "daily"
- stochast_values(peaks, orig_peaks, interval, stoch_percent)
- # update the latest time of value renewal in the given interval
- latesttime[interval] = epoch_time.time()
-
- if hourly_cycle:
- logger.info(
- "Quota Supervisor: just updated hourly peak rates in "
- "stochastic probablity!"
- )
- # turn off hourly cycle to avoid recycling
- hourly_cycle = False
-
- elif daily_cycle:
- logger.info(
- "Quota Supervisor: just updated daily peak rates in "
- "stochastic probablity!"
- )
- # turn off daily cycle to avoid recycling
- daily_cycle = False
-
-
-def stochast_values(peaks, orig_peaks, interval, percent):
- """Return randomly generated stochastic peak values"""
- for job in orig_peaks:
- job_data = orig_peaks[job]
-
- stochastic_peak = (
- None
- if job_data[interval] is None
- else stoch_randomizer(job_data[interval], percent)
- )
-
- # update the peaks object with a stochastic value for the given job
- peaks[job][interval] = stochastic_peak
-
-
-def stoch_randomizer(value, percent):
- """Value randomizer for stochastic flow"""
- stochastic_value = random.randint(int((value + 1) * percent / 100), value)
-
- return stochastic_value
-
-
-def remaining_time(sleepyhead, interval):
- """Calculate wake up time and return accurate or close-range random
- sleep seconds"""
- extra_sleep_percent = 140 # actually 114 also is not that bad amount
-
- if interval == "hourly":
- remaining_seconds = (61 - int(this_minute)) * 60
-
- elif interval == "daily":
- tomorrow = date.today() + timedelta(1)
- midnight = datetime.combine(tomorrow, time())
- now = datetime.now()
- remaining_seconds = (midnight - now).seconds
-
- if sleepyhead is True:
- remaining_seconds = random.randint(
- remaining_seconds, int(remaining_seconds * extra_sleep_percent / 100)
- )
-
- return remaining_seconds
-
-
-def send_message(job, action, interval, nap):
- """Send information messages about QS states"""
- job = job.replace("_", " ")
-
- if action == "sleep":
- if interval == "hourly":
- quick_drink = random.choice(
- [
- "lemon tea",
- "black tea",
- "green tea",
- "grey tea",
- "coffee mexicano",
- "coffee colombia",
- "fruit juice",
- ]
- )
- message = (
- "Quota Supervisor: hourly {} reached quotient!"
- "\t~going to sleep {} minutes long\n\ttake a {} "
- "break? :>".format(job, "%.0f" % (nap / 60), quick_drink)
- )
-
- elif interval == "daily":
- message = (
- "Quota Supervisor: daily {} reached quotient!"
- "\t~going to sleep {} hours long\n"
- "\ttime for InstaPy to take a big good nap :-)".format(
- job, "%.1f" % (nap / 60 / 60)
- )
- )
-
- elif action == "exit":
- message = (
- "Quota Supervisor: {} {} reached quotient!"
- "\t~exiting\n\tfor *non-stop botting use `sleep_after` "
- "parameter on the go! ;)".format(interval, job)
- )
-
- elif action == "jump":
- message = (
- "Quota Supervisor: jumped a {} out of {} quotient!\t~be fair "
- "with numbers :]\n".format(job[:-1], interval)
- )
-
- logger.info(message)
-
-
-def toast_notification(notify, alert, job, interval):
- """Send toast notifications about supervising states directly to OS
- using 'plyer' module"""
- platform_matches = platform.startswith(("win32", "linux", "darwin"))
- if notify is True and platform_matches:
- icons = get_icons()
- delay = 9 if alert == "exit" else 7
- label = job.replace("_", " ").capitalize()
-
- expr = (
- "Yawn! {} filled {} quotient!\t~falling asleep a little bit :>"
- if alert == "sleep"
- else "Yikes! {} just woke up from {} quotient bandage!\t~let's "
- "chill again wakey ;)"
- if alert == "wakeup"
- else "D'oh! {} finished {} quotient!\t~exiting ~,~"
- )
-
- try:
- notification.notify(
- title="Quota Supervisor",
- message=expr.format(label, interval),
- app_name="InstaPy",
- app_icon=icons[alert],
- timeout=delay,
- ticker="To switch supervising methods, please review "
- "quickstart script",
- )
-
- except Exception:
- # TypeError: out of 'plyer' bug in python 2 - INNER EXCEPTION
- # NotImplementedError: when 'plyer' is not supported
- # DBusException: dbus-display issue on linux boxes
-
- # turn off toast notification for the rest of the session
- configuration.update(notify=False)
-
-
-def get_icons():
- """Return the locations of icons according to the operating system"""
- # get full location of icons folder inside package
- icons_path = get_pkg_resource_path("instapy", "icons/")
-
- windows_ico = [
- "Windows/qs_sleep_windows.ico",
- "Windows/qs_wakeup_windows.ico",
- "Windows/qs_exit_windows.ico",
- ]
- linux_png = [
- "Linux/qs_sleep_linux.png",
- "Linux/qs_wakeup_linux.png",
- "Linux/qs_exit_linux.png",
- ]
- mac_icns = [
- "Mac/qs_sleep_mac.icns",
- "Mac/qs_wakeup_mac.icns",
- "Mac/qs_exit_mac.icns",
- ]
-
- # make it full path now
- windows_ico = [icons_path + icon for icon in windows_ico]
- linux_png = [icons_path + icon for icon in linux_png]
- mac_icns = [icons_path + icon for icon in mac_icns]
-
- (sleep_icon, wakeup_icon, exit_icon) = (
- windows_ico
- if platform.startswith("win32")
- else linux_png
- if platform.startswith("linux")
- else mac_icns
- if platform.startswith("darwin")
- else [None, None, None]
- )
-
- icons = {"sleep": sleep_icon, "wakeup": wakeup_icon, "exit": exit_icon}
-
- return icons
-
-
-def load_records():
- """Load the data from local DB file"""
- db, profile_id = get_database()
- conn = sqlite3.connect(db)
-
- # fetch live data from database
- with conn:
- conn.row_factory = sqlite3.Row
- cur = conn.cursor()
- cur.execute(
- "SELECT * FROM recordActivity "
- "WHERE profile_id=:var AND "
- "STRFTIME('%Y-%m-%d', created) == "
- "STRFTIME('%Y-%m-%d', 'now', 'localtime')",
- {"var": profile_id},
- )
- daily_data = cur.fetchall()
-
- if daily_data:
- ordered_data = {today: {}}
-
- # iterate over hourly rows and re-order data in the required structure
- for hourly_data in daily_data:
- hourly_data = tuple(hourly_data)
- hour = hourly_data[-1][-8:-6]
-
- ordered_data[today].update(
- {
- hour: {
- "likes": hourly_data[1],
- "comments": hourly_data[2],
- "follows": hourly_data[3],
- "unfollows": hourly_data[4],
- "server_calls": hourly_data[5],
- }
- }
- )
-
- # load data to the global storage
- records.update(ordered_data)
-
-
-def get_record(job, interval):
- """Quickly get and return daily or hourly records"""
- try:
- if interval == "hourly":
- record = records[today][this_hour][job]
-
- elif interval == "daily":
- record = sum(i[1][job] for i in list(records[today].items()))
-
- except KeyError:
- # record does not yet exist
- record = 0
-
- return record
-
-
-def update_record(job):
- """Update the corresponding record stored in the global Storage class"""
- # the order of the 2 conditional statements below is crucial
- if today not in records.keys():
- records.update({today: {this_hour: {}}})
-
- elif this_hour not in records[today].keys():
- records[today].update({this_hour: {}})
-
- # get live record
- live_rec = records[today][this_hour].get(job, 0) + 1
-
- # update records
- records[today][this_hour].update({job: live_rec})
diff --git a/instapy/relationship_tools.py b/instapy/relationship_tools.py
deleted file mode 100644
index 99ed38954..000000000
--- a/instapy/relationship_tools.py
+++ /dev/null
@@ -1,1350 +0,0 @@
-# import built-in & third-party modules
-import glob
-import json
-import os
-import random
-import time
-from datetime import datetime
-
-# import exceptions
-from selenium.common.exceptions import NoSuchElementException, WebDriverException
-from selenium.webdriver.common.by import By
-
-# import InstaPy modules
-from .follow_util import get_following_status
-from .time_util import sleep
-from .util import (
- get_relationship_counts,
- interruption_handler,
- is_private_profile,
- progress_tracker,
- truncate_float,
- web_address_navigator,
-)
-
-
-def get_followers(
- browser,
- self_username,
- username,
- grab,
- relationship_data,
- live_match,
- store_locally,
- logger,
- logfolder,
- verified_only=False,
-):
- """Get entire list of followers using graphql queries."""
-
- # Variables
- user_data = {}
- variables = {}
- all_followers = []
- sc_rolled = 0
- grab_notifier = False
- local_read_failure = False
- passed_time = "time loop"
-
- if username not in relationship_data:
- relationship_data.update({username: {"all_following": [], "all_followers": []}})
-
- grab_info = (
- 'at "full" range' if grab == "full" else "at the range of {}".format(grab)
- )
- tense = (
- "live"
- if (live_match is True or not relationship_data[username]["all_followers"])
- else "fresh"
- )
-
- logger.info(
- "Retrieving {} `Followers` data of {} {}".format(tense, username, grab_info)
- )
-
- user_link = "https://www.instagram.com/{}/".format(username)
- web_address_navigator(browser, user_link)
-
- # Get followers count
- followers_count, _ = get_relationship_counts(browser, username, logger)
-
- if grab != "full" and grab > followers_count:
- logger.info(
- "You have requested higher amount than existing followers count "
- " ~gonna grab all available"
- )
- grab = followers_count
-
- # Check if user's account is private and we don't follow
- following_status, _ = get_following_status(
- browser, "profile", self_username, username, None, logger, logfolder
- )
-
- is_private = is_private_profile(browser, logger, following_status == "Following")
-
- if not username == self_username and (
- is_private is None
- or (is_private is True and following_status not in ["Following", True])
- or (following_status == "Blocked")
- ):
- logger.info(
- "This user is private and we are not following. '{}':'{}'".format(
- is_private, following_status
- )
- )
- # Changed False to all_followers[], all_followers is empty
- return all_followers
-
- # sets the amount of usernames to be matched in the next queries
- match = (
- None
- if live_match is True
- else 10
- if relationship_data[username]["all_followers"]
- else None
- )
-
- # if there has been prior graphql query, use that existing data to speed
- # up querying time
- all_prior_followers = (
- relationship_data[username]["all_followers"] if match is not None else None
- )
-
- graphql_endpoint = "view-source:https://www.instagram.com/graphql/query/"
- graphql_followers = (
- graphql_endpoint + "?query_hash=37479f2b8209594dde7facb0d904896a"
- )
-
- try:
- user_data["id"] = browser.execute_script(
- "return window.__additionalData[Object.keys(window.__additionalData)[0]].data."
- "graphql.user.id"
- )
- except WebDriverException:
- user_data["id"] = browser.execute_script(
- "return window._sharedData.entry_data.ProfilePage[0].graphql.user.id"
- )
-
- variables["id"] = user_data["id"]
- variables["first"] = 50
-
- # get follower and user loop
- try:
- has_next_data = True
- filename = None
- graphql_queries = None
- query_date = None
-
- url = "{}&variables={}".format(graphql_followers, str(json.dumps(variables)))
- web_address_navigator(browser, url)
-
- # Get stored graphql queries data to be used
- try:
- filename = "{}graphql_queries.json".format(logfolder)
- query_date = datetime.today().strftime("%d-%m-%Y")
-
- if not os.path.isfile(filename):
- with interruption_handler():
- with open(filename, "w") as graphql_queries_file:
- json.dump(
- {username: {query_date: {"sc_rolled": 0}}},
- graphql_queries_file,
- )
- graphql_queries_file.close()
-
- # load the existing graphql queries data
- with open(filename) as graphql_queries_file:
- graphql_queries = json.load(graphql_queries_file)
- stored_usernames = list(name for name, date in graphql_queries.items())
-
- if username not in stored_usernames:
- graphql_queries[username] = {query_date: {"sc_rolled": 0}}
- stored_query_dates = list(
- date for date, score in graphql_queries[username].items()
- )
-
- if query_date not in stored_query_dates:
- graphql_queries[username][query_date] = {"sc_rolled": 0}
- except Exception as exc:
- logger.info(
- "Error occurred while getting `scroll` data from "
- "graphql_queries.json\n{}\n".format(str(exc).encode("utf-8"))
- )
- local_read_failure = True
-
- start_time = time.time()
- highest_value = followers_count if grab == "full" else grab
- # fetch all user while still has data
- while has_next_data:
- try:
- pre = browser.find_element(By.TAG_NAME, "pre").text
- except NoSuchElementException as exc:
- logger.info(
- "Encountered an error to find `pre` in page!"
- "\t~grabbed {} usernames \n\t{}".format(
- len(set(all_followers)), str(exc).encode("utf-8")
- )
- )
- return all_followers
-
- data = json.loads(pre)["data"]
-
- # get followers
- page_info = data["user"]["edge_followed_by"]["page_info"]
- edges = data["user"]["edge_followed_by"]["edges"]
- for user in edges:
- # If verified_only is True, determine if user is verified before adding to all_followers
- if verified_only:
- if user["node"]["is_verified"]:
- all_followers.append(user["node"]["username"])
- else:
- all_followers.append(user["node"]["username"])
-
- grabbed = len(set(all_followers))
-
- # write & update records at Progress Tracker
- progress_tracker(grabbed, highest_value, start_time, logger)
- print("\n")
-
- finish_time = time.time()
- diff_time = finish_time - start_time
- diff_n, diff_s = (
- (diff_time / 60 / 60, "hours")
- if diff_time / 60 / 60 >= 1
- else (diff_time / 60, "minutes")
- if diff_time / 60 >= 1
- else (diff_time, "seconds")
- )
- diff_n = truncate_float(diff_n, 2)
- passed_time = "{} {}".format(diff_n, diff_s)
-
- if match is not None:
- matched_followers = len(set(all_followers)) - len(
- set(all_followers) - set(all_prior_followers)
- )
- if matched_followers >= match:
- new_followers = set(all_followers) - set(all_prior_followers)
- all_followers = all_followers + all_prior_followers
- logger.info(
- "Grabbed {} new usernames from `Followers` in {} "
- "~total of {} usernames".format(
- len(set(new_followers)),
- passed_time,
- len(set(all_followers)),
- )
- )
- grab_notifier = True
- break
-
- if grab != "full" and grabbed >= grab:
- logger.info(
- "Grabbed {} usernames from `Followers` as requested at {}".format(
- grabbed, passed_time
- )
- )
- grab_notifier = True
- break
-
- has_next_data = page_info["has_next_page"]
- if has_next_data:
- variables["after"] = page_info["end_cursor"]
-
- url = "{}&variables={}".format(
- graphql_followers, str(json.dumps(variables))
- )
-
- web_address_navigator(browser, url)
- sc_rolled += 1
-
- # dump the current graphql queries data
- if local_read_failure is not True:
- try:
- with interruption_handler():
- with open(filename, "w") as graphql_queries_file:
- graphql_queries[username][query_date]["sc_rolled"] += 1
- json.dump(graphql_queries, graphql_queries_file)
- except Exception as exc:
- logger.info(
- "Error occurred while writing `scroll` data to "
- "graphql_queries.json\n{}\n".format(
- str(exc).encode("utf-8")
- )
- )
-
- # take breaks gradually
- if sc_rolled > 91:
- logger.info("Queried too much! ~ sleeping a bit :>")
- sleep(600)
- sc_rolled = 0
-
- except BaseException as exc:
- logger.info(
- "Unable to get `Followers` data:\n\t{}\n".format(str(exc).encode("utf-8"))
- )
-
- # remove possible duplicates
- all_followers = sorted(set(all_followers), key=lambda x: all_followers.index(x))
-
- if grab_notifier is False:
- logger.info(
- "Grabbed {} usernames from `Followers` in {}".format(
- len(all_followers), passed_time
- )
- )
-
- if len(all_followers) > 0:
- if (
- store_locally is True
- and relationship_data[username]["all_followers"] != all_followers
- ):
- store_followers_data(username, grab, all_followers, logger, logfolder)
- elif store_locally is True:
- logger.info(
- "The `Followers` data is identical with the data in previous "
- "query ~not storing the file again"
- )
-
- if grab == "full":
- relationship_data[username].update({"all_followers": all_followers})
-
- sleep_t = sc_rolled * 6
- sleep_t = sleep_t if sleep_t < 600 else random.randint(585, 655)
- sleep_n, sleep_s = (
- (sleep_t / 60, "minutes") if sleep_t / 60 >= 1 else (sleep_t, "seconds")
- )
- sleep_n = truncate_float(sleep_n, 4)
-
- logger.info(
- "Zz :[ time to take a good nap ~sleeping {} {}".format(sleep_n, sleep_s)
- )
- sleep(sleep_t)
- logger.info("Yawn :] let's go!\n")
-
- return all_followers
-
-
-def get_following(
- browser,
- self_username,
- username,
- grab,
- relationship_data,
- live_match,
- store_locally,
- logger,
- logfolder,
-):
- """Get entire list of following using graphql queries."""
-
- # Variables
- user_data = {}
- variables = {}
-
- if username not in relationship_data:
- relationship_data.update({username: {"all_following": [], "all_followers": []}})
-
- grab_info = (
- 'at "full" range' if grab == "full" else "at the range of {}".format(grab)
- )
- tense = (
- "live"
- if (live_match is True or not relationship_data[username]["all_following"])
- else "fresh"
- )
-
- logger.info(
- "Retrieving {} `Following` data of {} {}".format(tense, username, grab_info)
- )
-
- user_link = "https://www.instagram.com/{}/".format(username)
- web_address_navigator(browser, user_link)
-
- # Get following count
- _, following_count = get_relationship_counts(browser, username, logger)
-
- if grab != "full" and grab > following_count:
- logger.info(
- "You have requested higher amount than existing following count "
- " ~gonna grab all available"
- )
- grab = following_count
-
- # Check if user's account is private and we don't follow
- following_status, _ = get_following_status(
- browser, "profile", self_username, username, None, logger, logfolder
- )
-
- is_private = is_private_profile(browser, logger, following_status == "Following")
- if not username == self_username and (
- is_private is None
- or (is_private is True and following_status not in ["Following", True])
- or (following_status == "Blocked")
- ):
- logger.info(
- "This user is private and we are not following. '{}':'{}'".format(
- is_private, following_status
- )
- )
- return False
-
- # sets the amount of usernames to be matched in the next queries
- match = (
- None
- if live_match is True
- else 10
- if relationship_data[username]["all_following"]
- else None
- )
-
- # if there has been prior graphql query, use that existing data to speed
- # up querying time
- all_prior_following = (
- relationship_data[username]["all_following"] if match is not None else None
- )
-
- # FIXME: use util.py:get_query_hash to get the hash code
- graphql_endpoint = "view-source:https://www.instagram.com/graphql/query/"
-
- graphql_following = (
- graphql_endpoint + "?query_hash=58712303d941c6855d4e888c5f0cd22f"
- )
-
- try:
- user_data["id"] = browser.execute_script(
- "return window.__additionalData[Object.keys(window.__additionalData)[0]].data."
- "graphql.user.id"
- )
- except WebDriverException:
- user_data["id"] = browser.execute_script(
- "return window._sharedData.entry_data.ProfilePage[0].graphql.user.id"
- )
-
- variables["id"] = user_data["id"]
- variables["first"] = 50
-
- # get follower and user loop
-
- sc_rolled = 0
- grab_notifier = False
- local_read_failure = False
- passed_time = "time loop"
- all_following = []
-
- try:
- filename = None
- query_date = None
- graphql_queries = None
- has_next_data = True
-
- url = "{}&variables={}".format(graphql_following, str(json.dumps(variables)))
- web_address_navigator(browser, url)
-
- # Get stored graphql queries data to be used
- try:
- filename = "{}graphql_queries.json".format(logfolder)
- query_date = datetime.today().strftime("%d-%m-%Y")
- if not os.path.isfile(filename):
- with interruption_handler():
- with open(filename, "w") as graphql_queries_file:
- json.dump(
- {username: {query_date: {"sc_rolled": 0}}},
- graphql_queries_file,
- )
- graphql_queries_file.close()
-
- # Loads the existing graphql queries data
- with open(filename) as graphql_queries_file:
- graphql_queries = json.load(graphql_queries_file)
- stored_usernames = list(name for name, date in graphql_queries.items())
- if username not in stored_usernames:
- graphql_queries[username] = {query_date: {"sc_rolled": 0}}
- stored_query_dates = list(
- date for date, score in graphql_queries[username].items()
- )
- if query_date not in stored_query_dates:
- graphql_queries[username][query_date] = {"sc_rolled": 0}
- except Exception as exc:
- logger.info(
- "Error occurred while getting `scroll` data from "
- "graphql_queries.json\n{}\n".format(str(exc).encode("utf-8"))
- )
- local_read_failure = True
-
- start_time = time.time()
- highest_value = following_count if grab == "full" else grab
- # fetch all user while still has data
- while has_next_data:
- try:
- pre = browser.find_element(By.TAG_NAME, "pre").text
- except NoSuchElementException as exc:
- logger.info(
- "Encountered an error to find `pre` in page!"
- "\t~grabbed {} usernames \n\t{}".format(
- len(set(all_following)), str(exc).encode("utf-8")
- )
- )
- return all_following
-
- data = json.loads(pre)["data"]
-
- # get following
- page_info = data["user"]["edge_follow"]["page_info"]
- edges = data["user"]["edge_follow"]["edges"]
- for user in edges:
- all_following.append(user["node"]["username"])
-
- grabbed = len(set(all_following))
-
- # write & update records at Progress Tracker
- progress_tracker(grabbed, highest_value, start_time, logger)
- print("\n")
-
- finish_time = time.time()
- diff_time = finish_time - start_time
- diff_n, diff_s = (
- (diff_time / 60 / 60, "hours")
- if diff_time / 60 / 60 >= 1
- else (diff_time / 60, "minutes")
- if diff_time / 60 >= 1
- else (diff_time, "seconds")
- )
- diff_n = truncate_float(diff_n, 2)
- passed_time = "{} {}".format(diff_n, diff_s)
-
- if match is not None:
- matched_following = len(set(all_following)) - len(
- set(all_following) - set(all_prior_following)
- )
- if matched_following >= match:
- new_following = set(all_following) - set(all_prior_following)
- all_following = all_following + all_prior_following
- logger.info(
- "Grabbed {} new usernames from `Following` in {} "
- "~total of {} usernames".format(
- len(set(new_following)),
- passed_time,
- len(set(all_following)),
- )
- )
- grab_notifier = True
- break
-
- if grab != "full" and grabbed >= grab:
- logger.info(
- "Grabbed {} usernames from `Following` as requested at {}".format(
- grabbed, passed_time
- )
- )
- grab_notifier = True
- break
-
- has_next_data = page_info["has_next_page"]
- if has_next_data:
- variables["after"] = page_info["end_cursor"]
-
- url = "{}&variables={}".format(
- graphql_following, str(json.dumps(variables))
- )
-
- web_address_navigator(browser, url)
- sc_rolled += 1
-
- # dumps the current graphql queries data
- if local_read_failure is not True:
- try:
- with interruption_handler():
- with open(filename, "w") as graphql_queries_file:
- graphql_queries[username][query_date]["sc_rolled"] += 1
- json.dump(graphql_queries, graphql_queries_file)
- except Exception as exc:
- logger.info(
- "Error occurred while writing `scroll` data to "
- "graphql_queries.json\n{}\n".format(
- str(exc).encode("utf-8")
- )
- )
-
- # take breaks gradually
- if sc_rolled > 91:
- logger.info("Queried too much! ~ sleeping a bit :>")
- sleep(600)
- sc_rolled = 0
-
- except BaseException as exc:
- logger.info(
- "Unable to get `Following` data:\n\t{}\n".format(str(exc).encode("utf-8"))
- )
-
- # remove possible duplicates
- all_following = sorted(set(all_following), key=lambda x: all_following.index(x))
-
- if grab_notifier is False:
- logger.info(
- "Grabbed {} usernames from `Following` in {}".format(
- len(all_following), passed_time
- )
- )
-
- if len(all_following) > 0:
- if (
- store_locally is True
- and relationship_data[username]["all_following"] != all_following
- ):
- store_following_data(username, grab, all_following, logger, logfolder)
- elif store_locally is True:
- logger.info(
- "The `Following` data is identical with the data in previous "
- "query ~not storing the file again"
- )
-
- if grab == "full":
- relationship_data[username].update({"all_following": all_following})
-
- sleep_t = sc_rolled * 6
- sleep_t = sleep_t if sleep_t < 600 else random.randint(585, 655)
- sleep_n, sleep_s = (
- (sleep_t / 60, "minutes") if sleep_t / 60 >= 1 else (sleep_t, "seconds")
- )
- sleep_n = truncate_float(sleep_n, 4)
-
- logger.info(
- "Zz :[ time to take a good nap ~sleeping {} {}".format(sleep_n, sleep_s)
- )
- sleep(sleep_t)
- logger.info("Yawn :] let's go!\n")
-
- return all_following
-
-
-def get_unfollowers(
- browser,
- self_username,
- username,
- compare_by,
- compare_track,
- relationship_data,
- live_match,
- store_locally,
- print_out,
- logger,
- logfolder,
-):
- if compare_by not in ["latest", "day", "month", "year", "earliest"]:
- logger.info(
- "Please choose a valid compare point to pick Unfollowers "
- "~leaving out of an invalid value"
- )
- return [], []
-
- elif compare_track not in ["first", "median", "last"]:
- logger.info(
- "Please choose a valid compare track to pick Unfollowers "
- "~leaving out of an invalid value"
- )
- return [], []
-
- elif username is None or not isinstance(username, str):
- logger.info(
- "Please enter a username to pick Unfollowers ~leaving out of an "
- "invalid value"
- )
- return [], []
-
- prior_followers, selected_filename = load_followers_data(
- username, compare_by, compare_track, logger, logfolder
- )
-
- if not prior_followers and selected_filename is None:
- logger.info(
- "Generate `Followers` data to find Unfollowers in future! "
- "~couldn't pick Unfollowers"
- )
- return [], []
-
- current_followers = get_followers(
- browser,
- self_username,
- username,
- "full",
- relationship_data,
- live_match,
- store_locally,
- logger,
- logfolder,
- )
-
- # if current_followers is False we have targeted a private account that we don't follow
- if not current_followers:
- return False, False
-
- all_unfollowers = [
- follower for follower in prior_followers if follower not in current_followers
- ]
-
- if len(all_unfollowers) > 0:
- current_following = get_following(
- browser,
- self_username,
- username,
- "full",
- relationship_data,
- live_match,
- store_locally,
- logger,
- logfolder,
- )
-
- active_unfollowers = [
- unfollower
- for unfollower in current_following
- if unfollower in all_unfollowers
- ]
-
- logger.info(
- "Unfollowers found from {}! total: {} | active: {} "
- ":|\n".format(
- selected_filename, len(all_unfollowers), len(active_unfollowers)
- )
- )
- if store_locally is True:
- # store all Unfollowers in a local file
- store_all_unfollowers(username, all_unfollowers, logger, logfolder)
- # store active Unfollowers in a local file
- store_active_unfollowers(username, active_unfollowers, logger, logfolder)
-
- if print_out is True:
- logger.info(
- "Unfollowers of {}:\n\n\tAll Unfollowers: {}\n\n\tActive "
- "Unfollowers: {}\n".format(
- username, all_unfollowers, active_unfollowers
- )
- )
- else:
- logger.info(
- "Yay! You have no any Unfollowers from {}! ^v^".format(selected_filename)
- )
- return [], []
-
- return all_unfollowers, active_unfollowers
-
-
-def get_nonfollowers(
- browser,
- self_username,
- username,
- relationship_data,
- live_match,
- store_locally,
- logger,
- logfolder,
-):
- """Finds Nonfollowers of a given user"""
-
- if username is None or not isinstance(username, str):
- logger.info(
- "Please enter a username to pick Nonfollowers ~leaving out of "
- "an invalid value"
- )
- return []
-
- # get `Followers` data
- all_followers = get_followers(
- browser,
- self_username,
- username,
- "full",
- relationship_data,
- live_match,
- store_locally,
- logger,
- logfolder,
- )
-
- # if all_followers is False we have targeted a private account that we don't follow
- if not all_followers:
- return False
-
- # get `Following` data
- all_following = get_following(
- browser,
- self_username,
- username,
- "full",
- relationship_data,
- live_match,
- store_locally,
- logger,
- logfolder,
- )
-
- # using this approach we can preserve the order of elements to be used
- # with `FIFO`, `LIFO` or `RANDOM` styles
- nonfollowers = [user for user in all_following if user not in all_followers]
-
- # uniqify elements
- nonfollowers = sorted(set(nonfollowers), key=nonfollowers.index)
-
- logger.info(
- "There are {0} Nonfollowers of {1} ~the users {1} is following WHO "
- "do not follow back\n".format(len(nonfollowers), username)
- )
-
- # store Nonfollowers' data in a local file
- store_nonfollowers(
- username,
- len(all_followers),
- len(all_following),
- nonfollowers,
- logger,
- logfolder,
- )
-
- return nonfollowers
-
-
-def get_fans(
- browser,
- self_username,
- username,
- relationship_data,
- live_match,
- store_locally,
- logger,
- logfolder,
-):
- """Find Fans of a given user"""
-
- if username is None or not isinstance(username, str):
- logger.info(
- "Please enter a username to pick Fans ~leaving out of an invalid value"
- )
- return []
-
- # get `Followers` data
- all_followers = get_followers(
- browser,
- self_username,
- username,
- "full",
- relationship_data,
- live_match,
- store_locally,
- logger,
- logfolder,
- )
-
- # if all_followers is False we have targeted a private account that we don't follow
- if not all_followers:
- return False
-
- # get `Following` data
- all_following = get_following(
- browser,
- self_username,
- username,
- "full",
- relationship_data,
- live_match,
- store_locally,
- logger,
- logfolder,
- )
-
- # using this approach we can preserve the order of elements to be used
- # with `FIFO`, `LIFO` or `RANDOM` styles
- fans = [user for user in all_followers if user not in all_following]
-
- # uniqify elements
- fans = sorted(set(fans), key=fans.index)
-
- logger.info(
- "There are {0} Fans of {1} ~the users following {1} WHOM {1} does "
- "not follow back\n".format(len(fans), username)
- )
-
- # store Nonfollowers data in a local file
- store_fans(
- username, len(all_followers), len(all_following), fans, logger, logfolder
- )
-
- return fans
-
-
-def get_mutual_following(
- browser,
- self_username,
- username,
- relationship_data,
- live_match,
- store_locally,
- logger,
- logfolder,
-):
- """Find Mutual Following of a given user"""
-
- if username is None or type(username) != str:
- logger.info(
- "Please enter a username to pick Mutual Following ~leaving out "
- "of an invalid value"
- )
- return []
-
- # get `Followers` data
- all_followers = get_followers(
- browser,
- self_username,
- username,
- "full",
- relationship_data,
- live_match,
- store_locally,
- logger,
- logfolder,
- )
-
- # if all_followers is False we have targeted a private account that we don't follow
- if not all_followers:
- return False
-
- # get `Following` data
- all_following = get_following(
- browser,
- self_username,
- username,
- "full",
- relationship_data,
- live_match,
- store_locally,
- logger,
- logfolder,
- )
-
- # using this approach we can preserve the order of elements to be used
- # with `FIFO`, `LIFO` or `RANDOM` styles
- mutual_following = [user for user in all_following if user in all_followers]
-
- # uniqify elements
- mutual_following = sorted(set(mutual_following), key=mutual_following.index)
-
- logger.info(
- "There are {0} Mutual Following of {1} ~the users {1} is following "
- "WHO also follow back\n".format(len(mutual_following), username)
- )
-
- # store Mutual Following data in a local file
- store_mutual_following(
- username,
- len(all_followers),
- len(all_following),
- mutual_following,
- logger,
- logfolder,
- )
-
- return mutual_following
-
-
-def store_followers_data(username, grab, grabbed_followers, logger, logfolder):
- """Store grabbed `Followers` data in a local storage at generated date"""
- query_date = datetime.today().strftime("%d-%m-%Y")
- grabbed_followers_size = len(grabbed_followers)
- file_directory = "{}/relationship_data/{}/followers/".format(logfolder, username)
- file_name = "{}{}~{}~{}".format(
- file_directory, query_date, grab, grabbed_followers_size
- )
- file_index = 0
- final_file = "{}.json".format(file_name)
-
- try:
- if not os.path.exists(file_directory):
- os.makedirs(file_directory)
- # this loop provides unique data files
- while os.path.isfile(final_file):
- file_index += 1
- final_file = "{}({}).json".format(file_name, file_index)
-
- with open(final_file, "w") as followers_data:
- with interruption_handler():
- json.dump(grabbed_followers, followers_data)
- logger.info("Stored `Followers` data at {} local file".format(final_file))
-
- except Exception as exc:
- logger.info(
- "Failed to store `Followers` data in a local file :Z\n{}".format(
- str(exc).encode("utf-8")
- )
- )
-
-
-def store_following_data(username, grab, grabbed_following, logger, logfolder):
- """Store grabbed `Following` data in a local storage at generated date"""
- query_date = datetime.today().strftime("%d-%m-%Y")
- grabbed_following_size = len(grabbed_following)
- file_directory = "{}/relationship_data/{}/following/".format(logfolder, username)
- file_name = "{}{}~{}~{}".format(
- file_directory, query_date, grab, grabbed_following_size
- )
- file_index = 0
- final_file = "{}.json".format(file_name)
-
- try:
- if not os.path.exists(file_directory):
- os.makedirs(file_directory)
- # this loop provides unique data files
- while os.path.isfile(final_file):
- file_index += 1
- final_file = "{}({}).json".format(file_name, file_index)
-
- with open(final_file, "w") as following_data:
- with interruption_handler():
- json.dump(grabbed_following, following_data)
- logger.info("Stored `Following` data at {} local file".format(final_file))
-
- except Exception as exc:
- logger.info(
- "Failed to store `Following` data in a local file :Z\n{}".format(
- str(exc).encode("utf-8")
- )
- )
-
-
-def store_all_unfollowers(username, all_unfollowers, logger, logfolder):
- """Store all Unfollowers data in a local storage at generated date"""
- generation_date = datetime.today().strftime("%d-%m-%Y")
- all_unfollowers_size = len(all_unfollowers)
- file_directory = "{}/relationship_data/{}/unfollowers/all_unfollowers/".format(
- logfolder, username
- )
- file_name = "{}{}~all~{}".format(
- file_directory, generation_date, all_unfollowers_size
- )
- file_index = 0
- final_file = "{}.json".format(file_name)
-
- try:
- if not os.path.exists(file_directory):
- os.makedirs(file_directory)
- # this loop provides unique data files
- while os.path.isfile(final_file):
- file_index += 1
- final_file = "{}({}).json".format(file_name, file_index)
-
- with open(final_file, "w") as unfollowers_data:
- with interruption_handler():
- json.dump(all_unfollowers, unfollowers_data)
- logger.info("Stored all Unfollowers data at {} local file\n".format(final_file))
-
- except Exception as exc:
- logger.info(
- "Failed to store all Unfollowers data in a local file :Z\n{}"
- "\n".format(str(exc).encode("utf-8"))
- )
-
-
-def store_active_unfollowers(username, active_unfollowers, logger, logfolder):
- """Store active Unfollowers data in a local storage at generated date"""
- generation_date = datetime.today().strftime("%d-%m-%Y")
- active_unfollowers_size = len(active_unfollowers)
- file_directory = (
- "{}/relationship_data/{}"
- "/unfollowers/active_unfollowers/".format(logfolder, username)
- )
- file_name = "{}{}~active~{}".format(
- file_directory, generation_date, active_unfollowers_size
- )
- file_index = 0
- final_file = "{}.json".format(file_name)
-
- try:
- if not os.path.exists(file_directory):
- os.makedirs(file_directory)
- # this loop provides unique data files
- while os.path.isfile(final_file):
- file_index += 1
- final_file = "{}({}).json".format(file_name, file_index)
-
- with open(final_file, "w") as active_unfollowers_data:
- with interruption_handler():
- json.dump(active_unfollowers, active_unfollowers_data)
- logger.info(
- "Stored active Unfollowers data at {} local file\n".format(final_file)
- )
-
- except Exception as exc:
- logger.info(
- "Failed to store active Unfollowers data in a local file :Z\n{}"
- "\n".format(str(exc).encode("utf-8"))
- )
-
-
-def store_nonfollowers(
- username, followers_size, following_size, nonfollowers, logger, logfolder
-):
- """Store Nonfollowers data in a local storage at generated date"""
- generation_date = datetime.today().strftime("%d-%m-%Y")
- nonfollowers_size = len(nonfollowers)
- file_directory = "{}/relationship_data/{}/nonfollowers/".format(logfolder, username)
- file_name = "{}{}~[{}-{}]~{}".format(
- file_directory,
- generation_date,
- followers_size,
- following_size,
- nonfollowers_size,
- )
- file_index = 0
- final_file = "{}.json".format(file_name)
-
- try:
- if not os.path.exists(file_directory):
- os.makedirs(file_directory)
- # this loop provides unique data files
- while os.path.isfile(final_file):
- file_index += 1
- final_file = "{}({}).json".format(file_name, file_index)
-
- with open(final_file, "w") as nonfollowers_data:
- with interruption_handler():
- json.dump(nonfollowers, nonfollowers_data)
- logger.info("Stored Nonfollowers data at {} local file\n".format(final_file))
-
- except Exception as exc:
- logger.info(
- "Failed to store Nonfollowers data in a local file :Z\n{}"
- "\n".format(str(exc).encode("utf-8"))
- )
-
-
-def store_fans(username, followers_size, following_size, fans, logger, logfolder):
- """Store Fans data in a local storage at generated date"""
- generation_date = datetime.today().strftime("%d-%m-%Y")
- fans_size = len(fans)
-
- file_directory = "{}/relationship_data/{}/fans/".format(logfolder, username)
- file_name = "{}{}~[{}-{}]~{}".format(
- file_directory, generation_date, followers_size, following_size, fans_size
- )
-
- file_index = 0
- final_file = "{}.json".format(file_name)
-
- try:
- if not os.path.exists(file_directory):
- os.makedirs(file_directory)
- # this loop provides unique data files
- while os.path.isfile(final_file):
- file_index += 1
- final_file = "{}({}).json".format(file_name, file_index)
-
- with open(final_file, "w") as fans_data:
- with interruption_handler():
- json.dump(fans, fans_data)
- logger.info("Stored Fans data at {} local file\n".format(final_file))
-
- except Exception as exc:
- logger.info(
- "Failed to store Fans data in a local file :Z\n{}\n".format(
- str(exc).encode("utf-8")
- )
- )
-
-
-def store_mutual_following(
- username, followers_size, following_size, mutual_following, logger, logfolder
-):
- """Store Mutual Following data in a local storage at generated date"""
- generation_date = datetime.today().strftime("%d-%m-%Y")
- mutual_following_size = len(mutual_following)
-
- file_directory = "{}/relationship_data/{}/mutual_following/".format(
- logfolder, username
- )
- file_name = "{}{}~[{}-{}]~{}".format(
- file_directory,
- generation_date,
- followers_size,
- following_size,
- mutual_following_size,
- )
-
- file_index = 0
- final_file = "{}.json".format(file_name)
-
- try:
- if not os.path.exists(file_directory):
- os.makedirs(file_directory)
- # this loop provides unique data files
- while os.path.isfile(final_file):
- file_index += 1
- final_file = "{}({}).json".format(file_name, file_index)
-
- with open(final_file, "w") as mutual_following_data:
- with interruption_handler():
- json.dump(mutual_following, mutual_following_data)
- logger.info(
- "Stored Mutual Following data at {} local file\n".format(final_file)
- )
-
- except Exception as exc:
- logger.info(
- "Failed to store Mutual Following data in a local file :Z\n{}"
- "\n".format(str(exc).encode("utf-8"))
- )
-
-
-def load_followers_data(username, compare_by, compare_track, logger, logfolder):
- """Write grabbed `followers` data into local storage"""
-
- # Variables
- tracked_filenames = []
- structured_entries = {}
- selected_filename = None
-
- # get the list of all existing FULL `Followers` data files in
- # ~/logfolder/username/followers/ location
- files_location = "{}/relationship_data/{}/followers".format(logfolder, username)
- followers_data_files = [
- os.path.basename(file)
- for file in glob.glob("{}/*~full*.json".format(files_location))
- ]
-
- # check if there is any file to be compared
- if not followers_data_files:
- logger.info(
- "There are no any `Followers` data files in the {} location to "
- "compare".format(files_location)
- )
- return [], None
-
- # Filtrate and get the right track of file to compare
- for data_file in followers_data_files:
- tracked_filenames.append(data_file[:10])
- sorted_filenames = sorted(
- tracked_filenames, key=lambda x: datetime.strptime(x, "%d-%m-%Y")
- )
-
- this_day = datetime.today().strftime("%d")
- this_month = datetime.today().strftime("%m")
- this_year = datetime.today().strftime("%Y")
-
- for entry in sorted_filenames:
- entry_day, entry_month, entry_year = entry.split("-")
-
- structured_entries.setdefault("years", {}).setdefault(
- entry_year, {}
- ).setdefault("months", {}).setdefault(entry_month, {}).setdefault(
- "days", {}
- ).setdefault(
- entry_day, {}
- ).setdefault(
- "entries", []
- ).append(
- entry
- )
-
- if compare_by == "latest":
- selected_filename = sorted_filenames[-1]
-
- elif compare_by == "day":
- latest_day = sorted_filenames[-1]
- current_day = datetime.today().strftime("%d-%m-%Y")
-
- if latest_day == current_day:
- data_for_today = structured_entries["years"][this_year]["months"][
- this_month
- ]["days"][this_day]["entries"]
-
- if compare_track == "first" or len(data_for_today) <= 1:
- selected_filename = data_for_today[0]
- if compare_track == "median":
- median_index = int(len(data_for_today) / 2)
- selected_filename = data_for_today[median_index]
- if compare_track == "last":
- selected_filename = data_for_today[-1]
-
- else:
- selected_filename = sorted_filenames[-1]
- logger.info(
- "No any data exists for today! ~choosing the last existing "
- "data from {}".format(selected_filename)
- )
-
- elif compare_by == "month":
- latest_month = sorted_filenames[-1][-7:]
- current_month = datetime.today().strftime("%m-%Y")
-
- if latest_month == current_month:
- data_for_month = []
-
- for day in structured_entries["years"][this_year]["months"][this_month][
- "days"
- ]:
- data_for_month.extend(
- structured_entries["years"][this_year]["months"][this_month][
- "days"
- ][day]["entries"]
- )
-
- if compare_track == "first" or len(data_for_month) <= 1:
- selected_filename = data_for_month[0]
- if compare_track == "median":
- median_index = int(len(data_for_month) / 2)
- selected_filename = data_for_month[median_index]
- if compare_track == "last":
- selected_filename = data_for_month[-1]
-
- else:
- selected_filename = sorted_filenames[-1]
- logger.info(
- "No any data exists for this month! ~choosing the last "
- "existing data from {}".format(selected_filename)
- )
-
- elif compare_by == "year":
- latest_year = sorted_filenames[-1][-4:]
-
- if latest_year == this_year:
- data_for_year = []
-
- for month in structured_entries["years"][this_year]["months"]:
- for day in structured_entries["years"][this_year]["months"][month][
- "days"
- ]:
- data_for_year.extend(
- structured_entries["years"][this_year]["months"][month]["days"][
- day
- ]["entries"]
- )
-
- if compare_track == "first" or len(data_for_year) <= 1:
- selected_filename = data_for_year[0]
- if compare_track == "median":
- median_index = int(len(data_for_year) / 2)
- selected_filename = data_for_year[median_index]
- if compare_track == "last":
- selected_filename = data_for_year[-1]
-
- else:
- selected_filename = sorted_filenames[-1]
- logger.info(
- "No any data exists for this year! ~choosing the last existing data from {}".format(
- selected_filename
- )
- )
-
- elif compare_by == "earliest":
- selected_filename = sorted_filenames[0]
-
- # load that file
- selected_file = (
- glob.glob("{}/{}~full*.json".format(files_location, selected_filename))
- )[0]
- with open(selected_file) as followers_data_file:
- followers_data = json.load(followers_data_file)
-
- logger.info(
- "Took prior `Followers` data file from {} with {} usernames "
- "to be compared with live data\n".format(selected_filename, len(followers_data))
- )
-
- # return that file to be compared
- return followers_data, selected_filename
diff --git a/instapy/settings.py b/instapy/settings.py
deleted file mode 100644
index 07b001c08..000000000
--- a/instapy/settings.py
+++ /dev/null
@@ -1,92 +0,0 @@
-"""
-Global variables
-
-By design, import no any other local module inside this file.
-Vice verse, it'd produce circular dependent imports.
-"""
-# import built-in & third-party modules
-from sys import platform
-from os import environ as environmental_variables
-from os.path import join as join_path
-
-
-WORKSPACE = {
- "name": "InstaPy",
- "path": environmental_variables.get("INSTAPY_WORKSPACE"),
-}
-OS_ENV = (
- "windows" if platform == "win32" else "osx" if platform == "darwin" else "linux"
-)
-
-
-def localize_path(*args):
- """Join given locations as an OS path"""
-
- if WORKSPACE["path"]:
- path = join_path(WORKSPACE["path"], *args)
- return path
-
- else:
- return None
-
-
-class Settings:
- """Globally accessible settings throughout whole project"""
-
- # locations
- log_location = localize_path("logs")
- database_location = localize_path("db", "instapy.db")
-
- # set a logger cache outside the InstaPy object to avoid
- # re-instantiation issues
- loggers = {}
- logger = None
-
- # set current profile credentials for DB operations
- profile = {"id": None, "name": None}
-
- # hold live Quota Supervisor configuration for global usage
- QS_config = {}
-
- # store user-defined delay time to sleep after doing actions
- action_delays = {}
-
- # store configuration of text analytics
- meaningcloud_config = {}
- yandex_config = {}
-
- # store the parameter for global access
- show_logs = None
-
- user_agent = (
- "Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 "
- "(KHTML, like Gecko) FxiOS/29.0 Mobile/15E148 Safari/605.1.15"
- )
-
- # state of instantiation of InstaPy
- InstaPy_is_running = False
-
- # This is where currently the pods server is hosted
- pods_server_endpoint = "https://us-central1-instapy-pods.cloudfunctions.net"
- pods_fashion_server_endpoint = (
- "https://us-central1-instapy-pods-fashion.cloudfunctions.net"
- )
- pods_food_server_endpoint = (
- "https://us-central1-instapy-pods-food.cloudfunctions.net"
- )
- pods_travel_server_endpoint = (
- "https://us-central1-instapy-pods-travel.cloudfunctions.net"
- )
- pods_sports_server_endpoint = (
- "https://us-central1-instapy-pods-sports.cloudfunctions.net"
- )
- pods_entertainment_server_endpoint = (
- "https://us-central1-instapy-pods-entertainment.cloudfunctions.net"
- )
-
-
-class Storage:
- """Globally accessible standalone storage"""
-
- # store realtime record activity data
- record_activity = {}
diff --git a/instapy/story_util.py b/instapy/story_util.py
deleted file mode 100644
index 8cc6ee691..000000000
--- a/instapy/story_util.py
+++ /dev/null
@@ -1,230 +0,0 @@
-# import built-in & third-party modules
-import math
-import time
-from random import randint
-
-import requests
-
-# import exceptions
-from selenium.common.exceptions import NoSuchElementException, WebDriverException
-from selenium.webdriver.common.by import By
-
-from .settings import Settings
-
-# import InstaPy modules
-from .util import (
- click_element,
- get_action_delay,
- update_activity,
- web_address_navigator,
-)
-from .xpath import read_xpath
-
-
-def get_story_data(browser, elem, action_type, logger, simulate=False):
- """
- get the JSON data from the graphql URL
- output the amount of segments we can watch
- """
-
- # if things change in the future, modify here:
- query_hash = "cda12de4f7fd3719c0569ce03589f4c4"
- elem_id = ""
-
- if action_type == "user":
- try:
- reel_id = browser.execute_script(
- "return window.__additionalData[Object.keys(window.__additionalData)[0]].data.graphql.user.id"
- )
- # correct formating for elem_id
- elem_id = '"' + reel_id + '"'
- # and elem needs to be nothing
- elem = ""
- except WebDriverException:
- try:
- reel_id = browser.execute_script(
- "return window._sharedData."
- "entry_data.ProfilePage[0]."
- "graphql.user.id"
- )
- # correct formatting for elem_id
- elem_id = '"' + reel_id + '"'
- # and elem needs to be nothing
- elem = ""
- except WebDriverException:
- logger.error(
- "--> Sorry, this page isn't available!\t~either "
- + "link is broken or page is removed\n"
- )
- return {"status": "not_ok", "reels_cnt": 0}
- else:
- reel_id = "tag:{}".format(elem)
-
- graphql_query_url = (
- "https://www.instagram.com/graphql/query/?query_hash={}"
- '&variables={{"reel_ids":[{}],"tag_names":["{}"],"location_ids":[],'
- '"highlight_reel_ids":[],"precomposed_overlay":false,"show_story_viewer_list":true,'
- '"story_viewer_fetch_count":50,"story_viewer_cursor":"",'
- '"stories_video_dash_manifest":false}}'.format(query_hash, elem_id, elem)
- )
-
- cookies = browser.get_cookies()
- session = requests.Session()
- csrftoken = ""
-
- # prepare the cookies for the requests session
- for cookie in cookies:
- all_args = {
- "name": cookie["name"],
- "value": cookie["value"],
- "domain": cookie["domain"],
- "secure": cookie["secure"],
- "rest": {"HttpOnly": cookie["httpOnly"]},
- "path": cookie["path"],
- }
- if cookie["name"] == "csrftoken":
- csrftoken = cookie["value"]
- if not (cookie["name"] == "urlgen") and not (cookie["name"] == "rur"):
- all_args["expires"] = cookie["expiry"]
-
- session.cookies.set(**all_args)
-
- headers = {
- "User-Agent": Settings.user_agent,
- "X-Requested-With": "XMLHttpRequest",
- "SameSite": "Strict",
- }
-
- data = session.get(graphql_query_url, headers=headers)
- response = data.json()
- update_activity(browser, state=None)
-
- reels_cnt = 0
- if response["status"] == "ok":
- # we got a correct response from the server
- # check how many reels we got
- media_cnt = len(response["data"]["reels_media"])
-
- if media_cnt == 0:
- # then nothing to watch, we received no stories
- return {"status": "ok", "reels_cnt": 0}
- else:
- # we got content
- # check if there is something new to watch otherwise we just return 0
- seen = 0
- if (action_type != "tag") and (
- response["data"]["reels_media"][0]["seen"] is not None
- ):
- seen = response["data"]["reels_media"][0]["seen"]
- index = 1
- if simulate is True:
- for item in response["data"]["reels_media"][0]["items"]:
- if item["taken_at_timestamp"] <= seen:
- continue
- else:
- headers = {
- "User-Agent": Settings.user_agent,
- "X-CSRFToken": csrftoken,
- "X-Requested-With": "XMLHttpRequest",
- "Content-Type": "application/x-www-form-urlencoded",
- "SameSite": "Strict",
- }
- response = session.post(
- "https://www.instagram.com/stories/reel/seen",
- data={
- "reelMediaId": item["id"],
- "reelMediaOwnerId": item["owner"]["id"],
- "reelId": reel_id,
- "reelMediaTakenAt": item["taken_at_timestamp"],
- "viewSeenAt": math.floor(time.time()),
- },
- headers=headers,
- )
- logger.info(" --> simulated watch reel # {}".format(index))
- update_activity()
- index += 1
- time.sleep(randint(3, 6))
- reels_cnt += 1
- else:
- story_elem = browser.find_element(
- By.XPATH,
- read_xpath(
- watch_story.__name__ + "_for_{}".format(action_type),
- "explore_stories",
- ),
- )
-
- click_element(browser, story_elem)
-
- logger.info("Watching stories...")
- for item in response["data"]["reels_media"][0]["items"]:
- if item["taken_at_timestamp"] <= seen:
- continue
- else:
- time.sleep(2)
- if index == 1:
- try:
- next_elem = browser.find_element(
- By.XPATH,
- read_xpath(watch_story.__name__, "next_first"),
- )
- except NoSuchElementException:
- continue
- else:
- try:
- next_elem = browser.find_element(
- By.XPATH, read_xpath(watch_story.__name__, "next")
- )
- except NoSuchElementException:
- continue
- click_element(browser, next_elem)
- reels_cnt += 1
- index += 1
-
- return {"status": "ok", "reels_cnt": reels_cnt}
- else:
- return {"status": "not_ok", "reels_cnt": 0}
-
-
-def watch_story(browser, elem, logger, action_type, simulate=False):
- """
- Load Stories, and watch it until there is no more stores
- to watch for the related element
- """
-
- # make sure we work with a lower case elem
- elem = elem.lower()
-
- if action_type == "tag":
- story_link = "https://www.instagram.com/explore/tags/{}".format(elem)
-
- else:
- story_link = "https://www.instagram.com/{}".format(elem)
-
- web_address_navigator(browser, story_link)
- # wait for the page to load
- time.sleep(randint(2, 6))
- # order is important here otherwise we are not on the page of the story we want to watch
- story_data = get_story_data(browser, elem, action_type, logger, simulate)
-
- if story_data["status"] == "not ok":
- raise NoSuchElementException
-
- if story_data["reels_cnt"] == 0:
- # nothing to watch, there is no stories
- logger.info(
- "No stories to watch (either there is none) or we have already watched everything"
- )
- return 0
-
- logger.info(
- "Watched {} reels from {}: {}".format(
- story_data["reels_cnt"], action_type, elem.encode("utf-8")
- )
- )
-
- # get the post-story delay time to sleep
- naply = get_action_delay("story")
- time.sleep(naply)
-
- return story_data["reels_cnt"]
diff --git a/instapy/text_analytics.py b/instapy/text_analytics.py
deleted file mode 100644
index 125d9c978..000000000
--- a/instapy/text_analytics.py
+++ /dev/null
@@ -1,623 +0,0 @@
-"""
-Yandex Translate and MeaningCloud Sentiment Analysis services
-Official Documentations:
- Yandex: https://tech.yandex.com/translate/doc/dg/concepts/api-overview
- -docpage/
- MeaningCloud: https://www.meaningcloud.com/developer/sentiment-analysis/doc
-"""
-
-import json
-import requests
-from meaningcloud import SentimentResponse, SentimentRequest
-
-from .util import deform_emojis
-from .util import has_any_letters
-from .util import get_time_until_next_month
-from .util import truncate_float
-from .settings import Settings
-from .time_util import sleep
-
-from requests.exceptions import SSLError
-from requests.exceptions import ConnectionError
-
-YANDEX_API_VERSION = "v1.5"
-YANDEX_HOST = "https://translate.yandex.net"
-
-YANDEX_CONFIG = Settings.yandex_config
-MEANINGCLOUD_CONFIG = Settings.meaningcloud_config
-
-YANDEX_FAILURE_MSG = "Oh no! Yandex Translate failed :/"
-MEANINGCLOUD_FAILURE_MSG = "Oh no! MeaningCloud Sentiment Analysis failed :/"
-
-
-def text_analysis(text, text_type, logger):
- """
- Analyse text by sentiment analysis & language detection
-
- :return:
- Boolean indicating if the text is appropriate (after analysis) or
- None (if analysis isn't enabled)
- """
-
- # convert emojis in text into plain words for better analysis
- text, emojiless_text = deform_emojis(text)
- text_type_c = text_type.capitalize()
- inap_msg = "--> Content is inappropriate!" # generic negative result
- # message
- language_of_text = None
- text_is_printed = None
-
- if (
- not YANDEX_CONFIG
- or YANDEX_CONFIG["enabled"] is not True
- or (
- YANDEX_CONFIG["match_language"] is not True
- and (not MEANINGCLOUD_CONFIG or MEANINGCLOUD_CONFIG["enabled"] is not True)
- )
- ):
-
- # No analysis will be held
- print("")
- logger.info('{} text: "{}"'.format(text_type_c, text.encode("utf-8")))
- return None
-
- if YANDEX_CONFIG["match_language"] is True:
- # Language detection & match will take place
- if has_any_letters(emojiless_text):
- language_of_text = detect_language(emojiless_text)
- else:
- # text contains only emojis
- language_of_text = "en"
-
- # output the text to be analysed
- print("")
- logger.info(
- "{} text ['{}']: \"{}\"".format(
- text_type_c, language_of_text, text.encode("utf-8")
- )
- )
- text_is_printed = True
-
- if language_of_text and YANDEX_CONFIG["language_code"] != language_of_text:
- logger.info(
- "{}\t~language of the text is '{}'".format(inap_msg, language_of_text)
- )
- return False
-
- elif not language_of_text:
- logger.info("{}\t~language of text couldn't be detected!".format(inap_msg))
- return False
-
- if MEANINGCLOUD_CONFIG["enabled"] is True:
- # Text language normalization for accuracy & efficiency
- if not language_of_text:
- if has_any_letters(emojiless_text):
- language_of_text = detect_language(emojiless_text)
- else:
- # text contains only emojis
- language_of_text = "en"
-
- # output the text to be analysed [if not printed above]
- if text_is_printed is not True:
- print("")
- logger.info(
- "{} text ['{}']: \"{}\"".format(
- text_type_c, language_of_text, text.encode("utf-8")
- )
- )
-
- if not language_of_text:
- logger.info(
- "{}\t~language of text couldn't be detected!".format(inap_msg)
- )
- return False
-
- # if language of text is not supported by MeaningCloud, translate it
- # into english by Yandex
- if language_of_text not in ["en", "es", "fr", "it", "pt", "ca"]:
- translation_direction = "{}-en".format(language_of_text)
- text = translate_text(translation_direction, text)
- language_of_text = "en"
-
- # Sentiment Analysis
- sentiment = sentiment_analysis(text, language_of_text, logger)
-
- if sentiment is None:
- logger.info("{}\t~sentiment of text couldn't be detected!".format(inap_msg))
- return False
-
- # polarity verification
- if MEANINGCLOUD_CONFIG["score_tag"]:
- if not sentiment["score_tag"]:
- logger.info(
- "{}\t~polarity of text couldn't be detected!".format(inap_msg)
- )
- return False
-
- else:
- # get polarity & desired polarity levels to match towards
- # positivity
- pol = sentiment["score_tag"]
- des_pol = MEANINGCLOUD_CONFIG["score_tag"]
-
- polarity_level = (
- 3
- if pol == "P+"
- else 2
- if pol == "P"
- else 1
- if pol == "NEU"
- else -2
- if pol == "N+"
- else -1
- if pol == "N"
- else 0
- if pol == "NONE"
- else None
- )
-
- desired_polarity_level = (
- 3
- if des_pol == "P+"
- else 2
- if des_pol == "P"
- else 1
- if des_pol == "NEU"
- else -2
- if des_pol == "N+"
- else -1
- if des_pol == "N"
- else 0
- if des_pol == "NONE"
- else None
- )
-
- if desired_polarity_level > polarity_level:
- logger.info(
- "{}\t~polarity of text is '{}' with {}% confidence".format(
- inap_msg, sentiment["score_tag"], sentiment["confidence"]
- )
- )
- return False
-
- # agreement verification
- if MEANINGCLOUD_CONFIG["agreement"]:
- if not sentiment["agreement"]:
- logger.info(
- "{}\t~expressions' agreement of text couldn't be "
- "detected!".format(inap_msg)
- )
- return False
-
- elif MEANINGCLOUD_CONFIG["agreement"] != sentiment["agreement"]:
- logger.info(
- "{}\t~expressions in text has {}".format(
- inap_msg, sentiment["agreement"].lower()
- )
- )
- return False
-
- # subjectivity verification
- if MEANINGCLOUD_CONFIG["subjectivity"]:
- if not sentiment["subjectivity"]:
- logger.info(
- "{}\t~subjectivity of text couldn't be detected!".format(inap_msg)
- )
- return False
-
- elif MEANINGCLOUD_CONFIG["subjectivity"] != sentiment["subjectivity"]:
- logger.info(
- "{}\t~text is {}".format(
- inap_msg, sentiment["subjectivity"].lower()
- )
- )
- return False
-
- # confidence verification
- if MEANINGCLOUD_CONFIG["confidence"]:
- if not sentiment["confidence"]:
- logger.info(
- "{}\t~sentiment confidence of text couldn't be "
- "detected!".format(inap_msg)
- )
- return False
-
- elif MEANINGCLOUD_CONFIG["confidence"] > int(sentiment["confidence"]):
- logger.info(
- "{}\t~sentiment confidence of text is {}".format(
- inap_msg, sentiment["confidence"]
- )
- )
- return False
-
- return True
-
-
-def sentiment_analysis(text, language_of_text, logger):
- """
- Perform a detailed multilingual sentiment analysis of texts from
- different sources
- Available responses:
- https://github.com/MeaningCloud/meaningcloud-python/blob/master
- /meaningcloud/Response.py
-
- :return:
- Dictionary with the sentiment results or None
- """
-
- try:
- # make a request to the Sentiment Analysis API
- sentiment_response = SentimentResponse(
- SentimentRequest(
- key=MEANINGCLOUD_CONFIG["license_key"],
- lang=language_of_text,
- txt=text,
- txtf="plain",
- ).sendReq()
- )
- # check if there are any errors in the request
- request_state = lift_meaningcloud_request(sentiment_response)
- if request_state is not True:
- return None
-
- # get results
- sentiment = sentiment_response.getResults()
- if sentiment and "score_tag" in sentiment.keys() and sentiment["score_tag"]:
- # if text has a question mark & its polarity is neither negative
- # nor none, then label it neutral
- return sentiment
-
- else:
- status_message = sentiment_response.getStatusMsg()
- print("")
- logger.error(
- "{}\t~there was an unexpected error :|"
- "\n{}\n".format(MEANINGCLOUD_FAILURE_MSG, status_message)
- )
- return None
-
- except (ValueError, ConnectionError) as exc:
- print("")
- logger.exception(
- "{}\t~{}\n".format(MEANINGCLOUD_FAILURE_MSG, str(exc).encode("utf-8"))
- )
- return None
-
-
-def detect_language(text):
- """
- Detect the language of the specified text
-
- :return:
- String with the language of text or None
- """
-
- POST = "/api/{}/tr.json/detect?key={}&text={}".format(
- YANDEX_API_VERSION, YANDEX_CONFIG["API_key"], text
- )
- logger = Settings.logger
-
- try:
- req = requests.get(YANDEX_HOST + POST)
- except SSLError as exc:
- print("")
- logger.exception(
- "{}\t~there was a connection error :<"
- "\n{}\n".format(YANDEX_FAILURE_MSG, str(exc).encode("utf-8"))
- )
- return None
-
- data = json.loads(req.text)
- # check if there are any errors in the request
- request_state = lift_yandex_request(data)
- if request_state is not True:
- return None
-
- # get the result
- if "lang" in data.keys() and data["lang"]:
- language_of_text = data["lang"]
- return language_of_text
-
- else:
- return None
-
-
-def yandex_supported_languages(language_code="en"):
- """
- Get the list of translation directions supported by the service
- Overview of supported languages:
- https://tech.yandex.com/translate/doc/dg/concepts/api-overview
- -docpage/#api-overview__languages
-
- :return:
- dict.keys() object containing language codes or None
- """
-
- POST = "/api/{}/tr.json/getLangs?key={}&ui={}".format(
- YANDEX_API_VERSION, YANDEX_CONFIG["API_key"], language_code
- )
- logger = Settings.logger
-
- try:
- req = requests.get(YANDEX_HOST + POST)
- except SSLError:
- # try again one more time
- sleep(2)
-
- try:
- req = requests.get(YANDEX_HOST + POST)
- except SSLError as exc:
- print("")
- logger.exception(
- "{}\t~there was a connection error :<"
- "\n{}\n".format(YANDEX_FAILURE_MSG, str(exc).encode("utf-8"))
- )
- return None
-
- data = json.loads(req.text)
- if "langs" in data.keys() and data["langs"]:
- language_codes = data["langs"].keys()
- return language_codes
-
- else:
- return None
-
-
-def translate_text(translation_direction, text_to_translate):
- """
- Translate the text to the specified language
-
- :param translation_direction:
- "en-ru" [from english to russian]
- "en" [to english, auto-detect source lang]
-
- :return:
- String with the translated text or None
- """
-
- # if the text doesn't have an end mark, add a dot to get a better
- # translation
- if not text_to_translate.endswith((".", "?", "!", ";")):
- text_to_translate += "."
-
- POST = "/api/{}/tr.json/translate?key={}&text={}&lang={}".format(
- YANDEX_API_VERSION,
- YANDEX_CONFIG["API_key"],
- text_to_translate,
- translation_direction,
- )
- logger = Settings.logger
-
- try:
- req = requests.get(YANDEX_HOST + POST)
- except SSLError as exc:
- print("")
- logger.exception(
- "{}\t~there was a connection error :<"
- "\n{}\n".format(YANDEX_FAILURE_MSG, str(exc).encode("utf-8"))
- )
- return None
-
- data = json.loads(req.text)
- # check if there are any errors in the request
- request_state = lift_yandex_request(data)
- if request_state is not True:
- return None
-
- # get the result
- if "text" in data.keys() and data["text"]:
- translated_text = data["text"][0]
- return translated_text
-
- else:
- return None
-
-
-def lift_yandex_request(request):
- """
- Handle the Yandex status code from requests
-
- :return:
- Boolean indicating the state of request
- """
-
- status_code = request["code"]
- logger = Settings.logger
-
- # handle per status code
- if status_code in [401, 402, 404]:
- # turn off Yandex service
- YANDEX_CONFIG.update(enabled=False)
- service_turnoff_msg = "turned off Yandex service"
-
- if status_code == 401:
- error_msg = "API key provided is invalid"
- elif status_code == 402:
- error_msg = "API key provided is blocked"
- elif status_code == 404:
- error_msg = "you've reached the request limit"
-
- print("")
- logger.error(
- "{}\t~{} [{}]\n".format(YANDEX_FAILURE_MSG, error_msg, service_turnoff_msg)
- )
- return False
-
- elif status_code in [413, 422, 501]:
- if status_code == 413:
- error_msg = "given text exceeds the maximum size :<"
- elif status_code == 422:
- error_msg = "given text couldn't be translated :("
- elif status_code == 501:
- error_msg = "the specified translation direction is not " "supported ~.~"
-
- print("")
- logger.error("{}\t~{}\n".format(YANDEX_FAILURE_MSG, error_msg))
- return False
-
- return True
-
-
-def lift_meaningcloud_request(request):
- """
- Handle the MeaningCloud status code from requests
- Error Codes:
- https://www.meaningcloud.com/developer/documentation/error-codes
-
- :return:
- Boolean indicating the state of request
- """
-
- status_code = request.getStatusCode()
- logger = Settings.logger
-
- # handle per status code
- if status_code == "0":
- # request is successful
- return True
-
- elif status_code in ["100", "101", "102"]:
- # turn off MeaningCloud service
- MEANINGCLOUD_CONFIG.update(enabled=False)
- service_turnoff_msg = "turned off MeaningCloud service"
-
- if status_code == "100":
- error_msg = (
- "operation denied: license key is either incorrect,"
- " unauthorized to make requests or you've been "
- "banned from using service"
- )
-
- elif status_code == "101":
- error_msg = (
- "license expired: license key you're sending to use "
- "the API has expired"
- )
-
- elif status_code == "102":
- consumed_credits = request.getConsumedCredits() or "unknown"
- time_until_next_month = get_time_until_next_month()
-
- error_msg = (
- "credits per subscription exceeded: ran out of credits for "
- "current month"
- " (spent: {}) - wait for credits to be reset at month end ({}"
- " days)".format(
- consumed_credits,
- truncate_float(time_until_next_month / 60 / 60 / 24, 2),
- )
- )
-
- print("")
- logger.error(
- "{}\t~{} [{}]\n".format(
- MEANINGCLOUD_FAILURE_MSG, error_msg, service_turnoff_msg
- )
- )
-
- elif status_code in [
- "103",
- "104",
- "105",
- "200",
- "201",
- "202",
- "203",
- "204",
- "205",
- "206",
- "207",
- "212",
- "214",
- "215",
- ]:
-
- if status_code == "103":
- error_msg = (
- "request too large: exceeded the limit on the number of words"
- " that can be analyzed in a single request (max 50000)"
- )
-
- elif status_code == "104":
- error_msg = (
- "request rate limit exceeded: hit the limit set for number of"
- " requests can be carried out concurrently (per second)"
- )
-
- elif status_code == "105":
- error_msg = (
- "resource access denied: no access to a resource or language "
- "either cos haven't subscribed to any packs or trial ended"
- )
-
- elif status_code == "200":
- error_msg = (
- "missing required parameter(s): you haven't specified one of"
- " the required parameters"
- )
-
- elif status_code == "201":
- error_msg = (
- "resource not supported: you've sent an incorrect value for"
- " the 'model' or 'ud' parameters"
- )
-
- elif status_code == "202":
- error_msg = (
- "engine internal error: internal error has occurred in"
- " service engines (wait a few minutes and try again)"
- )
-
- elif status_code == "203":
- error_msg = (
- "can't connect to service: unable to serve the request due to"
- " high load in servers (wait a few minutes & try again)"
- )
-
- elif status_code == "204":
- error_msg = (
- "resource not compatible for the language automatically"
- " identified from the text"
- )
-
- elif status_code == "205":
- error_msg = (
- "language not supported: you've sent an incorrect value "
- "for the lang parameter"
- )
-
- elif status_code == "212":
- error_msg = (
- "no content to analyze: content provided to analyze couldn't "
- "be"
- " accessed or converted into HTML (make sure value is "
- "supported)"
- )
-
- elif status_code == "214":
- error_msg = (
- "wrong format: one of the parameters sent does not have"
- " the accepted format"
- )
-
- elif status_code == "215":
- error_msg = (
- "timeout exceeded for service response: it's taken too long"
- " to respond & exceeded the timeout set for the system"
- )
-
- print("")
- logger.error("{}\t~{}\n".format(MEANINGCLOUD_FAILURE_MSG, error_msg))
-
- else:
- response = request.getResponse()
- if response is None:
- error_msg = "the request sent did not return a JSON :/"
- else:
- status_message = request.getStatusMsg()
- error_msg = "there was an unusual error :|" "\n{}".format(status_message)
-
- print("")
- logger.error("{}\t~{}\n".format(MEANINGCLOUD_FAILURE_MSG, error_msg))
-
- return False
diff --git a/instapy/time_util.py b/instapy/time_util.py
deleted file mode 100644
index c6098e2cc..000000000
--- a/instapy/time_util.py
+++ /dev/null
@@ -1,62 +0,0 @@
-"""Helper module to handle time related stuff"""
-from time import sleep as original_sleep
-from datetime import datetime
-from random import gauss
-from random import uniform
-
-# Amount of variance to be introduced
-# i.e. random time will be in the range: TIME +/- STDEV %
-STDEV = 0.5
-sleep_percentage = 1
-sleep_percentage = sleep_percentage * uniform(0.9, 1.1)
-
-
-def randomize_time(mean):
- allowed_range = mean * STDEV
- stdev = allowed_range / 3 # 99.73% chance to be in the allowed range
-
- t = 0
- while abs(mean - t) > allowed_range:
- t = gauss(mean, stdev)
-
- return t
-
-
-def set_sleep_percentage(percentage):
- global sleep_percentage
- sleep_percentage = percentage / 100
- sleep_percentage = sleep_percentage * uniform(0.9, 1.1)
-
-
-def sleep(t, custom_percentage=None):
- if custom_percentage is None:
- custom_percentage = sleep_percentage
- time = randomize_time(t) * custom_percentage
- original_sleep(time)
-
-
-def sleep_actual(t):
- original_sleep(t)
-
-
-def get_time(labels):
- """To get a use out of this helpful function
- catch in the same order of passed parameters"""
- if not isinstance(labels, list):
- labels = [labels]
-
- results = []
-
- for label in labels:
- if label == "this_minute":
- results.append(datetime.now().strftime("%M"))
-
- if label == "this_hour":
- results.append(datetime.now().strftime("%H"))
-
- elif label == "today":
- results.append(datetime.now().strftime("%Y-%m-%d"))
-
- results = results if len(results) > 1 else results[0]
-
- return results
diff --git a/instapy/unfollow_util.py b/instapy/unfollow_util.py
deleted file mode 100644
index c5b8977c4..000000000
--- a/instapy/unfollow_util.py
+++ /dev/null
@@ -1,1672 +0,0 @@
-""" Module which handles the follow features like unfollowing and following """
-# import built-in & third-party modules
-import csv
-import json
-import os
-import random
-import sqlite3
-from datetime import datetime, timedelta
-from math import ceil
-
-# import exceptions
-from selenium.common.exceptions import (
- ElementNotVisibleException,
- NoSuchElementException,
- WebDriverException,
-)
-from selenium.webdriver.common.by import By
-
-from .database_engine import get_database
-from .event import Event
-from .follow_util import get_following_status
-from .print_log_writer import (
- get_log_time,
- log_followed_pool,
- log_record_all_unfollowed,
- log_uncertain_unfollowed_pool,
-)
-from .quota_supervisor import quota_supervisor
-from .relationship_tools import get_followers, get_following, get_nonfollowers
-
-# import InstaPy modules
-from .time_util import sleep
-from .util import (
- add_user_to_blacklist,
- click_element,
- click_visibly,
- delete_line_from_file,
- emergency_exit,
- find_user_id,
- format_number,
- get_action_delay,
- get_epoch_time_diff,
- get_query_hash,
- get_relationship_counts,
- is_follow_me,
- is_page_available,
- reload_webpage,
- truncate_float,
- update_activity,
- web_address_navigator,
-)
-from .xpath import read_xpath
-
-
-def set_automated_followed_pool(
- username,
- unfollow_after,
- logger,
- logfolder,
- delay_followbackers,
- pool="followedPool",
-):
- """Generate a user list based on the InstaPy followed usernames"""
- pool_name = "{0}{1}_{2}.csv".format(logfolder, username, pool)
- automatedFollowedPool = {"all": {}, "eligible": {}}
- time_stamp = None
- user = None
-
- try:
- with open(pool_name, "r+") as followedPoolFile:
- reader = csv.reader(followedPoolFile)
-
- for row in reader:
-
- # init
- followedback = None
- user_id = "undefined" # 'undefined' rather than None is *intentional
- eligle = True # 'undefined' rather than None is *intentional
-
- entries = row[0].split(" ~ ")
- sz = len(entries)
-
- # Data entry styles [historically]:
- # user, # oldest
- # datetime ~ user, # after `unfollow_after` was introduced
- # datetime ~ user ~ user_id, # after `user_id` was added
- if sz == 1:
- time_stamp = None
- user = entries[0]
-
- elif sz == 2:
- time_stamp = entries[0]
- user = entries[1]
-
- elif sz == 3:
- time_stamp = entries[0]
- user = entries[1]
- user_id = entries[2]
-
- elif sz == 4:
- time_stamp = entries[0]
- user = entries[1]
- user_id = entries[2]
- followedback = True if entries[3] == "true" else None
-
- automatedFollowedPool["all"].update(
- {
- user: {
- "id": user_id,
- "time_stamp": time_stamp,
- "followedback": followedback,
- }
- }
- )
- # get eligible list
- if time_stamp is not None:
- # filter the eligible users by
- # unfollow_after seconds
- # or by delay_followbackers seconds
- delay_unfollow = True
- unfollow_after_eligible = None
-
- if followedback is True and delay_followbackers:
- # delay length is for follow backers
- unfollow_after_eligible = delay_followbackers
- elif unfollow_after is not None:
- # delay length is set by admin
- unfollow_after_eligible = unfollow_after
- else:
- delay_unfollow = False
-
- if delay_unfollow:
- time_diff = get_epoch_time_diff(time_stamp, logger)
- if time_diff is None:
- continue
-
- if time_diff < unfollow_after_eligible:
- eligle = False
-
- if eligle:
- automatedFollowedPool["eligible"].update({user: {"id": user_id}})
-
- followedPoolFile.close()
-
- except BaseException as exc:
- logger.error(
- "Error occurred while generating a user list from the followed "
- "pool!\n\t{}".format(str(exc).encode("utf-8"))
- )
-
- return automatedFollowedPool
-
-
-def unfollow(
- browser,
- username,
- amount,
- customList,
- InstapyFollowed,
- nonFollowers,
- allFollowing,
- style,
- automatedFollowedPool,
- relationship_data,
- dont_include,
- white_list,
- sleep_delay,
- jumps,
- delay_followbackers,
- logger,
- logfolder,
-):
- """Unfollows the given amount of users"""
-
- msg = None
- unfollow_num = 0
- unfollow_list = None
- unfollow_track = None
- unfollow_state = None
- customList_data = None
- user_link = "https://www.instagram.com/{}/".format(username)
-
- if (
- customList is not None
- and isinstance(customList, (tuple, list))
- and len(customList) == 3
- and customList[0] is True
- and isinstance(customList[1], (list, tuple, set))
- and len(customList[1]) > 0
- and customList[2] in ["all", "nonfollowers"]
- ):
- customList_data = customList[1]
- if not isinstance(customList_data, list):
- customList_data = list(customList_data)
- unfollow_track = customList[2]
- customList = True
- else:
- customList = False
-
- if (
- InstapyFollowed is not None
- and isinstance(InstapyFollowed, (tuple, list))
- and len(InstapyFollowed) == 2
- and InstapyFollowed[0] is True
- and InstapyFollowed[1] in ["all", "nonfollowers"]
- ):
- unfollow_track = InstapyFollowed[1]
- InstapyFollowed = True
- else:
- InstapyFollowed = False
-
- # check URL of the webpage, if it already is the one to be navigated
- # then do not navigate to it again
- web_address_navigator(browser, user_link)
-
- # check how many people we are following
- _, allfollowing = get_relationship_counts(browser, username, logger)
-
- if allfollowing is None:
- logger.warning(
- "Unable to find the count of users followed ~leaving unfollow feature"
- )
- return 0
- elif allfollowing == 0:
- logger.warning("There are 0 people to unfollow ~leaving unfollow feature")
- return 0
-
- if amount > allfollowing:
- logger.info(
- "There are less users to unfollow than you have requested: "
- "{}/{} ~using available amount\n".format(allfollowing, amount)
- )
- amount = allfollowing
-
- if (
- customList is True
- or InstapyFollowed is True
- or nonFollowers is True
- or allFollowing is True
- ):
-
- if nonFollowers is True:
- InstapyFollowed = False
-
- if customList is True:
- logger.info("Unfollowing from the list of pre-defined usernames\n")
- unfollow_list = customList_data
-
- elif InstapyFollowed is True:
- logger.info("Unfollowing the users followed by InstaPy\n")
- unfollow_list = list(automatedFollowedPool["eligible"].keys())
-
- elif nonFollowers is True:
- logger.info("Unfollowing the users who do not follow back\n")
-
- # Unfollow only the users who do not follow you back
- unfollow_list = get_nonfollowers(
- browser,
- username,
- username,
- relationship_data,
- False,
- True,
- logger,
- logfolder,
- )
-
- # pick only the users in the right track- ["all" or "nonfollowers"]
- # for `customList` and
- # `InstapyFollowed` unfollow methods
- if customList is True or InstapyFollowed is True:
- if unfollow_track == "nonfollowers":
- all_followers = get_followers(
- browser,
- username,
- username,
- "full",
- relationship_data,
- False,
- True,
- logger,
- logfolder,
- )
- loyal_users = [user for user in unfollow_list if user in all_followers]
- logger.info(
- "Found {} loyal followers! ~will not unfollow "
- "them".format(len(loyal_users))
- )
- unfollow_list = [
- user for user in unfollow_list if user not in loyal_users
- ]
-
- elif unfollow_track != "all":
- logger.info(
- 'Unfollow track is not specified! ~choose "all" or '
- '"nonfollowers"'
- )
- return 0
-
- # re-generate unfollow list according to the `unfollow_after`
- # parameter for `customList` and
- # `nonFollowers` unfollow methods
- if customList is True or nonFollowers is True:
- not_found = []
- non_eligible = []
- for person in unfollow_list:
- if person not in automatedFollowedPool["all"].keys():
- not_found.append(person)
- elif (
- person in automatedFollowedPool["all"].keys()
- and person not in automatedFollowedPool["eligible"].keys()
- ):
- non_eligible.append(person)
-
- unfollow_list = [user for user in unfollow_list if user not in non_eligible]
- logger.info(
- "Total {} users available to unfollow"
- " ~not found in 'followedPool.csv': {} | didn't "
- "pass `unfollow_after`: {}\n".format(
- len(unfollow_list), len(not_found), len(non_eligible)
- )
- )
-
- elif InstapyFollowed is True:
- non_eligible = [
- user
- for user in automatedFollowedPool["all"].keys()
- if user not in automatedFollowedPool["eligible"].keys()
- ]
- logger.info(
- "Total {} users available to unfollow ~didn't pass "
- "`unfollow_after`: {}\n".format(len(unfollow_list), len(non_eligible))
- )
- elif allFollowing is True:
- logger.info("Unfollowing the users you are following")
- unfollow_list = get_following(
- browser,
- username,
- username,
- "full",
- relationship_data,
- False,
- True,
- logger,
- logfolder,
- )
-
- if len(unfollow_list) < 1:
- logger.info("There are no any users available to unfollow")
- return 0
-
- # choose the desired order of the elements
- if style == "LIFO":
- unfollow_list = list(reversed(unfollow_list))
- elif style == "RANDOM":
- random.shuffle(unfollow_list)
-
- if amount > len(unfollow_list):
- logger.info(
- "You have requested more amount: {} than {} of users "
- "available to unfollow"
- "~using available amount\n".format(amount, len(unfollow_list))
- )
- amount = len(unfollow_list)
-
- # unfollow loop
- try:
- sleep_counter = 0
- sleep_after = random.randint(8, 12)
- index = 0
-
- for person in unfollow_list:
- if unfollow_num >= amount:
- logger.warning(
- "--> Total unfollows reached it's amount given {}\n".format(
- unfollow_num
- )
- )
- break
-
- if jumps["consequent"]["unfollows"] >= jumps["limit"]["unfollows"]:
- logger.warning(
- "--> Unfollow quotient reached its peak!\t~leaving "
- "Unfollow-Users activity\n"
- )
- break
-
- if sleep_counter >= sleep_after and sleep_delay not in [0, None]:
- delay_random = random.randint(
- ceil(sleep_delay * 0.85), ceil(sleep_delay * 1.14)
- )
- logger.info(
- "Unfollowed {} new users ~sleeping about {}\n".format(
- sleep_counter,
- "{} seconds".format(delay_random)
- if delay_random < 60
- else "{} minutes".format(
- truncate_float(delay_random / 60, 2)
- ),
- )
- )
- sleep(delay_random)
- sleep_counter = 0
- sleep_after = random.randint(8, 12)
- pass
-
- if person not in dont_include:
- logger.info(
- "Ongoing Unfollow [{}/{}]: now unfollowing '{}'...".format(
- unfollow_num + 1, amount, person.encode("utf-8")
- )
- )
-
- person_id = (
- automatedFollowedPool["all"][person]["id"]
- if person in automatedFollowedPool["all"].keys()
- else False
- )
-
- # delay unfollowing of follow-backers
- if delay_followbackers and unfollow_track != "nonfollowers":
-
- followedback_status = automatedFollowedPool["all"][person][
- "followedback"
- ]
- # if once before we set that flag to true
- # now it is time to unfollow since
- # time filter pass, user is now eligble to unfollow
- if followedback_status is not True:
-
- user_link = "https://www.instagram.com/{}/".format(person)
- web_address_navigator(browser, user_link)
- valid_page = is_page_available(browser, logger)
-
- if valid_page and is_follow_me(browser, person):
- # delay follow-backers with delay_follow_back.
- time_stamp = (
- automatedFollowedPool["all"][person]["time_stamp"]
- if person in automatedFollowedPool["all"].keys()
- else False
- )
- if time_stamp not in [False, None]:
- try:
- time_diff = get_epoch_time_diff(
- time_stamp, logger
- )
- if time_diff is None:
- continue
-
- if (
- time_diff < delay_followbackers
- ): # N days in seconds
- set_followback_in_pool(
- username,
- person,
- person_id,
- time_stamp, # stay with original timestamp
- logger,
- logfolder,
- )
- # don't unfollow (for now) this follow backer !
- continue
-
- except ValueError:
- logger.error(
- "time_diff reading for user {} failed \n".format(
- person
- )
- )
- pass
-
- try:
- unfollow_state, msg = unfollow_user(
- browser,
- "profile",
- username,
- person,
- person_id,
- None,
- relationship_data,
- logger,
- logfolder,
- )
- except BaseException as e:
- logger.error("Unfollow loop error: {}\n".format(str(e)))
-
- post_unfollow_actions(browser, person, logger)
-
- if unfollow_state is True:
- unfollow_num += 1
- sleep_counter += 1
- # reset jump counter after a successful unfollow
- jumps["consequent"]["unfollows"] = 0
-
- elif msg == "jumped":
- # will break the loop after certain consecutive jumps
- jumps["consequent"]["unfollows"] += 1
-
- elif msg in ["temporary block", "not connected", "not logged in"]:
- # break the loop in extreme conditions to prevent
- # misbehaviours
- logger.warning(
- "There is a serious issue: '{}'!\t~leaving "
- "Unfollow-Users activity".format(msg)
- )
- break
-
- else:
- # if the user in dont include (should not be) we shall
- # remove him from the follow list
- # if he is a white list user (set at init and not during
- # run time)
- if person in white_list:
- delete_line_from_file(
- "{0}{1}_followedPool.csv".format(logfolder, username),
- person,
- logger,
- )
- list_type = "whitelist"
- else:
- list_type = "dont_include"
- logger.info(
- "Not unfollowed '{}'!\t~user is in the list {}"
- "\n".format(person, list_type)
- )
- index += 1
- continue
- except BaseException as e:
- logger.error("Unfollow loop error: {}\n".format(str(e)))
- else:
- logger.info(
- "Please select a proper unfollow method! ~leaving unfollow activity\n"
- )
-
- return unfollow_num
-
-
-def follow_user(browser, track, login, user_name, button, blacklist, logger, logfolder):
- """Follow a user either from the profile page or post page or dialog box"""
- # list of available tracks to follow in: ["profile", "post dialog"]
-
- # check action availability
- if quota_supervisor("follows") == "jump":
- return False, "jumped"
-
- if track in ["profile", "post"]:
- # if track == "profile":
- # check URL of the webpage, if it already is user's profile
- # page, then do not navigate to it again
- user_link = "https://www.instagram.com/{}/".format(user_name)
- web_address_navigator(browser, user_link)
-
- # find out CURRENT following status
- following_status, follow_button = get_following_status(
- browser, track, login, user_name, None, logger, logfolder
- )
- if following_status in ["Follow", "Follow Back"]:
- click_visibly(browser, follow_button) # click to follow
- follow_state, msg = verify_action(
- browser, "follow", track, login, user_name, None, logger, logfolder
- )
- if follow_state is not True:
- return False, msg
-
- elif following_status in ["Following", "Requested"]:
- if following_status == "Following":
- logger.info("--> Already following '{}'!\n".format(user_name))
-
- elif following_status == "Requested":
- logger.info("--> Already requested '{}' to follow!\n".format(user_name))
-
- sleep(1)
- return False, "already followed"
-
- elif following_status in ["Unblock", "UNAVAILABLE"]:
- if following_status == "Unblock":
- failure_msg = "user is in block"
-
- elif following_status == "UNAVAILABLE":
- failure_msg = "user is inaccessible"
-
- else:
- # Trace the current status
- failure_msg = following_status
-
- logger.warning(
- "--> Couldn't follow '{}'!\t~{}".format(user_name, failure_msg)
- )
- return False, following_status
-
- elif following_status is None:
- sirens_wailing, emergency_state = emergency_exit(browser, login, logger)
- if sirens_wailing is True:
- return False, emergency_state
-
- else:
- logger.warning(
- "--> Couldn't unfollow '{}'!\t~unexpected failure".format(user_name)
- )
- return False, "unexpected failure"
- elif track == "dialog":
- click_element(browser, button)
- sleep(3)
-
- # general tasks after a successful follow
- logger.info("--> Followed '{}'!".format(user_name.encode("utf-8")))
- Event().followed(user_name)
- update_activity(
- browser, action="follows", state=None, logfolder=logfolder, logger=logger
- )
-
- # get user ID to record alongside username
- user_id = get_user_id(browser, track, user_name, logger)
-
- logtime = datetime.now().strftime("%Y-%m-%d %H:%M")
- log_followed_pool(login, user_name, logger, logfolder, logtime, user_id)
-
- follow_restriction("write", user_name, None, logger)
-
- if blacklist["enabled"] is True:
- action = "followed"
- add_user_to_blacklist(
- user_name, blacklist["campaign"], action, logger, logfolder
- )
-
- # get the post-follow delay time to sleep
- naply = get_action_delay("follow")
- sleep(naply)
-
- return True, "success"
-
-
-def scroll_to_bottom_of_followers_list(browser):
- browser.execute_script("window.scrollTo(0, document.body.scrollHeight)")
- return
-
-
-def get_users_through_dialog_with_graphql(
- browser,
- login,
- user_name,
- amount,
- users_count,
- randomize,
- dont_include,
- blacklist,
- follow_times,
- simulation,
- channel,
- jumps,
- logger,
- logfolder,
- edge_followed_by,
-):
-
- # TODO: simulation implementation
-
- real_amount = amount
- followers_list = []
-
- if randomize and amount >= 3:
- # expanding the population for better sampling distribution
- amount = amount * 1.9
- try:
- user_id = browser.execute_script(
- "return window.__additionalData[Object.keys(window.__additionalData)[0]].data.graphql.user.id"
- )
- except WebDriverException:
- user_id = browser.execute_script(
- "return window._sharedData.entry_data.ProfilePage[0].graphql.user.id"
- )
-
- # There are two query hash, one for followers and following, ie:
- # t="c76146de99bb02f6415203be841dd25a",n="d04b0a864b4b54837c0d870b0e77e076"
- if edge_followed_by:
- # True: User requested session.follow_user_followers
- edge_type = "edge_followed_by"
- else:
- # False: User requested session.follow_user_following
- edge_type = "edge_follow"
-
- query_hash = get_query_hash(browser, logger, edge_followed_by)
-
- # check if hash is present
- if query_hash is None:
- logger.info("Unable to locate GraphQL query hash")
- else:
- logger.info("GraphQL query hash: [{}]".format(query_hash))
-
- graphql_query_URL = (
- "view-source:https://www.instagram.com/graphql/query/?query_hash={}".format(
- query_hash
- )
- )
- variables = {
- "id": str(user_id),
- "include_reel": "true",
- "fetch_mutual": "true",
- "first": 50,
- }
- url = "{}&variables={}".format(graphql_query_URL, str(json.dumps(variables)))
-
- web_address_navigator(browser, url)
-
- pre = browser.find_element(By.TAG_NAME, "pre").text
- # set JSON object
- data = json.loads(pre)
-
- try:
- # get all followers or following of current page
- # edge_type: used to check followers or following in JSON
- # "edge_followed_by" or "edge_follow"
- followers_page = data["data"]["user"][str(edge_type)]["edges"]
- except:
- # sometimes IG page displays a message that "Failed to Load. Retry"
- # so, instead of terminatig the App we will move to next step.
- # Cool down maybe ^.^
- # XPATH:
- # class="gxNyb">Failed to Load.
- # Marionette:
- # {"value":"{\"message\": \"\", \"spam\": true, \"status\": \"fail\"}"}
- logger.error("JSON (1) cannot be loaded, moving on...")
- return [], []
-
- # iterate over page size and add users to the list
- for follower in followers_page:
- # get follower name
- followers_list.append(follower["node"]["username"])
-
- has_next_page = data["data"]["user"][str(edge_type)]["page_info"]["has_next_page"]
-
- while has_next_page and len(followers_list) <= amount:
- # server call interval
- sleep(random.randint(2, 6))
-
- # get next page reference
- end_cursor = data["data"]["user"][str(edge_type)]["page_info"]["end_cursor"]
-
- # url variables
- variables = {
- "id": str(user_id),
- "include_reel": "true",
- "fetch_mutual": "true",
- "first": 50,
- "after": end_cursor,
- }
-
- url = "{}&variables={}".format(graphql_query_URL, str(json.dumps(variables)))
- browser.get(url)
- pre = browser.find_element(By.TAG_NAME, "pre").text
-
- # response to JSON object
- data = json.loads(pre)
-
- try:
- # get all followers of current page
- followers_page = data["data"]["user"][str(edge_type)]["edges"]
- except:
- logger.error("JSON (2) cannot be loaded, moving on...")
- return [], []
-
- # iterate over page size and add users to the list
- for follower in followers_page:
- # get follower name
- followers_list.append(follower["node"]["username"])
-
- # check if there is next page
- has_next_page = data["data"]["user"][str(edge_type)]["page_info"][
- "has_next_page"
- ]
-
- # simulation
- # TODO: this needs to be rewrited
- # if (
- # simulation["enabled"] is True
- # and simulation["percentage"] >= random.randint(1, 100)
- # and (
- # simulator_counter > random.randint(5, 17)
- # or abort is True
- # or total_list >= amount
- # or sc_rolled == random.randint(3, 5)
- # )
- # and len(buttons) > 0
- # ):
-
- # quick_amount = 1 if not total_list >= amount else random.randint(1, 4)
-
- # for i in range(0, quick_amount):
- # quick_index = random.randint(0, len(buttons) - 1)
- # quick_button = buttons[quick_index]
- # quick_username = dialog_username_extractor(quick_button)
-
- # if quick_username and quick_username[0] not in simulated_list:
- # if not pts_printed:
- # if total_list >= amount:
- # pts_printed = True
-
- # logger.info("Simulated follow : {}".format(len(simulated_list) + 1))
-
- # quick_follow = follow_through_dialog(
- # browser,
- # login,
- # quick_username,
- # quick_button,
- # quick_amount,
- # dont_include,
- # blacklist,
- # follow_times,
- # jumps,
- # logger,
- # logfolder,
- # )
- # if (quick_amount == 1 or i != (quick_amount - 1)) and (
- # not pts_printed or not abort
- # ):
- # simulated_list.extend(quick_follow)
-
- # simulator_counter = 0
-
- # shuffle it if randomize is enable
- if randomize:
- random.shuffle(followers_list)
-
- # get real amount
- followers_list = random.sample(followers_list, real_amount)
-
- for i, user in enumerate(followers_list):
- logger.info(
- "To be followed: [{}/{}/{}]".format(i + 1, len(followers_list), user)
- )
-
- return followers_list, []
-
-
-def dialog_username_extractor(buttons):
- """Extract username of a follow button from a dialog box"""
-
- if not isinstance(buttons, list):
- buttons = [buttons]
-
- person_list = []
- for person in buttons:
- if person and hasattr(person, "text") and person.text:
- try:
- xpath = read_xpath(dialog_username_extractor.__name__, "person")
- element_by_xpath = person.find_element(By.XPATH, xpath)
- elements_by_tag_name = element_by_xpath.find_elements(By.TAG_NAME, "a")[
- 0
- ].text
-
- if elements_by_tag_name == "":
- elements_by_tag_name = element_by_xpath.find_elements(
- By.TAG_NAME, "a"
- )[1].text
-
- person_list.append(elements_by_tag_name)
- except IndexError:
- print("how many?")
- pass # Element list is too short to have a [1] element
-
- return person_list
-
-
-def follow_through_dialog(
- browser,
- login,
- person_list,
- buttons,
- amount,
- dont_include,
- blacklist,
- follow_times,
- jumps,
- logger,
- logfolder,
-):
- """Will follow username directly inside a dialog box"""
- if not isinstance(person_list, list):
- person_list = [person_list]
-
- if not isinstance(buttons, list):
- buttons = [buttons]
-
- person_followed = []
- followNum = 0
-
- try:
- for person, button in zip(person_list, buttons):
- if followNum >= amount:
- logger.info("--> Total follow number reached: {}".format(followNum))
- break
-
- elif jumps["consequent"]["follows"] >= jumps["limit"]["follows"]:
- logger.warning(
- "--> Follow quotient reached its peak!\t~leaving "
- "Follow-Through-Dialog activity\n"
- )
- break
-
- if person not in dont_include and not follow_restriction(
- "read", person, follow_times, logger
- ):
- follow_state, msg = follow_user(
- browser,
- "dialog",
- login,
- person,
- button,
- blacklist,
- logger,
- logfolder,
- )
- if follow_state is True:
- # register this session's followed user for further
- # interaction
- person_followed.append(person)
- followNum += 1
- # reset jump counter after a successful follow
- jumps["consequent"]["follows"] = 0
-
- elif msg == "jumped":
- # will break the loop after certain consecutive jumps
- jumps["consequent"]["follows"] += 1
-
- else:
- logger.info("Not followed '{}' ~inappropriate user".format(person))
-
- except BaseException as e:
- logger.error(
- "Error occurred while following through dialog box:\n{}".format(str(e))
- )
-
- return person_followed
-
-
-def get_given_user_followers(
- browser,
- login,
- user_name,
- amount,
- dont_include,
- randomize,
- blacklist,
- follow_times,
- simulation,
- jumps,
- logger,
- logfolder,
-):
- """
- For the given username, follow their followers.
-
- :param browser: webdriver instance
- :param login:
- :param user_name: given username of account to follow
- :param amount: the number of followers to follow
- :param dont_include: ignore these usernames
- :param randomize: randomly select from users' followers
- :param blacklist:
- :param follow_times:
- :param logger: the logger instance
- :param logfolder: the logger folder
- :return: list of user's followers also followed
- """
- user_name = user_name.strip().lower()
-
- user_link = "https://www.instagram.com/{}/".format(user_name)
- web_address_navigator(browser, user_link)
-
- if not is_page_available(browser, logger):
- return [], []
-
- # check how many people are following this user.
- allfollowers, _ = get_relationship_counts(browser, user_name, logger)
-
- # skip early for no followers
- if not allfollowers:
- logger.info("'{}' has no followers".format(user_name))
- return [], []
-
- elif allfollowers < amount:
- logger.warning(
- "'{}' has less followers- {}, than the given amount of {}".format(
- user_name, allfollowers, amount
- )
- )
-
- # locate element to user's followers
- try:
- followers_link = browser.find_element(
- By.XPATH, read_xpath(get_given_user_followers.__name__, "followers_link")
- )
- click_element(browser, followers_link)
- # update server calls
- update_activity(browser, state=None)
-
- except NoSuchElementException:
- logger.error("Could not find followers' link for '{}'".format(user_name))
- return [], []
-
- except BaseException as e:
- logger.error("`followers_link` error {}".format(str(e)))
- return [], []
-
- channel = "Follow"
- edge_followed_by = True
- person_list, simulated_list = get_users_through_dialog_with_graphql(
- browser,
- login,
- user_name,
- amount,
- allfollowers,
- randomize,
- dont_include,
- blacklist,
- follow_times,
- simulation,
- channel,
- jumps,
- logger,
- logfolder,
- edge_followed_by,
- )
-
- return person_list, simulated_list
-
-
-def get_given_user_following(
- browser,
- login,
- user_name,
- amount,
- dont_include,
- randomize,
- blacklist,
- follow_times,
- simulation,
- jumps,
- logger,
- logfolder,
-):
- """
- For the given username, follow who they follows.
-
- :param browser: webdriver instance
- :param login:
- :param user_name: given username of account to follow
- :param amount: the number of followers to follow
- :param dont_include: ignore these usernames
- :param randomize: randomly select from users' followers
- :param blacklist:
- :param follow_times:
- :param logger: the logger instance
- :param logfolder: the logger folder
- :return: list of user's following
- """
- user_name = user_name.strip().lower()
-
- user_link = "https://www.instagram.com/{}/".format(user_name)
- web_address_navigator(browser, user_link)
-
- if not is_page_available(browser, logger):
- return [], []
-
- # check how many people are following this user.
- # throw RuntimeWarning if we are 0 people following this user
- try:
- # allfollowing = format_number(
- # browser.find_element(By.XPATH, read_xpath(get_given_user_following.__name__,"all_following")).text)
- allfollowing = format_number(
- browser.find_element(
- By.XPATH, read_xpath(get_given_user_following.__name__, "all_following")
- ).text
- )
-
- except NoSuchElementException:
- try:
- allfollowing = browser.execute_script(
- "return window.__additionalData[Object.keys(window.__additionalData)[0]].data."
- "graphql.user.edge_follow.count"
- )
-
- except WebDriverException:
- try:
- browser.execute_script("location.reload()")
- update_activity(browser, state=None)
-
- allfollowing = browser.execute_script(
- "return window._sharedData."
- "entry_data.ProfilePage[0]."
- "graphql.user.edge_follow.count"
- )
-
- except WebDriverException:
- try:
- topCount_elements = browser.find_elements(
- By.XPATH,
- read_xpath(
- get_given_user_following.__name__, "topCount_elements"
- ),
- )
-
- if topCount_elements:
- allfollowing = format_number(topCount_elements[2].text)
- else:
- logger.info(
- "Failed to get following count of '{}' ~empty "
- "list".format(user_name)
- )
- allfollowing = None
-
- except (NoSuchElementException, IndexError):
- logger.error(
- "\nError occured during getting the following count "
- "of '{}'\n".format(user_name)
- )
- return [], []
-
- # skip early for no followers
- if not allfollowing:
- logger.info("'{}' has no any following".format(user_name))
- return [], []
-
- elif allfollowing < amount:
- logger.warning(
- "'{}' has less following- {} than the desired amount of {}".format(
- user_name, allfollowing, amount
- )
- )
-
- try:
- following_link = browser.find_elements(
- By.XPATH,
- read_xpath(get_given_user_following.__name__, "following_link").format(
- user_name
- ),
- )
- click_element(browser, following_link[0])
- # update server calls
- update_activity(browser, state=None)
-
- except NoSuchElementException:
- logger.error("Could not find following's link for '{}'".format(user_name))
- return [], []
-
- except BaseException as e:
- logger.error("`following_link` error {}".format(str(e)))
- return [], []
-
- channel = "Follow"
- edge_followed_by = False
- person_list, simulated_list = get_users_through_dialog_with_graphql(
- browser,
- login,
- user_name,
- amount,
- allfollowing,
- randomize,
- dont_include,
- blacklist,
- follow_times,
- simulation,
- channel,
- jumps,
- logger,
- logfolder,
- edge_followed_by,
- )
-
- return person_list, simulated_list
-
-
-def dump_follow_restriction(profile_name, logger, logfolder):
- """Dump follow restriction data to a local human-readable JSON"""
-
- conn = None
-
- try:
- # get a DB and start a connection
- db, id = get_database()
- conn = sqlite3.connect(db)
-
- with conn:
- conn.row_factory = sqlite3.Row
- cur = conn.cursor()
-
- cur.execute(
- "SELECT * FROM followRestriction WHERE profile_id=:var", {"var": id}
- )
- data = cur.fetchall()
-
- if data:
- # get the existing data
- filename = "{}followRestriction.json".format(logfolder)
- if os.path.isfile(filename):
- with open(filename) as followResFile:
- current_data = json.load(followResFile)
- else:
- current_data = {}
-
- # pack the new data
- follow_data = {user_data[1]: user_data[2] for user_data in data or []}
- current_data[profile_name] = follow_data
-
- # dump the fresh follow data to a local human readable JSON
- with open(filename, "w") as followResFile:
- json.dump(current_data, followResFile)
-
- except Exception as exc:
- logger.error(
- "Pow! Error occurred while dumping follow restriction data to a "
- "local JSON:\n\t{}".format(str(exc).encode("utf-8"))
- )
-
- finally:
- if conn:
- # close the open connection
- conn.close()
-
-
-def follow_restriction(operation, username, limit, logger):
- """Keep track of the followed users and help avoid excessive follow of
- the same user"""
-
- conn = None
-
- try:
- # get a DB and start a connection
- db, profile_id = get_database()
- conn = sqlite3.connect(db)
-
- with conn:
- conn.row_factory = sqlite3.Row
- cur = conn.cursor()
-
- cur.execute(
- "SELECT * FROM followRestriction WHERE profile_id=:id_var "
- "AND username=:name_var",
- {"id_var": profile_id, "name_var": username},
- )
- data = cur.fetchone()
- follow_data = dict(data) if data else None
-
- if operation == "write":
- if follow_data is None:
- # write a new record
- cur.execute(
- "INSERT INTO followRestriction (profile_id, "
- "username, times) VALUES (?, ?, ?)",
- (profile_id, username, 1),
- )
- else:
- # update the existing record
- follow_data["times"] += 1
- sql = (
- "UPDATE followRestriction set times = ? WHERE "
- "profile_id=? AND username = ?"
- )
- cur.execute(sql, (follow_data["times"], profile_id, username))
-
- # commit the latest changes
- conn.commit()
-
- elif operation == "read":
- if follow_data is None:
- return False
-
- elif follow_data["times"] < limit:
- return False
-
- else:
- exceed_msg = "" if follow_data["times"] == limit else "more than "
- logger.info(
- "--> {} has already been followed {}{} times".format(
- username, exceed_msg, str(limit)
- )
- )
- return True
-
- except Exception as exc:
- logger.error(
- "Dap! Error occurred with follow Restriction:\n\t{}".format(
- str(exc).encode("utf-8")
- )
- )
-
- finally:
- if conn:
- # close the open connection
- conn.close()
-
-
-def unfollow_user(
- browser,
- track,
- username,
- person,
- person_id,
- button,
- relationship_data,
- logger,
- logfolder,
-):
- """Unfollow a user either from the profile or post page or dialog box"""
- # list of available tracks to unfollow in: ["profile", "post dialog]
- # check action availability
- if quota_supervisor("unfollows") == "jump":
- return False, "jumped"
-
- if track in ["profile", "post"]:
- # Method of unfollowing from a user's profile page or post page
- if track == "profile":
- user_link = "https://www.instagram.com/{}/".format(person)
- web_address_navigator(browser, user_link)
-
- # find out CURRENT follow status
- following_status, follow_button = get_following_status(
- browser, track, username, person, person_id, logger, logfolder
- )
-
- if following_status in ["Following", "Requested"]:
- click_element(browser, follow_button) # click to unfollow
- sleep(4) # TODO: use explicit wait here
- confirm_unfollow(browser)
- unfollow_state, msg = verify_action(
- browser,
- "unfollow",
- track,
- username,
- person,
- person_id,
- logger,
- logfolder,
- )
- if unfollow_state is not True:
- return False, msg
-
- elif following_status in ["Follow", "Follow Back"]:
- logger.info(
- "--> Already unfollowed '{}'! or a private user that "
- "rejected your req".format(person)
- )
- post_unfollow_cleanup(
- ["successful", "uncertain"],
- username,
- person,
- relationship_data,
- person_id,
- logger,
- logfolder,
- )
- return False, "already unfollowed"
-
- elif following_status in ["Unblock", "UNAVAILABLE"]:
- if following_status == "Unblock":
- failure_msg = "user is in block"
-
- elif following_status == "UNAVAILABLE":
- failure_msg = "user is inaccessible"
-
- else:
- # Trace the current status
- failure_msg = following_status
-
- logger.warning(
- "--> Couldn't unfollow '{}'!\t~{}".format(person, failure_msg)
- )
- post_unfollow_cleanup(
- "uncertain",
- username,
- person,
- relationship_data,
- person_id,
- logger,
- logfolder,
- )
- return False, following_status
-
- elif following_status is None:
- sirens_wailing, emergency_state = emergency_exit(browser, username, logger)
- if sirens_wailing is True:
- return False, emergency_state
-
- else:
- logger.warning(
- "--> Couldn't unfollow '{}'!\t~unexpected failure".format(person)
- )
- return False, "unexpected failure"
- elif track == "dialog":
- # Method of unfollowing from a dialog box
-
- click_element(browser, button)
- sleep(4) # TODO: use explicit wait here
- confirm_unfollow(browser)
-
- # general tasks after a successful unfollow
- logger.info("--> Unfollowed '{}'!".format(person))
- Event().unfollowed(person)
- update_activity(
- browser, action="unfollows", state=None, logfolder=logfolder, logger=logger
- )
- post_unfollow_cleanup(
- "successful", username, person, relationship_data, person_id, logger, logfolder
- )
-
- # get the post-unfollow delay time to sleep
- naply = get_action_delay("unfollow")
- sleep(naply)
-
- return True, "success"
-
-
-def confirm_unfollow(browser):
- """Deal with the confirmation dialog boxes during an unfollow"""
- attempt = 0
-
- while attempt < 3:
- try:
- attempt += 1
- button_xp = read_xpath(
- confirm_unfollow.__name__, "button_xp"
- ) # "//button[contains(
- # text(), 'Unfollow')]"
- unfollow_button = browser.find_element(By.XPATH, button_xp)
-
- if unfollow_button.is_displayed():
- click_element(browser, unfollow_button)
- sleep(2)
- break
-
- except (ElementNotVisibleException, NoSuchElementException) as exc:
- # prob confirm dialog didn't pop up
- if isinstance(exc, ElementNotVisibleException):
- break
-
- elif isinstance(exc, NoSuchElementException):
- sleep(1)
-
-
-def post_unfollow_cleanup(
- state, username, person, relationship_data, person_id, logger, logfolder
-):
- """Casual local data cleaning after an unfollow"""
- if not isinstance(state, list):
- state = [state]
-
- delete_line_from_file(
- "{0}{1}_followedPool.csv".format(logfolder, username), person, logger
- )
-
- if "successful" in state:
- if person in relationship_data[username]["all_following"]:
- relationship_data[username]["all_following"].remove(person)
-
- if "uncertain" in state:
- # this user was found in our unfollow list but currently is not
- # being followed
- logtime = get_log_time()
- log_uncertain_unfollowed_pool(
- username, person, logger, logfolder, logtime, person_id
- )
- # take a generic 3 seconds of sleep per each uncertain unfollow
- sleep(3)
-
- # save any unfollowed person
- log_record_all_unfollowed(username, person, logger, logfolder)
-
-
-def get_buttons_from_dialog(dialog, channel):
- """Gets buttons from the `Followers` or `Following` dialog boxes"""
-
- buttons = None
-
- if channel == "Follow":
- # get follow buttons. This approach will find the follow buttons and
- # ignore the Unfollow/Requested buttons.
- buttons = dialog.find_elements(
- By.XPATH, read_xpath(get_buttons_from_dialog.__name__, "follow_button")
- )
-
- elif channel == "Unfollow":
- buttons = dialog.find_elements(
- By.XPATH, read_xpath(get_buttons_from_dialog.__name__, "unfollow_button")
- )
-
- return buttons
-
-
-def get_user_id(browser, track, username, logger):
- """Get user's ID either from a profile page or post page"""
- user_id = "unknown"
-
- if track != "dialog": # currently do not get the user ID for follows
- # from 'dialog'
- user_id = find_user_id(browser, track, username, logger)
-
- return user_id
-
-
-def verify_action(
- browser, action, track, username, person, person_id, logger, logfolder
-):
- """Verify if the action has succeeded"""
- # currently supported actions are follow & unfollow
-
- retry_count = 0
- post_action_text_fail = None
- post_action_text_correct = None
-
- if action in ["follow", "unfollow"]:
-
- # assuming button_change testing is relevant to those actions only
- button_change = False
-
- if action == "follow":
- post_action_text_correct = ["Following", "Requested", "Message"]
- post_action_text_fail = ["Follow", "Follow Back", "Unblock"]
-
- elif action == "unfollow":
- post_action_text_correct = ["Follow", "Follow Back", "Unblock"]
- post_action_text_fail = ["Following", "Requested", "Message"]
-
- while True:
-
- # count retries at beginning
- retry_count += 1
-
- # find out CURRENT follow status (this is safe as the follow button is before others)
- following_status, follow_button = get_following_status(
- browser, track, username, person, person_id, logger, logfolder
- )
- if following_status in post_action_text_correct:
- button_change = True
- elif following_status in post_action_text_fail:
- button_change = False
- else:
- logger.error(
- "Hey! Last {} is not verified out of an unexpected "
- "failure!".format(action)
- )
- return False, "unexpected"
-
- if button_change:
- break
- else:
- if retry_count == 1:
- reload_webpage(browser)
- sleep(4)
-
- elif retry_count == 2:
- # handle it!
- # try to do the action one more time!
- click_visibly(browser, follow_button)
-
- if action == "unfollow":
- confirm_unfollow(browser)
-
- sleep(4)
- elif retry_count == 3:
- user_link = "https://www.instagram.com/{}/".format(person)
- web_address_navigator(browser, user_link)
- follow_button_xp = read_xpath(
- "get_following_status", "follow_button_XP"
- )
- button = browser.find_element(By.XPATH, follow_button_xp)
- try:
- button.click()
- except:
- return False, "unexpected"
- sleep(random.randint(4, 7))
- return True, "success"
-
- elif retry_count == 4:
- logger.warning(
- "Last {0} is not verified."
- "\t~'{1}' might be temporarily blocked "
- "from {0}ing\n".format(action, username)
- )
- sleep(210)
- return False, "temporary block"
-
- logger.info("Last {} is verified after reloading the page!".format(action))
-
- return True, "success"
-
-
-def post_unfollow_actions(browser, person, logger):
- pass
-
-
-def get_follow_requests(browser, amount, sleep_delay, logger, logfolder):
- """Get follow requests from instagram access tool list"""
-
- user_link = "https://www.instagram.com/accounts/access_tool/current_follow_requests"
- web_address_navigator(browser, user_link)
-
- list_of_users = []
- view_more_button_exist = True
- view_more_clicks = 0
- view_more_button = None
-
- while (
- len(list_of_users) < amount
- and view_more_clicks < 750
- and view_more_button_exist
- ):
- sleep(4)
- list_of_users = browser.find_elements(
- By.XPATH, read_xpath(get_follow_requests.__name__, "list_of_users")
- )
-
- if len(list_of_users) == 0:
- logger.info("There are not outgoing follow requests")
- break
-
- try:
- view_more_button = browser.find_element(
- By.XPATH, read_xpath(get_follow_requests.__name__, "view_more_button")
- )
- except NoSuchElementException:
- view_more_button_exist = False
-
- if view_more_button_exist:
- logger.info(
- "Found '{}' outgoing follow requests, Going to ask for more...".format(
- len(list_of_users)
- )
- )
- click_element(browser, view_more_button)
- view_more_clicks += 1
-
- users_to_unfollow = []
-
- for user in list_of_users:
- users_to_unfollow.append(user.text)
- if len(users_to_unfollow) == amount:
- break
-
- logger.info(
- "Found '{}' outgoing follow requests '{}'".format(
- len(users_to_unfollow), users_to_unfollow
- )
- )
-
- return users_to_unfollow
-
-
-def set_followback_in_pool(username, person, person_id, logtime, logger, logfolder):
- # first we delete the user from pool
- delete_line_from_file(
- "{0}{1}_followedPool.csv".format(logfolder, username), person, logger
- )
-
- # return the username with new timestamp
- log_followed_pool(username, person, logger, logfolder, logtime, person_id)
-
-
-def refresh_follow_time_in_pool(
- username, person, person_id, extra_secs, logger, logfolder
-):
- # set the new time to now plus extra delay
- logtime = (datetime.now() + timedelta(seconds=extra_secs)).strftime(
- "%Y-%m-%d %H:%M"
- )
-
- # first we delete the user from pool
- delete_line_from_file(
- "{0}{1}_followedPool.csv".format(logfolder, username), person, logger
- )
-
- # return the username with new timestamp
- log_followed_pool(username, person, logger, logfolder, logtime, person_id)
diff --git a/instapy/util.py b/instapy/util.py
deleted file mode 100644
index 6d77e577e..000000000
--- a/instapy/util.py
+++ /dev/null
@@ -1,2654 +0,0 @@
-""" Common utilities """
-# import built-in & third-party modules
-import csv
-import datetime
-import json
-import os
-import random
-import re
-import signal
-import sqlite3
-import sys
-import time
-from argparse import ArgumentParser
-from contextlib import contextmanager
-from math import ceil, cos
-from math import degrees as rad2deg
-from math import radians
-from platform import python_version, system
-from random import randint
-from subprocess import call
-from sys import exit as clean_exit
-from tempfile import gettempdir
-
-import emoji
-import regex
-from bs4 import BeautifulSoup
-from emoji.unicode_codes import UNICODE_EMOJI
-
-# import exceptions
-from selenium.common.exceptions import (
- NoSuchElementException,
- StaleElementReferenceException,
- TimeoutException,
- WebDriverException,
-)
-from selenium.webdriver.common.by import By
-from selenium.webdriver.support import expected_conditions as ec
-from selenium.webdriver.support.ui import WebDriverWait
-
-from .database_engine import get_database
-from .event import Event
-from .quota_supervisor import quota_supervisor
-from .settings import Settings
-from .time_util import sleep, sleep_actual
-
-# import InstaPy modules
-from .xpath import read_xpath
-
-default_profile_pic_instagram = [
- "https://instagram.flas1-2.fna.fbcdn.net/vp"
- "/a8539c22ed9fec8e1c43b538b1ebfd1d/5C5A1A7A/t51.2885-19"
- "/11906329_960233084022564_1448528159_a.jpg",
- "https://scontent-yyz1-1.cdninstagram.com/vp"
- "/a8539c22ed9fec8e1c43b538b1ebfd1d/5C5A1A7A/t51.2885-19"
- "/11906329_960233084022564_1448528159_a.jpg",
- "https://instagram.faep12-1.fna.fbcdn.net/vp"
- "/a8539c22ed9fec8e1c43b538b1ebfd1d/5C5A1A7A/t51.2885-19"
- "/11906329_960233084022564_1448528159_a.jpg",
- "https://instagram.fbts2-1.fna.fbcdn.net/vp"
- "/a8539c22ed9fec8e1c43b538b1ebfd1d/5C5A1A7A/t51.2885-19"
- "/11906329_960233084022564_1448528159_a.jpg",
- "https://scontent-mia3-1.cdninstagram.com/vp"
- "/a8539c22ed9fec8e1c43b538b1ebfd1d/5C5A1A7A/t51.2885-19"
- "/11906329_960233084022564_1448528159_a.jpg",
-]
-
-next_screenshot = 1
-
-
-def is_private_profile(browser, logger, following=True):
- """
- Verify if account is Private
-
- :param browser: The selenium webdriver instance
- :param logger: the logger instance
- :param following: Not accessed
- :return: None if profile cannot be verified
- """
-
- try:
- # Get profile owner information
- shared_data = get_shared_data(browser)
-
- # Sometimes shared_data["entry_data"]["ProfilePage"][0] is empty, but get_additional_data()
- # fetches all data needed
- get_key = shared_data.get("entry_data").get("ProfilePage")
-
- if get_key:
- data = get_key[0]
- else:
- data = get_additional_data(browser)
- finally:
- is_private = data["graphql"]["user"]["is_private"]
-
- logger.info(
- "Checked if '{}' is private, and it is: '{}'".format(
- data["graphql"]["user"]["username"], is_private
- )
- )
-
- return is_private
-
-
-# Evaluate a mandatory words list against a text
-def evaluate_mandatory_words(text, mandatory_words_list, level=0):
- if level % 2 == 0:
- # this is an "or" level so at least one of the words of compound sub-conditions should match
- for word in mandatory_words_list:
- if isinstance(word, list):
- res = evaluate_mandatory_words(text, word, level + 1)
- if res:
- return True
- elif word.lower() in text:
- return True
- return False
- else:
- # this is an "and" level so all of the words and compound sub-conditions must match
- for word in mandatory_words_list:
- if isinstance(word, list):
- res = evaluate_mandatory_words(text, word, level + 1)
- if not res:
- return False
- elif word.lower() not in text:
- return False
- return True
-
-
-def validate_username(
- browser,
- username_or_link,
- own_username,
- ignore_users,
- blacklist,
- potency_ratio,
- delimit_by_numbers,
- max_followers,
- max_following,
- min_followers,
- min_following,
- min_posts,
- max_posts,
- skip_private,
- skip_private_percentage,
- skip_public,
- skip_public_percentage,
- skip_no_profile_pic,
- skip_no_profile_pic_percentage,
- skip_business,
- skip_non_business,
- skip_business_percentage,
- skip_business_categories,
- dont_skip_business_categories,
- skip_bio_keyword,
- mandatory_bio_keywords,
- logger,
- logfolder,
-):
- """Check if we can interact with the user"""
-
- # some features may not provide `username` and in those cases we will
- # get it from post's page.
- if "/" in username_or_link:
- link = username_or_link # if there is a `/` in `username_or_link`,
- # then it is a `link`
-
- # check URL of the webpage, if it already is user's profile page,
- # then do not navigate to it again
- web_address_navigator(browser, link)
-
- try:
- username = browser.execute_script(
- "return window._sharedData.entry_data."
- "PostPage[0].graphql.shortcode_media.owner.username"
- )
-
- except WebDriverException:
- try:
- browser.execute_script("location.reload()")
- update_activity(browser, state=None)
-
- username = browser.execute_script(
- "return window._sharedData.entry_data."
- "PostPage[0].graphql.shortcode_media.owner.username"
- )
-
- except WebDriverException:
- logger.error(
- "Username validation failed!\t~cannot get the post "
- "owner's username"
- )
- inap_msg = (
- "--> Sorry, this page isn't available!\t~either "
- "link is broken or page is removed\n"
- )
- return False, inap_msg
-
- else:
- username = username_or_link # if there is no `/` in
- # `username_or_link`, then it is a `username`
-
- if username == own_username:
- inap_msg = "--> Username '{}' is yours!\t~skipping user\n".format(own_username)
- return False, inap_msg
-
- if username in ignore_users:
- inap_msg = "--> '{}' is in the `ignore_users` list\t~skipping " "user\n".format(
- username
- )
- return False, inap_msg
-
- blacklist_file = "{}blacklist.csv".format(logfolder)
- blacklist_file_exists = os.path.isfile(blacklist_file)
- if blacklist_file_exists:
- with open("{}blacklist.csv".format(logfolder), "rt") as f:
- reader = csv.reader(f, delimiter=",")
- for row in reader:
- for field in row:
- if field == username:
- logger.info("Username in BlackList: {} ".format(username))
- return (
- False,
- "--> {} is in blacklist ~skipping "
- "user\n".format(username),
- )
-
- # Checks the potential of target user by relationship status in order
- # to delimit actions within the desired boundary
- if (
- potency_ratio
- or delimit_by_numbers
- and (max_followers or max_following or min_followers or min_following)
- ):
-
- relationship_ratio = None
- reverse_relationship = False
-
- # get followers & following counts
- followers_count, following_count = get_relationship_counts(
- browser, username, logger
- )
-
- if potency_ratio and potency_ratio < 0:
- potency_ratio *= -1
- reverse_relationship = True
-
- # division by zero is bad
- followers_count = 1 if followers_count == 0 else followers_count
- following_count = 1 if following_count == 0 else following_count
-
- if followers_count and following_count:
- relationship_ratio = (
- float(followers_count) / float(following_count)
- if not reverse_relationship
- else float(following_count) / float(followers_count)
- )
-
- logger.info(
- "User: '{}' |> followers: {} |> following: {} |> relationship "
- "ratio: {}".format(
- username,
- followers_count if followers_count else "unknown",
- following_count if following_count else "unknown",
- truncate_float(relationship_ratio, 2)
- if relationship_ratio
- else "unknown",
- )
- )
-
- if followers_count or following_count:
- if potency_ratio and not delimit_by_numbers:
- if relationship_ratio and relationship_ratio < potency_ratio:
- inap_msg = (
- "'{}' is not a {} with the relationship ratio of {} "
- "~skipping user\n".format(
- username,
- "potential user"
- if not reverse_relationship
- else "massive follower",
- truncate_float(relationship_ratio, 2),
- )
- )
- return False, inap_msg
-
- elif delimit_by_numbers:
- if followers_count:
- if max_followers:
- if followers_count > max_followers:
- inap_msg = (
- "User '{}'s followers count exceeds maximum "
- "limit ~skipping user\n".format(username)
- )
- return False, inap_msg
-
- if min_followers:
- if followers_count < min_followers:
- inap_msg = (
- "User '{}'s followers count is less than "
- "minimum limit ~skipping user\n".format(username)
- )
- return False, inap_msg
-
- if following_count:
- if max_following:
- if following_count > max_following:
- inap_msg = (
- "User '{}'s following count exceeds maximum "
- "limit ~skipping user\n".format(username)
- )
- return False, inap_msg
-
- if min_following:
- if following_count < min_following:
- inap_msg = (
- "User '{}'s following count is less than "
- "minimum limit ~skipping user\n".format(username)
- )
- return False, inap_msg
-
- if potency_ratio:
- if relationship_ratio and relationship_ratio < potency_ratio:
- inap_msg = (
- "'{}' is not a {} with the relationship ratio of "
- "{} ~skipping user\n".format(
- username,
- "potential user"
- if not reverse_relationship
- else "massive follower",
- truncate_float(relationship_ratio, 2),
- )
- )
- return False, inap_msg
-
- if min_posts or max_posts or skip_private or skip_no_profile_pic or skip_business:
- user_link = "https://www.instagram.com/{}/".format(username)
- web_address_navigator(browser, user_link)
-
- if min_posts or max_posts:
- # if you are interested in relationship number of posts boundaries
- try:
- number_of_posts = getUserData(
- "graphql.user.edge_owner_to_timeline_media.count", browser
- )
-
- if max_posts:
- if number_of_posts > max_posts:
- inap_msg = (
- "Number of posts ({}) of '{}' exceeds the maximum limit "
- "given {}\n".format(number_of_posts, username, max_posts)
- )
- return False, inap_msg
- if min_posts:
- if number_of_posts < min_posts:
- inap_msg = (
- "Number of posts ({}) of '{}' is less than the minimum "
- "limit given {}\n".format(number_of_posts, username, min_posts)
- )
- return False, inap_msg
- except (WebDriverException, TypeError): # Catch if number_of_posts is NoneType
- logger.error("~cannot get number of posts for username".format(username))
- inap_msg = "--> Sorry, couldn't check for number of posts of username: '{}'\n".format(
- username
- )
- return False, inap_msg
-
- # Skip users
-
- # skip private
- if skip_private:
- try:
- is_private = getUserData("graphql.user.is_private", browser)
-
- if is_private and (random.randint(0, 100) <= skip_private_percentage):
- return False, "{} is private account, by default skip\n".format(
- username
- )
- except:
- logger.error("~could not check if profile is public or private")
- return False, "--> Sorry, could not check if profile is public or private\n"
-
- # skip public
- if skip_public:
- try:
- is_public = not getUserData("graphql.user.is_private", browser)
-
- if is_public and (random.randint(0, 100) <= skip_public_percentage):
- return (
- False,
- "{} is public account, skip because of configuration\n".format(
- username
- ),
- )
- except:
- logger.error("~could not check if profile is public or private")
- return False, "--> Sorry, could not check if profile is public or private\n"
-
- # skip no profile pic
- if skip_no_profile_pic:
- try:
- profile_pic = getUserData("graphql.user.profile_pic_url", browser)
- except WebDriverException:
- logger.error("~cannot get the post profile pic url")
- return False, "--> Sorry, couldn't get if user profile pic url\n"
- if (
- profile_pic in default_profile_pic_instagram
- or str(profile_pic).find("11906329_960233084022564_1448528159_a.jpg") > 0
- ) and (random.randint(0, 100) <= skip_no_profile_pic_percentage):
- return False, "{} has default instagram profile picture\n".format(username)
-
- # skip business
- if skip_business or skip_non_business:
- # if is business account skip under conditions
- try:
- is_business_account = getUserData(
- "graphql.user.is_business_account", browser
- )
- except WebDriverException:
- logger.error("~cannot get if user has business account active")
- return (
- False,
- "--> Sorry, couldn't get if user has business account active\n",
- )
-
- if skip_non_business and not is_business_account:
- return (
- False,
- "--> Skipping non business because skip_non_business set to True",
- )
-
- if is_business_account:
- try:
- category = getUserData("graphql.user.business_category_name", browser)
- except WebDriverException:
- logger.error("~cannot get category name for user")
- return False, "--> Sorry, couldn't get category name for user\n"
-
- if len(skip_business_categories) == 0:
- # skip if not in dont_include
- if category not in dont_skip_business_categories:
- if len(dont_skip_business_categories) == 0 and (
- random.randint(0, 100) <= skip_business_percentage
- ):
- return False, "'{}' has a business account\n".format(username)
- else:
- return (
- False,
- (
- "'{}' has a business account in the "
- "undesired category of '{}'\n".format(
- username, category
- )
- ),
- )
- else:
- if category in skip_business_categories:
- return (
- False,
- (
- "'{}' has a business account in the "
- "undesired category of '{}'\n".format(username, category)
- ),
- )
-
- if len(skip_bio_keyword) > 0 or len(mandatory_bio_keywords) > 0:
- # Navigate to the target user profile to read the Bio
- user_link = "https://www.instagram.com/{}/".format(username)
- web_address_navigator(browser, user_link)
-
- # if contain stop words then skip
- try:
- profile_bio = getUserData("graphql.user.biography", browser).lower()
- except WebDriverException:
- logger.error("~cannot read '{}' bio".format(username))
- return False, "--> Sorry, couldn't get get user bio account active\n"
- for bio_keyword in skip_bio_keyword:
- if bio_keyword.lower() in profile_bio:
- return (
- False,
- "{} has a bio keyword of {}, by default skip\n".format(
- username, bio_keyword
- ),
- )
- # the mandatory keywords applies to the username as well as the bio text
- if mandatory_bio_keywords and not evaluate_mandatory_words(
- username + " " + profile_bio, mandatory_bio_keywords
- ):
- return False, "Mandatory bio keywords not found"
-
- # if everything is ok
- return True, "Valid user"
-
-
-def getUserData(
- query,
- browser,
- basequery="no-longer-needed",
-):
- shared_data = get_shared_data(browser)
-
- # Sometimes shared_data["entry_data"]["ProfilePage"][0] is empty, but get_additional_data()
- # fetches all data needed
- get_key = shared_data.get("entry_data").get("ProfilePage")
-
- if get_key:
- data = get_key[0]
- else:
- data = get_additional_data(browser)
-
- if query.find(".") == -1:
- data = data[query]
- else:
- subobjects = query.split(".")
- for subobject in subobjects:
- data = data[subobject]
-
- return data
-
-
-def getMediaData(
- query,
- browser,
-):
- additional_data = get_additional_data(browser)
- data = additional_data["graphql"]["shortcode_media"]
-
- if query.find(".") == -1:
- data = data[query]
- else:
- subobjects = query.split(".")
- for subobject in subobjects:
- data = data[subobject]
-
- return data
-
-
-def update_activity(
- browser=None, action="server_calls", state=None, logfolder=None, logger=None
-):
- """
- 1. Record every Instagram server call (page load, content load, likes,
- comments, follows, unfollow)
- 2. Take rotative screenshots
- 3. update connection state and record to .json file
- """
- # check action availability
- quota_supervisor("server_calls")
-
- # take screen shot
- if browser and logfolder and logger:
- take_rotative_screenshot(browser, logfolder)
-
- # update state to JSON file
- if state and logfolder and logger:
- try:
- path = "{}state.json".format(logfolder)
- data = {}
- # check if file exists and has content
- if os.path.isfile(path) and os.path.getsize(path) > 0:
- # load JSON file
- with open(path, "r") as json_file:
- data = json.load(json_file)
-
- # update connection state
- connection_data = {}
- connection_data["connection"] = state
- data["state"] = connection_data
-
- # write to JSON file
- with open(path, "w") as json_file:
- json.dump(data, json_file, indent=4)
- except Exception:
- logger.warning("Unable to update JSON state file")
-
- # in case is just a state update and there is no server call
- if action is None:
- return
-
- # get a DB, start a connection and sum a server call
- db, id = get_database()
- conn = sqlite3.connect(db)
-
- with conn:
- conn.row_factory = sqlite3.Row
- cur = conn.cursor()
- # collect today data
- cur.execute(
- "SELECT * FROM recordActivity WHERE profile_id=:var AND "
- "STRFTIME('%Y-%m-%d %H', created) == STRFTIME('%Y-%m-%d "
- "%H', 'now', 'localtime')",
- {"var": id},
- )
- data = cur.fetchone()
-
- if data is None:
- # create a new record for the new day
- cur.execute(
- "INSERT INTO recordActivity VALUES "
- "(?, 0, 0, 0, 0, 1, STRFTIME('%Y-%m-%d %H:%M:%S', "
- "'now', 'localtime'))",
- (id,),
- )
-
- else:
- # sqlite3.Row' object does not support item assignment -> so,
- # convert it into a new dict
- data = dict(data)
-
- # update
- data[action] += 1
- quota_supervisor(action, update=True)
-
- if action != "server_calls":
- # always update server calls
- data["server_calls"] += 1
- quota_supervisor("server_calls", update=True)
-
- sql = (
- "UPDATE recordActivity set likes = ?, comments = ?, "
- "follows = ?, unfollows = ?, server_calls = ?, "
- "created = STRFTIME('%Y-%m-%d %H:%M:%S', 'now', "
- "'localtime') "
- "WHERE profile_id=? AND STRFTIME('%Y-%m-%d %H', created) "
- "== "
- "STRFTIME('%Y-%m-%d %H', 'now', 'localtime')"
- )
-
- cur.execute(
- sql,
- (
- data["likes"],
- data["comments"],
- data["follows"],
- data["unfollows"],
- data["server_calls"],
- id,
- ),
- )
-
- # commit the latest changes
- conn.commit()
-
-
-def add_user_to_blacklist(username, campaign, action, logger, logfolder):
- file_exists = os.path.isfile("{}blacklist.csv".format(logfolder))
- fieldnames = ["date", "username", "campaign", "action"]
- today = datetime.date.today().strftime("%m/%d/%y")
-
- try:
- with open("{}blacklist.csv".format(logfolder), "a+") as blacklist:
- writer = csv.DictWriter(blacklist, fieldnames=fieldnames)
- if not file_exists:
- writer.writeheader()
- writer.writerow(
- {
- "date": today,
- "username": username,
- "campaign": campaign,
- "action": action,
- }
- )
- except Exception as err:
- logger.error(
- "blacklist dictWrite error \n\t{}".format(str(err).encode("utf-8"))
- )
-
- logger.info(
- "--> {} added to blacklist for {} campaign (action: {})".format(
- username, campaign, action
- )
- )
-
-
-def get_active_users(browser, username, posts, boundary, logger):
- """Returns a list with usernames who liked the latest n posts"""
-
- user_link = "https://www.instagram.com/{}/".format(username)
-
- # check URL of the webpage, if it already is user's profile page,
- # then do not navigate to it again
- web_address_navigator(browser, user_link)
-
- try:
- total_posts = browser.execute_script(
- "return window._sharedData.entry_data."
- "ProfilePage[0].graphql.user.edge_owner_to_timeline_media.count"
- )
- except WebDriverException:
- try:
- topCount_elements = browser.find_elements(
- By.XPATH, read_xpath(get_active_users.__name__, "topCount_elements")
- )
-
- if topCount_elements: # prevent an empty string scenario
- total_posts = format_number(topCount_elements[0].text)
- else:
- logger.info("Failed to get posts count on your profile! ~empty string")
- total_posts = None
- except NoSuchElementException:
- logger.info("Failed to get posts count on your profile!")
- total_posts = None
-
- # if posts > total user posts, assume total posts
- posts = (
- posts if total_posts is None else total_posts if posts > total_posts else posts
- )
-
- active_users = []
- sc_rolled = 0
- start_time = time.time()
- too_many_requests = 0 # helps to prevent misbehaviours when requests
- # list of active users repeatedly within less than 10 min of breaks
-
- message = (
- "~collecting the entire usernames from posts without a boundary!\n"
- if boundary is None
- else "~collecting only the visible usernames from posts without scrolling "
- "at the boundary of zero..\n"
- if boundary == 0
- else "~collecting the usernames from posts with the boundary of {}"
- "\n".format(boundary)
- )
- # posts argument is the number of posts to collect usernames
- logger.info(
- "Getting active users who liked the latest {} posts:\n {}".format(
- posts, message
- )
- )
-
- count = 1
- checked_posts = 0
- user_list = []
-
- while count <= posts:
- # load next post
- try:
- latest_post = browser.find_element(
- By.XPATH,
- read_xpath(get_active_users.__name__, "profile_posts").format(count),
- )
- # avoid no posts
- if latest_post:
- click_element(browser, latest_post)
- except (NoSuchElementException, WebDriverException):
- logger.warning("Failed to click on the latest post to grab active likers!")
- return []
- try:
- checked_posts += 1
- sleep_actual(2)
-
- try:
- likers_count = browser.find_element(
- By.XPATH, read_xpath(get_active_users.__name__, "likers_count")
- ).text
- if likers_count: # prevent an empty string scenarios
- likers_count = format_number(likers_count)
- # liked by 'username' AND 165 others (166 in total)
- likers_count += 1
- else:
- logger.info(
- "Failed to get likers count on your post {} "
- "~empty string".format(count)
- )
- likers_count = None
- except NoSuchElementException:
- logger.info("Failed to get likers count on your post {}".format(count))
- likers_count = None
- try:
- likes_button = browser.find_elements(
- By.XPATH, read_xpath(get_active_users.__name__, "likes_button")
- )
-
- if likes_button != []:
- if likes_button[1] is not None:
- likes_button = likes_button[1]
- else:
- likes_button = likes_button[0]
- click_element(browser, likes_button)
- sleep_actual(3)
- else:
- raise NoSuchElementException
-
- except (IndexError, NoSuchElementException):
- # Video have no likes button / no posts in page
- logger.info("Video found, try next post until we run out of posts")
-
- # edge case of account having only videos, or last post is a video.
- if checked_posts >= total_posts:
- break
- # if not reached posts(parameter) value, continue (but load next post)
- browser.back()
- # go to next post
- count += 1
- continue
-
- # get a reference to the 'Likes' dialog box
- dialog = browser.find_element(
- By.XPATH, read_xpath("class_selectors", "likes_dialog_body_xpath")
- )
-
- scroll_it = True
- try_again = 0
- start_time = time.time()
-
- if likers_count:
- amount = (
- likers_count
- if boundary is None
- else None
- if boundary == 0
- else (boundary if boundary < likers_count else likers_count)
- )
- else:
- amount = None
- tmp_scroll_height = 0
- user_list_len = -1
- while scroll_it is not False and boundary != 0:
- scroll_height = browser.execute_script(
- """
- let main = document.getElementsByTagName('main')
- return main[0].scrollHeight
- """
- )
- # check if it should keep scrolling down or exit
- if (
- scroll_height >= tmp_scroll_height
- and len(user_list) > user_list_len
- ):
- tmp_scroll_height = scroll_height
- user_list_len = len(user_list)
- scroll_it = True
- else:
- scroll_it = False
-
- if scroll_it is True:
- scroll_it = browser.execute_script("window.scrollBy(0, 1000)")
- update_activity(browser, state=None)
-
- if sc_rolled > 91 or too_many_requests > 1: # old value 100
- print("\n")
- logger.info("Too Many Requests sent! ~will sleep some :>\n")
- sleep_actual(600)
- sc_rolled = 0
- too_many_requests = (
- 0 if too_many_requests >= 1 else too_many_requests
- )
-
- else:
- sleep_actual(1.2) # old value 5.6
- sc_rolled += 1
-
- user_list = get_users_from_dialog(user_list, dialog, logger)
-
- # write & update records at Progress Tracker
- if amount:
- progress_tracker(len(user_list), amount, start_time, None)
- print("\n")
-
- if boundary is not None:
- if len(user_list) >= boundary:
- break
-
- if (
- scroll_it is False
- and likers_count
- and likers_count - 1 > len(user_list)
- ):
-
- if (
- boundary is not None and likers_count - 1 > boundary
- ) or boundary is None:
-
- if try_again <= 1: # can increase the amount of tries
- logger.info(
- "Failed to get the desired amount of "
- "usernames but trying again..."
- "\t|> post: {} |> attempt: {}\n".format(
- posts, try_again + 1
- )
- )
- try_again += 1
- too_many_requests += 1
- scroll_it = True
- nap_it = 4 if try_again == 0 else 7
- sleep_actual(nap_it)
-
- user_list = get_users_from_dialog(user_list, dialog, logger)
-
- logger.info(
- "Post {} | Likers: found {}, catched {}\n\n".format(
- count, likers_count, len(user_list)
- )
- )
- except NoSuchElementException as exc:
- logger.error(
- "Ku-ku! There is an error searching active users"
- "~\t{}\n\n".format(str(exc).encode("utf-8"))
- )
-
- for user in user_list:
- active_users.append(user)
-
- sleep_actual(1)
-
- # if not reached posts(parameter) value, continue
- if count != posts + 1:
- try:
- # click close button
- close_dialog_box(browser)
- browser.back()
- except Exception:
- logger.error("Unable to go to next profile post")
- count += 1
-
- real_time = time.time()
- diff_in_minutes = int((real_time - start_time) / 60)
- diff_in_seconds = int((real_time - start_time) % 60)
-
- # delete duplicated users
- active_users = list(set(active_users))
-
- logger.info(
- "Gathered total of {} unique active followers from the latest {} "
- "posts in {} minutes and {} seconds".format(
- len(active_users), posts, diff_in_minutes, diff_in_seconds
- )
- )
-
- return active_users
-
-
-def delete_line_from_file(filepath, userToDelete, logger):
- """Remove user's record from the followed pool file after unfollowing"""
- if not os.path.isfile(filepath):
- # in case of there is no any followed pool file yet
- return 0
-
- try:
- file_path_old = filepath + ".old"
- file_path_Temp = filepath + ".temp"
-
- with open(filepath, "r") as f:
- lines = f.readlines()
-
- with open(file_path_Temp, "w") as f:
- for line in lines:
- entries = line.split(" ~ ")
- sz = len(entries)
- if sz == 1:
- user = entries[0][:-2]
- elif sz == 2:
- user = entries[1][:-2]
- else:
- user = entries[1]
-
- if user == userToDelete:
- slash_in_filepath = "/" if "/" in filepath else "\\"
- filename = filepath.split(slash_in_filepath)[-1]
- logger.info(
- "\tRemoved '{}' from {} file".format(
- line.split(",\n")[0], filename
- )
- )
-
- else:
- f.write(line)
-
- # File leftovers that should not exist, but if so remove it
- while os.path.isfile(file_path_old):
- try:
- os.remove(file_path_old)
-
- except OSError as e:
- logger.error(
- "Can't remove file_path_old \n\t{}".format(str(e).encode("utf-8"))
- )
-
- # rename original file to _old
- os.rename(filepath, file_path_old)
-
- # rename new temp file to filepath
- while os.path.isfile(file_path_Temp):
- try:
- os.rename(file_path_Temp, filepath)
-
- except OSError as e:
- logger.error(
- "Can't rename file_path_Temp to filepath \n\t{}".format(
- str(e).encode("utf-8")
- )
- )
- sleep(5)
-
- # remove old and temp file
- os.remove(file_path_old)
-
- except BaseException as e:
- logger.error(
- "delete_line_from_file error \n\t{}".format(str(e).encode("utf-8"))
- )
-
-
-def scroll_bottom(browser, element, range_int):
- # put a limit to the scrolling
- if range_int > 50:
- range_int = 50
-
- for _ in range(int(range_int / 2)):
- # scroll down the page by 1000 pixels every time
- browser.execute_script("window.scrollBy(0, 1000)")
- # update server calls
- update_activity(browser, state=None)
- sleep(1)
-
- return
-
-
-def scroll_down(browser, y: int = 50):
- """
- Scroll down the page by 50 pixels
-
- This is intended mainly for accept_follow_requests(), since user could
- have several request to be accepted. By default only 10 users are shown,
- but InstaPy user could requested to accept more than 10.
-
- :param y: number of pixels to be moved
- """
-
- browser.execute_script("window.scrollBy(0, {})".format(y))
- # update server calls
- update_activity(browser, state=None)
- sleep(randint(1, 5))
-
- return
-
-
-def click_element(browser, element, tryNum=0):
- """
- There are three (maybe more) different ways to "click" an element/button.
- 1. element.click()
- 2. element.send_keys("\n")
- 3. browser.execute_script("document.getElementsByClassName('" +
- element.get_attribute("class") + "')[0].click()")
-
- I'm guessing all three have their advantages/disadvantages
- Before committing over this code, you MUST justify your change
- and potentially adding an 'if' statement that applies to your
- specific case. See the following issue for more details
- https://github.com/timgrossmann/InstaPy/issues/1232
-
- explanation of the following recursive function:
- we will attempt to click the element given, if an error is thrown
- we know something is wrong (element not in view, element doesn't
- exist, ...). on each attempt try and move the screen around in
- various ways. if all else fails, programmically click the button
- using `execute_script` in the browser.
- """
-
- try:
- # use Selenium's built in click function
- element.click()
-
- # update server calls after a successful click by selenium
- update_activity(browser, state=None)
-
- except Exception:
- # click attempt failed
- # try something funky and try again
-
- if tryNum == 0:
- # try scrolling the element into view
- try:
- # This tends to fail because the script fails to get the element class
- if element.get_attribute("class") != "":
- browser.execute_script(
- "document.getElementsByClassName('"
- + element.get_attribute("class")
- + "')[0].scrollIntoView({ inline: 'center' });"
- )
- except Exception:
- pass
-
- elif tryNum == 1:
- # well, that didn't work, try scrolling to the top and then
- # clicking again
- browser.execute_script("window.scrollTo(0,0);")
-
- elif tryNum == 2:
- # that didn't work either, try scrolling to the bottom and then
- # clicking again
- browser.execute_script("window.scrollTo(0,document.body.scrollHeight);")
-
- else:
- # try `execute_script` as a last resort
- # print("attempting last ditch effort for click, `execute_script`")
- try:
- if element.get_attribute("class") != "":
- browser.execute_script(
- "document.getElementsByClassName('"
- + element.get_attribute("class")
- + "')[0].click()"
- )
- # update server calls after last click attempt by JS
- update_activity(browser, state=None)
- except Exception:
- print("Failed to click an element, giving up now")
-
- # end condition for the recursive function
- return
-
- # update server calls after the scroll(s) in 0, 1 and 2 attempts
- update_activity(browser, state=None)
-
- # sleep for 1 second to allow window to adjust (may or may not be
- # needed)
- sleep_actual(1)
-
- tryNum += 1
-
- # try again!
- click_element(browser, element, tryNum)
-
-
-def format_number(number):
- """
- Format number. Remove the unused comma. Replace the concatenation with
- relevant zeros. Remove the dot.
-
- :param number: str
-
- :return: int
- """
- formatted_num = number.replace(",", "")
- formatted_num = re.sub(
- r"(k)$", "00" if "." in formatted_num else "000", formatted_num
- )
- formatted_num = re.sub(
- r"(m)$", "00000" if "." in formatted_num else "000000", formatted_num
- )
- formatted_num = formatted_num.replace(".", "")
- return int(formatted_num)
-
-
-def username_url_to_username(username_url):
- a = username_url.replace("https://www.instagram.com/", "")
- username = a.split("/")
- return username[0]
-
-
-def get_number_of_posts(browser):
- """Get the number of posts from the profile screen"""
- try:
- num_of_posts = getUserData(
- "graphql.user.edge_owner_to_timeline_media.count", browser
- )
- except WebDriverException:
- try:
- num_of_posts_txt = browser.find_element(
- By.XPATH, read_xpath(get_number_of_posts.__name__, "num_of_posts_txt")
- ).text
-
- except NoSuchElementException:
- num_of_posts_txt = browser.find_element(
- By.XPATH,
- read_xpath(
- get_number_of_posts.__name__, "num_of_posts_txt_no_such_element"
- ),
- ).text
-
- num_of_posts_txt = num_of_posts_txt.replace(" ", "")
- num_of_posts_txt = num_of_posts_txt.replace(",", "")
- num_of_posts = int(num_of_posts_txt)
-
- return num_of_posts
-
-
-def get_relationship_counts(browser, username, logger):
- """Gets the followers & following counts of a given user"""
-
- user_link = "https://www.instagram.com/{}/".format(username)
-
- # check URL of the webpage, if it already is user's profile page,
- # then do not navigate to it again
- web_address_navigator(browser, user_link)
-
- try:
- followers_count = browser.execute_script(
- "return window._sharedData.entry_data."
- "ProfilePage[0].graphql.user.edge_followed_by.count"
- )
-
- except WebDriverException:
- try:
- followers_count = format_number(
- browser.find_element(
- By.XPATH,
- str(
- read_xpath(get_relationship_counts.__name__, "followers_count")
- ),
- ).text
- )
- except NoSuchElementException:
- try:
- browser.execute_script("location.reload()")
- update_activity(browser, state=None)
-
- followers_count = browser.execute_script(
- "return window._sharedData.entry_data."
- "ProfilePage[0].graphql.user.edge_followed_by.count"
- )
-
- except WebDriverException:
- try:
- topCount_elements = browser.find_elements(
- By.XPATH,
- read_xpath(
- get_relationship_counts.__name__, "topCount_elements"
- ),
- )
-
- if topCount_elements:
- followers_count = format_number(topCount_elements[1].text)
- else:
- logger.info(
- "Failed to get followers count of '{}' ~empty "
- "list".format(username.encode("utf-8"))
- )
- followers_count = None
-
- except NoSuchElementException:
- logger.error(
- "Error occurred during getting the followers count "
- "of '{}'\n".format(username.encode("utf-8"))
- )
- followers_count = None
-
- try:
- following_count = browser.execute_script(
- "return window._sharedData.entry_data."
- "ProfilePage[0].graphql.user.edge_follow.count"
- )
-
- except WebDriverException:
- try:
- following_count = format_number(
- browser.find_element(
- By.XPATH,
- str(
- read_xpath(get_relationship_counts.__name__, "following_count")
- ),
- ).text
- )
-
- except NoSuchElementException:
- try:
- browser.execute_script("location.reload()")
- update_activity(browser, state=None)
-
- following_count = browser.execute_script(
- "return window._sharedData.entry_data."
- "ProfilePage[0].graphql.user.edge_follow.count"
- )
-
- except WebDriverException:
- try:
- topCount_elements = browser.find_elements(
- By.XPATH,
- read_xpath(
- get_relationship_counts.__name__, "topCount_elements"
- ),
- )
-
- if topCount_elements:
- following_count = format_number(topCount_elements[2].text)
- else:
- logger.info(
- "Failed to get following count of '{}' ~empty "
- "list".format(username.encode("utf-8"))
- )
- following_count = None
-
- except (NoSuchElementException, IndexError):
- logger.error(
- "\nError occurred during getting the following count "
- "of '{}'\n".format(username.encode("utf-8"))
- )
- following_count = None
-
- Event().profile_data_updated(username, followers_count, following_count)
- return followers_count, following_count
-
-
-def web_address_navigator(browser, link):
- """Checks and compares current URL of web page and the URL to be
- navigated and if it is different, it does navigate"""
- current_url = get_current_url(browser)
- total_timeouts = 0
- page_type = None # file or directory
-
- # remove slashes at the end to compare efficiently
- if current_url is not None and current_url.endswith("/"):
- current_url = current_url[:-1]
-
- if link.endswith("/"):
- link = link[:-1]
- page_type = "dir" # slash at the end is a directory
-
- new_navigation = current_url != link
-
- if current_url is None or new_navigation:
- link = link + "/" if page_type == "dir" else link # directory links
- # navigate faster
-
- while True:
- try:
- browser.get(link)
- # update server calls
- update_activity(browser, state=None)
- sleep(2)
- break
-
- except TimeoutException as exc:
- if total_timeouts >= 7:
- raise TimeoutException(
- "Retried {} times to GET '{}' webpage "
- "but failed out of a timeout!\n\t{}".format(
- total_timeouts,
- str(link).encode("utf-8"),
- str(exc).encode("utf-8"),
- )
- )
- total_timeouts += 1
- sleep(2)
-
-
-@contextmanager
-def interruption_handler(
- threaded=False,
- SIG_type=signal.SIGINT,
- handler=signal.SIG_IGN,
- notify=None,
- logger=None,
-):
- """Handles external interrupt, usually initiated by the user like
- KeyboardInterrupt with CTRL+C"""
- if notify is not None and logger is not None:
- logger.warning(notify)
-
- original_handler = None
-
- if not threaded:
- original_handler = signal.signal(SIG_type, handler)
-
- try:
- yield
-
- finally:
- if not threaded:
- signal.signal(SIG_type, original_handler)
-
-
-def highlight_print(
- username=None, message=None, priority=None, level=None, logger=None
-):
- """Print headers in a highlighted style"""
- # can add other highlighters at other priorities enriching this function
-
- # find the number of chars needed off the length of the logger message
- output_len = 28 + len(username) + 3 + len(message) if logger else len(message)
- show_logs = Settings.show_logs
- upper_char = None
- lower_char = None
-
- if priority in ["initialization", "end"]:
- # OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
- # E.g.: Session started!
- # oooooooooooooooooooooooooooooooooooooooooooooooo
- upper_char = "O"
- lower_char = "o"
-
- elif priority == "login":
- # ................................................
- # E.g.: Logged in successfully!
- # ''''''''''''''''''''''''''''''''''''''''''''''''
- upper_char = "."
- lower_char = "'"
-
- elif priority == "feature": # feature highlighter
- # ________________________________________________
- # E.g.: Starting to interact by users..
- # """"""""""""""""""""""""""""""""""""""""""""""""
- upper_char = "_"
- lower_char = '"'
-
- elif priority == "user iteration":
- # ::::::::::::::::::::::::::::::::::::::::::::::::
- # E.g.: User: [1/4]
- upper_char = ":"
- lower_char = None
-
- elif priority == "post iteration":
- # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- # E.g.: Post: [2/10]
- upper_char = "~"
- lower_char = None
-
- elif priority == "workspace":
- # ._. ._. ._. ._. ._. ._. ._. ._. ._. ._. ._. ._.
- # E.g.: |> Workspace in use: "C:/Users/El/InstaPy"
- upper_char = " ._. "
- lower_char = None
-
- if upper_char and (show_logs or priority == "workspace"):
- print("{}".format(upper_char * int(ceil(output_len / len(upper_char)))))
-
- if level == "info":
- if logger:
- logger.info(message)
- else:
- print(message)
-
- elif level == "warning":
- if logger:
- logger.warning(message)
- else:
- print(message)
-
- elif level == "critical":
- if logger:
- logger.critical(message)
- else:
- print(message)
-
- if lower_char and (show_logs or priority == "workspace"):
- print("{}".format(lower_char * int(ceil(output_len / len(lower_char)))))
-
-
-def remove_duplicates(container, keep_order, logger):
- """Remove duplicates from all kinds of data types easily"""
- # add support for data types as needed in future
- # currently only 'list' data type is supported
- if isinstance(container, list):
- if keep_order is True:
- result = sorted(set(container), key=container.index)
-
- else:
- result = set(container)
-
- else:
- if not logger:
- logger = Settings.logger
-
- logger.warning(
- "The given data type- '{}' is not supported "
- "in `remove_duplicates` function, yet!".format(type(container))
- )
- result = container
-
- return result
-
-
-def dump_record_activity(profile_name, logger, logfolder):
- """Dump the record activity data to a local human-readable JSON"""
-
- conn = None
-
- try:
- # get a DB and start a connection
- db, id = get_database()
- conn = sqlite3.connect(db)
-
- with conn:
- conn.row_factory = sqlite3.Row
- cur = conn.cursor()
-
- cur.execute(
- "SELECT * FROM recordActivity WHERE profile_id=:var", {"var": id}
- )
- user_data = cur.fetchall()
-
- if user_data:
- ordered_user_data = {}
- current_data = {}
-
- # get the existing data
- filename = "{}recordActivity.json".format(logfolder)
- if os.path.isfile(filename):
- with open(filename) as recordActFile:
- current_data = json.load(recordActFile)
-
- # re-order live user data in the required structure
- for hourly_data in user_data:
- hourly_data = tuple(hourly_data)
- day = hourly_data[-1][:10]
- hour = hourly_data[-1][-8:-6]
-
- if day not in ordered_user_data.keys():
- ordered_user_data.update({day: {}})
-
- ordered_user_data[day].update(
- {
- hour: {
- "likes": hourly_data[1],
- "comments": hourly_data[2],
- "follows": hourly_data[3],
- "unfollows": hourly_data[4],
- "server_calls": hourly_data[5],
- }
- }
- )
-
- # update user data with live data whilst preserving all other
- # data (keys)
- current_data.update({profile_name: ordered_user_data})
-
- # dump the fresh record data to a local human readable JSON
- with open(filename, "w") as recordActFile:
- json.dump(current_data, recordActFile)
-
- except Exception as exc:
- logger.error(
- "Pow! Error occurred while dumping record activity data to a "
- "local JSON:\n\t{}".format(str(exc).encode("utf-8"))
- )
-
- finally:
- if conn:
- # close the open connection
- conn.close()
-
-
-def ping_server(host, logger):
- """
- Return True if host (str) responds to a ping request.
- Remember that a host may not respond to a ping (ICMP) request even if
- the host name is valid.
- """
- logger.info("Pinging '{}' to check the connectivity...".format(str(host)))
-
- # ping command count option as function of OS
- param = "-n" if system().lower() == "windows" else "-c"
- # building the command. Ex: "ping -c 1 google.com"
- command = " ".join(["ping", param, "1", str(host)])
- need_sh = False if system().lower() == "windows" else True
-
- # pinging
- ping_attempts = 2
- connectivity = None
-
- while connectivity is not True and ping_attempts > 0:
- connectivity = call(command, shell=need_sh) == 0
-
- if connectivity is False:
- logger.warning(
- "Pinging the server again!\t~total attempts left: {}".format(
- ping_attempts
- )
- )
- ping_attempts -= 1
- sleep(5)
-
- if connectivity is False:
- logger.critical("There is no connection to the '{}' server!".format(host))
- return False
-
- return True
-
-
-def emergency_exit(browser, username, logger):
- """Raise emergency if the is no connection to server OR if user is not
- logged in"""
- server_address = "instagram.com"
- connection_state = ping_server(server_address, logger)
- if connection_state is False:
- return True, "not connected"
-
- # check if the user is logged in
- auth_method = "activity counts"
- login_state = check_authorization(browser, username, auth_method, logger)
- if login_state is False:
- return True, "not logged in"
-
- return False, "no emergency"
-
-
-def load_user_id(username, person, logger, logfolder):
- """Load the user ID at request from local records"""
- pool_name = "{0}{1}_followedPool.csv".format(logfolder, username)
- user_id = "undefined"
-
- try:
- with open(pool_name, "r+") as followedPoolFile:
- reader = csv.reader(followedPoolFile)
-
- for row in reader:
- entries = row[0].split(" ~ ")
- if len(entries) < 3:
- # old entry which does not contain an ID
- pass
-
- user_name = entries[1]
- if user_name == person:
- user_id = entries[2]
- break
-
- followedPoolFile.close()
-
- except BaseException as exc:
- logger.exception(
- "Failed to load the user ID of '{}'!\n\t{}".format(
- person, str(exc).encode("utf-8")
- )
- )
-
- return user_id
-
-
-def check_authorization(browser, username, method, logger, notify=True):
- """Check if user is NOW logged in"""
- if notify is True:
- logger.info("Checking if '{}' is logged in...".format(username))
-
- # different methods can be added in future
- if method == "activity counts":
-
- # navigate to owner's profile page only if it is on an unusual page
- current_url = get_current_url(browser)
- if (
- not current_url
- or "https://www.instagram.com" not in current_url
- or "https://www.instagram.com/graphql/" in current_url
- ):
- profile_link = "https://www.instagram.com/{}/".format(username)
- web_address_navigator(browser, profile_link)
-
- # if user is not logged in, `activity_counts` will be `None`- JS `null`
- try:
- activity_counts = browser.execute_script(
- "return window._sharedData.activity_counts"
- )
-
- except WebDriverException:
- try:
- browser.execute_script("location.reload()")
- update_activity(browser, state=None)
-
- activity_counts = browser.execute_script(
- "return window._sharedData.activity_counts"
- )
-
- except WebDriverException:
- activity_counts = None
-
- # if user is not logged in, `activity_counts_new` will be `None`- JS
- # `null`
- try:
- activity_counts_new = browser.execute_script(
- "return window._sharedData.config.viewer"
- )
-
- except WebDriverException:
- try:
- browser.execute_script("location.reload()")
- activity_counts_new = browser.execute_script(
- "return window._sharedData.config.viewer"
- )
-
- except WebDriverException:
- activity_counts_new = None
-
- if activity_counts is None and activity_counts_new is None:
- if notify is True:
- logger.critical("--> '{}' is not logged in!\n".format(username))
- return False
-
- return True
-
-
-def get_username(browser, track, logger):
- """Get the username of a user from the loaded profile page"""
-
- query = None
-
- if track == "profile":
- query = "return window._sharedData.entry_data. \
- ProfilePage[0].graphql.user.username"
-
- elif track == "post":
- query = "return window._sharedData.entry_data. \
- PostPage[0].graphql.shortcode_media.owner.username"
-
- try:
- username = browser.execute_script(query)
-
- except WebDriverException:
- try:
- browser.execute_script("location.reload()")
- update_activity(browser, state=None)
-
- username = browser.execute_script(query)
-
- except WebDriverException:
- current_url = get_current_url(browser)
- logger.info(
- "Failed to get the username from '{}' page".format(
- current_url or "user" if track == "profile" else "post"
- )
- )
- username = None
-
- # in future add XPATH ways of getting username
-
- return username
-
-
-def find_user_id(browser, track, username, logger):
- """Find the user ID from the loaded page"""
-
- query = None
- meta_XP = None
-
- logger.info(
- "Attempting to find user ID: Track: {}, Username {}".format(track, username)
- )
- if track in ["dialog", "profile"]:
- query = "return window.__additionalData[Object.keys(window.__additionalData)[0]].data.graphql.user.id"
-
- elif track == "post":
- query = "return window._sharedData.entry_data.ProfilePage[0].graphql.user.id"
- meta_XP = read_xpath(find_user_id.__name__, "meta_XP")
-
- failure_message = "Failed to get the user ID of '{}' from {} page!".format(
- username, track
- )
-
- try:
- user_id = browser.execute_script(query)
-
- except WebDriverException:
- try:
- browser.execute_script("location.reload()")
- update_activity(browser, state=None)
-
- user_id = browser.execute_script(
- "return window._sharedData.entry_data.ProfilePage[0].graphql.user.id"
- )
-
- except WebDriverException:
- if track == "post":
- try:
- user_id = browser.find_element(By.XPATH, meta_XP).get_attribute(
- "content"
- )
- if user_id:
- user_id = format_number(user_id)
-
- else:
- logger.error("{}\t~empty string".format(failure_message))
- user_id = None
-
- except NoSuchElementException:
- logger.error(failure_message)
- user_id = None
-
- else:
- logger.error(failure_message)
- user_id = None
-
- return user_id
-
-
-@contextmanager
-def new_tab(browser):
- """USE once a host tab must remain untouched and yet needs extra data-
- get from guest tab"""
- try:
- # add a guest tab
- browser.execute_script("window.open()")
- sleep(1)
- # switch to the guest tab
- browser.switch_to.window(browser.window_handles[1])
- sleep(2)
- yield
-
- finally:
- # close the guest tab
- browser.execute_script("window.close()")
- sleep(1)
- # return to the host tab
- browser.switch_to.window(browser.window_handles[0])
- sleep(2)
-
-
-def explicit_wait(browser, track, ec_params, logger, timeout=35, notify=True):
- """
- Explicitly wait until expected condition validates
-
- :param browser: webdriver instance
- :param track: short name of the expected condition
- :param ec_params: expected condition specific parameters - [param1, param2]
- :param logger: the logger instance
- """
- # list of available tracks:
- #
-
- if not isinstance(ec_params, list):
- ec_params = [ec_params]
-
- # find condition according to the tracks
- condition = None
- ec_name = None
-
- if track == "VOEL":
- elem_address, find_method = ec_params
- ec_name = "visibility of element located"
-
- find_by = (
- By.XPATH
- if find_method == "XPath"
- else By.CSS_SELECTOR
- if find_method == "CSS"
- else By.CLASS_NAME
- )
- locator = (find_by, elem_address)
- condition = ec.visibility_of_element_located(locator)
-
- elif track == "TC":
- expect_in_title = ec_params[0]
- ec_name = "title contains '{}' string".format(expect_in_title)
-
- condition = ec.title_contains(expect_in_title)
-
- elif track == "PFL":
- ec_name = "page fully loaded"
- condition = lambda browser: browser.execute_script(
- "return document.readyState"
- ) in ["complete" or "loaded"]
-
- elif track == "SO":
- ec_name = "staleness of"
- element = ec_params[0]
-
- condition = ec.staleness_of(element)
-
- # generic wait block
- try:
- wait = WebDriverWait(browser, timeout)
- result = wait.until(condition)
-
- except TimeoutException:
- if notify is True:
- logger.info(
- "Timed out with failure while explicitly waiting until {}!\n".format(
- ec_name
- )
- )
- return False
-
- return result
-
-
-def get_current_url(browser):
- """Get URL of the loaded webpage"""
- try:
- current_url = browser.execute_script("return window.location.href")
-
- except WebDriverException:
- try:
- current_url = browser.current_url
-
- except WebDriverException:
- current_url = None
-
- return current_url
-
-
-def get_username_from_id(browser, user_id, logger):
- """Convert user ID to username"""
- # method using graphql 'Account media' endpoint
- logger.info("Trying to find the username from the given user ID by loading a post")
-
- query_hash = "42323d64886122307be10013ad2dcc44" # earlier-
- # "472f257a40c653c64c666ce877d59d2b"
- graphql_query_URL = "https://www.instagram.com/graphql/query/?query_hash={}".format(
- query_hash
- )
- variables = {"id": str(user_id), "first": 1}
- post_url = "{}&variables={}".format(graphql_query_URL, str(json.dumps(variables)))
-
- web_address_navigator(browser, post_url)
- try:
- pre = browser.find_element(By.TAG_NAME, "pre").text
- except NoSuchElementException:
- logger.info("Encountered an error to find `pre` in page, skipping username.")
- return None
- user_data = json.loads(pre)["data"]["user"]
-
- if user_data:
- user_data = user_data["edge_owner_to_timeline_media"]
-
- if user_data["edges"]:
- post_code = user_data["edges"][0]["node"]["shortcode"]
- post_page = "https://www.instagram.com/p/{}".format(post_code)
-
- web_address_navigator(browser, post_page)
- username = get_username(browser, "post", logger)
- if username:
- return username
-
- else:
- if user_data["count"] == 0:
- logger.info("Profile with ID {}: no pics found".format(user_id))
-
- else:
- logger.info(
- "Can't load pics of a private profile to find username ("
- "ID: {})".format(user_id)
- )
-
- else:
- logger.info(
- "No profile found, the user may have blocked you (ID: {})".format(user_id)
- )
- return None
-
- """ method using private API
- #logger.info("Trying to find the username from the given user ID by a
- quick API call")
-
- #req = requests.get(u"https://i.instagram.com/api/v1/users/{}/info/"
- # .format(user_id))
- #if req:
- # data = json.loads(req.text)
- # if data["user"]:
- # username = data["user"]["username"]
- # return username
- """
-
- """ Having a BUG (random log-outs) with the method below, use it only in
- the external sessions
- # method using graphql 'Follow' endpoint
- logger.info("Trying to find the username from the given user ID "
- "by using the GraphQL Follow endpoint")
-
- user_link_by_id = ("https://www.instagram.com/web/friendships/{}/follow/"
- .format(user_id))
-
- web_address_navigator(browser, user_link_by_id)
- username = get_username(browser, "profile", logger)
- """
-
- return None
-
-
-def is_page_available(browser, logger):
- """Check if the page is available and valid"""
- expected_keywords = ["Page Not Found", "Content Unavailable"]
- page_title = get_page_title(browser, logger)
-
- if any(keyword in page_title for keyword in expected_keywords):
- reload_webpage(browser)
- page_title = get_page_title(browser, logger)
-
- if any(keyword in page_title for keyword in expected_keywords):
- if "Page Not Found" in page_title:
- logger.warning(
- "The page isn't available!\t~the link may be broken, "
- "or the page may have been removed..."
- )
-
- elif "Content Unavailable" in page_title:
- logger.warning(
- "The page isn't available!\t~the user may have blocked you..."
- )
-
- return False
-
- return True
-
-
-@contextmanager
-def smart_run(session, threaded=False):
- try:
- session.login()
- yield
- except NoSuchElementException:
- # The problem is with a change in IG page layout
- log_file = "{}.html".format(time.strftime("%Y%m%d-%H%M%S"))
- file_path = os.path.join(gettempdir(), log_file)
-
- with open(file_path, "wb") as fp:
- fp.write(session.browser.page_source.encode("utf-8"))
-
- print(
- "{0}\nIf raising an issue, "
- "please also upload the file located at:\n{1}\n{0}".format(
- "*" * 70, file_path
- )
- )
- except KeyboardInterrupt:
- clean_exit("You have exited successfully.")
- finally:
- session.end(threaded_session=threaded)
-
-
-def reload_webpage(browser):
- """Reload the current webpage"""
- browser.execute_script("location.reload()")
- update_activity(browser, state=None)
- sleep(2)
-
- return True
-
-
-def get_page_title(browser, logger):
- """Get the title of the webpage"""
- # wait for the current page fully load to get the correct page's title
- explicit_wait(browser, "PFL", [], logger, 10)
-
- try:
- page_title = browser.title
-
- except WebDriverException:
- try:
- page_title = browser.execute_script("return document.title")
-
- except WebDriverException:
- try:
- page_title = browser.execute_script(
- "return document.getElementsByTagName('title')[0].text"
- )
-
- except WebDriverException:
- logger.info("Unable to find the title of the page :(")
- return None
-
- return page_title
-
-
-def click_visibly(browser, element):
- """Click as the element become visible"""
- if element.is_displayed():
- click_element(browser, element)
-
- else:
- browser.execute_script(
- "arguments[0].style.visibility = 'visible'; "
- "arguments[0].style.height = '10px'; "
- "arguments[0].style.width = '10px'; "
- "arguments[0].style.opacity = 1",
- element,
- )
- # update server calls
- update_activity(browser, state=None)
- sleep(randint(1, 5))
-
- click_element(browser, element)
-
- return True
-
-
-def get_action_delay(action):
- """Get the delay time to sleep after doing actions"""
- defaults = {"like": 2, "comment": 2, "follow": 3, "unfollow": 10, "story": 3}
- config = Settings.action_delays
-
- if (
- not config
- or action not in config
- or config["enabled"] is not True
- or config[action] is None
- or isinstance(config[action], (int, float)) is not True
- ):
- return defaults[action]
-
- else:
- custom_delay = config[action]
-
- # randomize the custom delay in user-defined range
- if (
- config["randomize"] is True
- and isinstance(config["random_range"], tuple)
- and len(config["random_range"]) == 2
- and all(
- (isinstance(i, (type(None), int, float)) for i in config["random_range"])
- )
- and any(not isinstance(i, type(None)) for i in config["random_range"])
- ):
- min_range = config["random_range"][0]
- max_range = config["random_range"][1]
-
- if not min_range or min_range < 0:
- min_range = 100
-
- if not max_range or max_range < 0:
- max_range = 100
-
- if min_range > max_range:
- a = min_range
- min_range = max_range
- max_range = a
-
- custom_delay = random.uniform(
- custom_delay * min_range / 100, custom_delay * max_range / 100
- )
-
- if custom_delay < defaults[action] and config["safety_match"] is not False:
- return defaults[action]
-
- return custom_delay
-
-
-def deform_emojis(text):
- """Convert unicode emojis into their text form"""
- new_text = ""
- emojiless_text = ""
- data = regex.findall(r"\X", text)
- emojis_in_text = []
-
- for word in data:
- if any(char in UNICODE_EMOJI for char in word):
- word_emoji = emoji.demojize(word).replace(":", "").replace("_", " ")
- if word_emoji not in emojis_in_text: # do not add an emoji if
- # already exists in text
- emojiless_text += " "
- new_text += " ({}) ".format(word_emoji)
- emojis_in_text.append(word_emoji)
- else:
- emojiless_text += " "
- new_text += " " # add a space [instead of an emoji to be
- # duplicated]
-
- else:
- new_text += word
- emojiless_text += word
-
- emojiless_text = remove_extra_spaces(emojiless_text)
- new_text = remove_extra_spaces(new_text)
-
- return new_text, emojiless_text
-
-
-def extract_text_from_element(elem):
- """
- As an element is valid and contains text, extract it and return
- Added filter to words that has spaces between them, they for sure are not valid username
- Error looks like: "User: 'NOVEMBER 5' |> followers: unknown |> following: unknown |> relationship ratio: unknown"
- ^^^^^^^^^^^^^^^^^
- """
-
- # if element is valid and contains text withou spaces
- if elem and hasattr(elem, "text") and elem.text and not re.search("\s", elem.text):
- return elem.text
-
- # if the element is not valid, return None
- return None
-
-
-def truncate_float(number, precision, round=False):
- """Truncate (shorten) a floating point value at given precision"""
-
- # don't allow a negative precision [by mistake?]
- precision = abs(precision)
-
- if round:
- # python 2.7+ supported method [recommended]
- short_float = round(number, precision)
-
- # python 2.6+ supported method
- """short_float = float("{0:.{1}f}".format(number, precision))
- """
-
- else:
- operate_on = 1 # returns the absolute number (e.g. 11.0 from 11.456)
-
- for _ in range(precision):
- operate_on *= 10
-
- short_float = float(int(number * operate_on)) / operate_on
-
- return short_float
-
-
-def get_time_until_next_month():
- """Get total seconds remaining until the next month"""
- now = datetime.datetime.now()
- next_month = now.month + 1 if now.month < 12 else 1
- year = now.year if now.month < 12 else now.year + 1
- date_of_next_month = datetime.datetime(year, next_month, 1)
-
- remaining_seconds = (date_of_next_month - now).total_seconds()
-
- return remaining_seconds
-
-
-def remove_extra_spaces(text):
- """Find and remove redundant spaces more than 1 in text"""
- new_text = re.sub(r" {2,}", " ", text)
-
- return new_text
-
-
-def has_any_letters(text):
- """Check if the text has any letters in it"""
- # result = re.search("[A-Za-z]", text) # works only with english letters
- result = any(
- c.isalpha() for c in text
- ) # works with any letters - english or non-english
-
- return result
-
-
-def save_account_progress(browser, username, logger):
- """
- Check account current progress and update database
-
- Args:
- :browser: web driver
- :username: Account to be updated
- :logger: library to log actions
- """
- logger.info("Saving account progress...")
- followers, following = get_relationship_counts(browser, username, logger)
-
- # save profile total posts
- posts = getUserData("graphql.user.edge_owner_to_timeline_media.count", browser)
-
- try:
- # DB instance
- db, id = get_database()
- conn = sqlite3.connect(db)
- with conn:
- conn.row_factory = sqlite3.Row
- cur = conn.cursor()
- sql = (
- "INSERT INTO accountsProgress (profile_id, followers, "
- "following, total_posts, created, modified) "
- "VALUES (?, ?, ?, ?, strftime('%Y-%m-%d %H:%M:%S'), "
- "strftime('%Y-%m-%d %H:%M:%S'))"
- )
- cur.execute(sql, (id, followers, following, posts))
- conn.commit()
- except Exception:
- logger.exception("message")
-
-
-def get_epoch_time_diff(time_stamp, logger):
- try:
- # time diff in seconds from input to now
- log_time = datetime.datetime.strptime(time_stamp, "%Y-%m-%d %H:%M")
-
- former_epoch = (log_time - datetime.datetime(1970, 1, 1)).total_seconds()
- cur_epoch = (
- datetime.datetime.now() - datetime.datetime(1970, 1, 1)
- ).total_seconds()
-
- return cur_epoch - former_epoch
- except ValueError:
- logger.error("Error occurred while reading timestamp value from database")
- return None
-
-
-def is_follow_me(browser, person=None):
- # navigate to profile page if not already in it
- if person:
- user_link = "https://www.instagram.com/{}/".format(person)
- web_address_navigator(browser, user_link)
-
- return getUserData("graphql.user.follows_viewer", browser)
-
-
-def get_users_from_dialog(old_data, dialog, logger):
- """
- Prepared to work specially with the dynamic data load in the 'Likes'
- dialog box
- """
-
- try:
- user_blocks = dialog.find_elements(By.TAG_NAME, "a")
- loaded_users = [
- extract_text_from_element(u)
- for u in user_blocks
- if extract_text_from_element(u)
- ]
- new_data = old_data + loaded_users
- new_data = remove_duplicates(new_data, True, None)
-
- return new_data
-
- except (NoSuchElementException, StaleElementReferenceException) as exc:
- # Catch stale elements if any
- logger.error(
- "Error occurred while retrieving data.\n\t{}".format(
- str(exc).encode("utf-8")
- )
- )
-
- return old_data
-
-
-def progress_tracker(current_value, highest_value, initial_time, logger):
- """Provide a progress tracker to keep value updated until finishes"""
- if current_value is None or highest_value is None or highest_value == 0:
- return
-
- try:
- real_time = time.time()
- progress_percent = int((current_value / highest_value) * 100)
- show_logs = Settings.show_logs
-
- elapsed_time = real_time - initial_time
- elapsed_formatted = truncate_float(elapsed_time, 2)
- elapsed = (
- "{} seconds".format(elapsed_formatted)
- if elapsed_formatted < 60
- else "{} minutes".format(truncate_float(elapsed_formatted / 60, 2))
- )
-
- eta_time = abs(
- (elapsed_time * 100) / (progress_percent if progress_percent != 0 else 1)
- - elapsed_time
- )
- eta_formatted = truncate_float(eta_time, 2)
- eta = (
- "{} seconds".format(eta_formatted)
- if eta_formatted < 60
- else "{} minutes".format(truncate_float(eta_formatted / 60, 2))
- )
-
- tracker_line = "-----------------------------------"
- filled_index = int(progress_percent / 2.77)
- progress_container = (
- "[" + tracker_line[:filled_index] + "+" + tracker_line[filled_index:] + "]"
- )
- progress_container = (
- progress_container[: filled_index + 1].replace("-", "=")
- + progress_container[filled_index + 1 :]
- )
-
- total_message = (
- "\r {0}/{1} {2} {3}% "
- "|> Elapsed: {4:20} "
- "|> ETA: {5:20} ".format(
- current_value,
- highest_value,
- progress_container,
- progress_percent,
- elapsed,
- eta,
- )
- )
-
- if show_logs is True:
- sys.stdout.write(total_message)
- sys.stdout.flush()
-
- except Exception as exc:
- if not logger:
- logger = Settings.logger
-
- logger.info(
- "Error occurred with Progress Tracker:\n\t{}".format(
- str(exc).encode("utf-8")
- )
- )
-
-
-def close_dialog_box(browser):
- """Click on the close button spec. in the 'Likes' dialog box"""
-
- try:
- close = browser.find_element(
- By.XPATH, read_xpath("class_selectors", "likes_dialog_close_xpath")
- )
-
- click_element(browser, close)
-
- except NoSuchElementException:
- pass
-
-
-def parse_cli_args():
- """Parse arguments passed by command line interface"""
-
- AP_kwargs = dict(
- prog="InstaPy",
- description="Parse InstaPy constructor's arguments",
- epilog="And that's how you'd pass arguments by CLI..",
- conflict_handler="resolve",
- )
- if python_version() < "3.5":
- parser = CustomizedArgumentParser(**AP_kwargs)
- else:
- AP_kwargs.update(allow_abbrev=False)
- parser = ArgumentParser(**AP_kwargs)
-
- """ Flags that REQUIRE a value once added
- ```python quickstart.py --username abc```
- """
- parser.add_argument("-u", "--username", help="Username", type=str, metavar="abc")
- parser.add_argument("-p", "--password", help="Password", type=str, metavar="123")
- parser.add_argument(
- "-pd", "--page-delay", help="Implicit wait", type=int, metavar=25
- )
- parser.add_argument(
- "-pa", "--proxy-address", help="Proxy address", type=str, metavar="192.168.1.1"
- )
- parser.add_argument(
- "-pp", "--proxy-port", help="Proxy port", type=int, metavar=8080
- )
-
- """ Auto-booleans: adding these flags ENABLE themselves automatically
- ```python quickstart.py --use-firefox```
- """
- parser.add_argument(
- "-uf", "--use-firefox", help="Use Firefox", action="store_true", default=None
- )
- parser.add_argument(
- "-hb",
- "--headless-browser",
- help="Headless browser",
- action="store_true",
- default=None,
- )
- parser.add_argument(
- "-dil",
- "--disable-image-load",
- help="Disable image load",
- action="store_true",
- default=None,
- )
- parser.add_argument(
- "-bsa",
- "--bypass-suspicious-attempt",
- help="Bypass suspicious attempt",
- action="store_true",
- default=None,
- )
- parser.add_argument(
- "-bwm",
- "--bypass-with-mobile",
- help="Bypass with mobile phone",
- action="store_true",
- default=None,
- )
- parser.add_argument(
- "-sdb",
- "--split-db",
- help="Split sqlite-db as instapy_{username}.db",
- action="store_true",
- default=None,
- )
- parser.add_argument(
- "-wcb",
- "--want_check_browser",
- help="Check connectivity before connecting to Instagram",
- default=None,
- )
-
- """ Style below can convert strings into booleans:
- ```parser.add_argument("--is-debug",
- default=False,
- type=lambda x: (str(x).capitalize() == "True"))```
-
- So that, you can pass bool values explicitly from CLI,
- ```python quickstart.py --is-debug True```
-
- NOTE: This style is the easiest of it and currently not being used.
- """
-
- args, _ = parser.parse_known_args()
- # Once added custom arguments if you use a reserved name of core flags
- # and don't parse it, e.g.,
- # `-ufa` will misbehave cos it has `-uf` reserved flag in it.
- # But if you parse it, it's okay.
-
- return args
-
-
-def get_cord_location(browser, location):
- base_url = "https://www.instagram.com/explore/locations/"
- query_url = "{}{}{}".format(base_url, location, "?__a=1")
- browser.get(query_url)
- json_text = browser.find_element(
- By.XPATH, read_xpath(get_cord_location.__name__, "json_text")
- ).text
- data = json.loads(json_text)
-
- lat = data["graphql"]["location"]["lat"]
- lon = data["graphql"]["location"]["lng"]
-
- return lat, lon
-
-
-def get_bounding_box(
- latitude_in_degrees, longitude_in_degrees, half_side_in_miles, logger
-):
- if half_side_in_miles == 0:
- logger.error("Check your Radius its lower then 0")
- return {}
- if latitude_in_degrees < -90.0 or latitude_in_degrees > 90.0:
- logger.error("Check your latitude should be between -90/90")
- return {}
- if longitude_in_degrees < -180.0 or longitude_in_degrees > 180.0:
- logger.error("Check your longtitude should be between -180/180")
- return {}
- half_side_in_km = half_side_in_miles * 1.609344
- lat = radians(latitude_in_degrees)
- lon = radians(longitude_in_degrees)
-
- radius = 6371
- # Radius of the parallel at given latitude
- parallel_radius = radius * cos(lat)
-
- lat_min = lat - half_side_in_km / radius
- lat_max = lat + half_side_in_km / radius
- lon_min = lon - half_side_in_km / parallel_radius
- lon_max = lon + half_side_in_km / parallel_radius
-
- lat_min = rad2deg(lat_min)
- lon_min = rad2deg(lon_min)
- lat_max = rad2deg(lat_max)
- lon_max = rad2deg(lon_max)
-
- bbox = {
- "lat_min": lat_min,
- "lat_max": lat_max,
- "lon_min": lon_min,
- "lon_max": lon_max,
- }
-
- return bbox
-
-
-def take_rotative_screenshot(browser, logfolder):
- """
- Make a sequence of screenshots, based on hour:min:secs
- """
- global next_screenshot
-
- if next_screenshot == 1:
- browser.save_screenshot("{}screenshot_1.png".format(logfolder))
- elif next_screenshot == 2:
- browser.save_screenshot("{}screenshot_2.png".format(logfolder))
- else:
- browser.save_screenshot("{}screenshot_3.png".format(logfolder))
- next_screenshot = 0
- # sum +1 next
-
- # update next
- next_screenshot += 1
-
-
-def get_query_hash(browser, logger, edge_followed_by):
- """
- Load Instagram JS file and find query hash code
-
- :param browser: webdriver instance
- :param logger: the logger instance
- :param edge_followed_by: query hash flag, edge_followed_by or edge_follow
- :return: query hash
- """
- link = "https://www.instagram.com/static/bundles/es6/Consumer.js/1f67555edbd3.js"
- web_address_navigator(browser, link)
- page_source = browser.page_source
- # There are two query hash, one for followers and following, ie:
- # t="c76146de99bb02f6415203be841dd25a",n="d04b0a864b4b54837c0d870b0e77e076"
- if edge_followed_by:
- pattern_hash = '[a-z0-9]{32}(?=",n=")' # Used to query: edge_followed_by
- else:
- pattern_hash = '[a-z0-9]{32}(?=",u=1)' # Used to query: edge_follow
- # locate pattern value from JS file
- # sequence of 32 words and/or numbers just before ,n=" value
- hash = re.findall(pattern_hash, page_source)
- if hash:
- return hash[0]
- else:
- logger.warning("Query Hash not found")
-
-
-def file_handling(file):
- """Extracts text file's elements"""
- elements = []
- try:
- with open(file, "r") as f:
- # extract file's lines in list
- for line in f.readlines():
- if line != "\n":
- # remove leading whitespaces, newline and tab characters
- element = line.lstrip().strip("\n")
- elements.append(element)
- except FileNotFoundError:
- return ["FileNotFoundError"]
-
- return elements
-
-
-class CustomizedArgumentParser(ArgumentParser):
- """
- Subclass ArgumentParser in order to turn off
- the abbreviation matching on older pythons.
-
- `allow_abbrev` parameter was added by Python 3.5 to do it.
- Thanks to @paul.j3 - https://bugs.python.org/msg204678 for this solution.
- """
-
- def _get_option_tuples(self, option_string):
- """
- Default of this method searches through all possible prefixes
- of the option string and all actions in the parser for possible
- interpretations.
-
- To view the original source of this method, running,
- ```
- import inspect; import argparse; inspect.getsourcefile(argparse)
- ```
- will give the location of the 'argparse.py' file that have this method.
- """
- return []
-
-
-def get_additional_data(browser):
- """
- Get additional data object from page source
- Idea and Code by alokkumarsbg
-
- :param browser: The selenium webdriver instance
- :return additional_data: Json data from window.__additionalData extracted from page source
- """
- additional_data = None
- soup = BeautifulSoup(browser.page_source, "html.parser")
- for text in soup(text=re.compile(r"window.__additionalDataLoaded")):
- if re.search("^window.__additionalDataLoaded", text):
- additional_data = json.loads(re.search("{.*}", text).group())
- break
-
- return additional_data
-
-
-def get_shared_data(browser):
- """
- Get shared data object from page source
- Code by schealex
-
- :param browser: The selenium webdriver instance
- :return shared_data: Json data from window._sharedData extracted from page source
- """
- shared_data = None
- soup = BeautifulSoup(browser.page_source, "html.parser")
- for text in soup(text=re.compile(r"window._sharedData")):
- if re.search("^window._sharedData", text):
- shared_data = json.loads(re.search("{.*}", text).group())
- break
-
- return shared_data
diff --git a/instapy/xpath.py b/instapy/xpath.py
deleted file mode 100644
index f94075150..000000000
--- a/instapy/xpath.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from .xpath_compile import xpath
-
-
-def read_xpath(function_name, xpath_name):
- return xpath[function_name][xpath_name]
diff --git a/instapy/xpath_compile.py b/instapy/xpath_compile.py
deleted file mode 100644
index e36da5949..000000000
--- a/instapy/xpath_compile.py
+++ /dev/null
@@ -1,212 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-###############################################################################
-# Note:
-# Update the xpaths with a generic form, try to avoid using xpaths like the
-# Browser is displaying; i.e.: /html/body/div[2]/div/div[2]/div[1]/div[2].
-# Usually the Browser use the most un-portable form and then it could be broken
-# after IG updates the DOM.
-#
-# Absolute: paths are the direct way to locate an element, "/html/body/div[2]"
-# Relative: starts with a double slash “//” that means it can start to search
-# anywhere in the DOM structure, "//div[@class=’form-group’]"
-###############################################################################
-
-xpath = {}
-
-xpath["bypass_suspicious_login"] = {
- "bypass_with_sms_option": "//label[contains(text(),'Phone:')]",
- "bypass_with_email_option": "//label[contains(text(),'Email:')]",
- "send_security_code_button": "//button[text()='Send Security Code']",
- "security_code_field": "//input[@id='security_code']",
- "submit_security_code_button": "//button[text()='Submit']",
- "wrong_login": "//p[text()='Please check the code we sent you and try again.']",
-}
-
-xpath["dismiss_this_was_me"] = {
- "this_was_me_button": "//button[@name='choice'][text()='This Was Me']"
-}
-
-xpath["class_selectors"] = {
- "likes_dialog_body_xpath": "//main",
- "likes_dialog_close_xpath": "//*[*[local-name()='svg']/@aria-label='Close']",
-}
-
-xpath["confirm_unfollow"] = {"button_xp": "//button[text()='Unfollow']"}
-
-xpath["dialog_username_extractor"] = {"person": "../../*"}
-
-xpath["dismiss_get_app_offer"] = {
- "offer_elem": "//*[contains(text(), 'Get App')]",
- "dismiss_elem": "//*[contains(text(), 'Not Now')]",
-}
-
-xpath["dismiss_notification_offer"] = {
- "offer_elem_loc": "//div/h2[text()='Turn on Notifications']",
- "dismiss_elem_loc": "//button[text()='Not Now']",
-}
-
-xpath["dismiss_save_information"] = {
- "offer_elem_loc": "//*[contains(text(), 'Save Info')]",
- "dismiss_elem_loc": "//*[contains(text(), 'Not Now')]",
-}
-
-xpath["extract_information"] = {
- "close_overlay": "//div/div[@role='dialog']",
- "one_pic_elem": "//section/main/article/div[1]/div/div[10]/div[3]/a/div",
- "like_element": "//a[@role='button']/span[text()='Like']/..",
-}
-
-xpath["extract_post_info"] = {
- "comment_list": "//div/ul",
- "comments": "//li[@role='menuitem']",
- "load_more_comments_element": "//div/ul/li/div/button",
- "load_more_comments_element_alt": "//div/ul/li[1]/button",
-}
-
-xpath["find_user_id"] = {"meta_XP": "//meta[@property='instapp:owner_user_id']"}
-
-xpath["get_active_users"] = {
- "profile_posts": "(//div[contains(@class, '_9AhH0')])[{}]",
- "likers_count": "//section/div/div/a/span",
- "likes_button": "//div[@class='Nm9Fw']/a",
- "next_button": "//a[text()='Next']",
- "topCount_elements": "//span[contains(@class,'g47SY')]",
-}
-
-xpath["get_buttons_from_dialog"] = {
- "follow_button": "//button[text()='Follow']",
- "unfollow_button": "//button[text() = 'Following']",
-}
-
-xpath["get_comment_input"] = {
- "comment_input": "//form/textarea",
- "placeholder": '//textarea[@Placeholder = "Add a comment…"]',
-}
-
-xpath["get_comments_on_post"] = {
- "commenter_elem": "//*[contains(@class,'FPmhX')]",
- "comments_block": "//*[contains(@class,'EtaWk')]",
- "like_button_full_XPath": "//*[*[local-name()='svg']/@aria-label='Like']",
- "unlike_button_full_XPath": "//*[*[local-name()='svg']/@aria-label='Unlike']",
-}
-
-xpath["get_cord_location"] = {"json_text": "//body"}
-
-xpath["get_following_status"] = {
- "follow_button_XP": "//button[text()='Following' or \
- text()='Requested' or \
- text()='Follow' or \
- text()='Follow Back' or \
- text()='Unblock' and not(ancestor::*/@role = 'presentation')]",
- "follow_span_XP_following": "//button/div/span[contains(@aria-label, 'Following')]",
-}
-
-xpath["get_follow_requests"] = {
- "list_of_users": "//section/div",
- "view_more_button": "//button[text()='View More']",
-}
-
-xpath["get_given_user_followers"] = {"followers_link": "//ul/li[2]/a/span"}
-
-xpath["get_given_user_following"] = {
- "all_following": "//a[contains(@href,'following')]/span",
- "topCount_elements": "//span[contains(@class,'g47SY')]",
- "following_link": '//a[@href="/{}/following/"]',
-}
-
-xpath["get_photo_urls_from_profile"] = {"photos_a_elems": "//div/a"}
-
-xpath["get_links_for_location"] = {
- "top_elements": "//main/article/div[1]",
- "main_elem": "//main/article/div[2]",
-}
-
-xpath["get_links_from_feed"] = {"get_links": "//*[contains(@class,'c-Yi7')]"}
-
-xpath["get_links_for_tag"] = {
- "top_elements": "//main/article/div[1]",
- "main_elem": "//main/article/div[2]",
- "possible_post": "//span[contains(@class, 'g47SY')]",
-}
-
-xpath["get_number_of_posts"] = {
- "num_of_posts_txt": "//section/main/div/ul/li[1]/span/span",
- "num_of_posts_txt_no_such_element": "//section/div[3]/div/header/section/ul/li[1]/span/span",
-}
-
-xpath["get_relationship_counts"] = {
- "following_count": "//a[contains(@href,'following') and not(contains(@href,'mutual'))]/span",
- "followers_count": "//a[contains(@href,'followers') and not(contains(@href,'mutual'))]/span",
- "topCount_elements": "//span[contains(@class,'g47SY')]",
-}
-
-xpath["get_source_link"] = {
- "image": '//img[@class="FFVAD"]',
- "image_alt": '//img[@class="_8jZFn"]',
- "video": '//video[@class="tWeCl"]',
-}
-
-xpath["get_users_through_dialog"] = {"find_dialog_box": "//body/div[4]/div/div[2]"}
-
-xpath["is_private_profile"] = {"is_private": '//h2[@class="_kcrwx"]'}
-
-xpath["like_comment"] = {
- "comments_block": "//*[contains(@class,'EtaWk')]",
- "span_like_elements": "//span[@aria-label='Like']",
- "comment_like_button": "..",
-}
-
-xpath["like_image"] = {
- "like": "//*[contains(@class, 'fr66n')]/button/div/*[*[local-name()='svg']/@aria-label='Like']/*",
- "unlike": "//*[contains(@class, 'fr66n')]/button/div/*[*[local-name()='svg']/@aria-label='Unlike']/*",
- "play": "//*/span[contains(@aria-label, 'Play')]",
-}
-
-xpath["like_from_image"] = {
- "main_article": "//main//article//div//div[1]//div[1]//a[1]"
-}
-
-xpath["login_user"] = {
- "input_password": "//input[@name='password']",
- "input_username_XP": "//input[@name='username']",
- "login_elem": "//button[text()='Log In']",
- "login_elem_no_such_exception": "//a[text()='Log in']",
- "login_elem_no_such_exception_2": "//div[text()='Log In']",
- "nav": "//nav",
- "website_status": "//span[@id='status']",
- "response_time": "//span[@id='response']",
- "response_code": "//span[@id='code']",
- "account_disabled": "//p[contains(text(),'Your account has been disabled')]",
- "add_phone_number": "//h2[text()='Add Your Phone Number']",
- "suspicious_login_attempt": "//p[text()='Suspicious Login Attempt']",
- "error_alert": "//p[@id='slfErrorAlert']",
- "verification_code": "//input[@name='verificationCode']",
- "confirm": "//button[text()='Confirm']",
-}
-
-xpath["open_comment_section"] = {
- "comment_elem": "//button/div[*[local-name()='svg']/@aria-label='Comment']"
-}
-
-xpath["unfollow"] = {
- "following_link": "//ul/li[3]/a/span",
- "find_dialog_box": "//section/main/div[2]",
-}
-
-xpath["watch_story_for_tag"] = {"explore_stories": "//section/main/header/div[1]/div"}
-
-xpath["watch_story_for_user"] = {"explore_stories": "//section/main/div/header/div/div"}
-
-xpath["watch_story"] = {
- "next_first": "//*[contains(@class,'Cd8X1')]",
- "next": "//*[contains(@class,'FhutL')]",
-}
-
-xpath["likers_from_photo"] = {
- "liked_counter_button": "//a[contains(@href,'liked_by')]/span",
- "second_counter_button": "//a[contains(@href,'liked_by')]",
-}
-
-xpath["accept_igcookie_dialogue"] = {"accept_button": "//button[text()='Accept']"}
diff --git a/proxy_extension.py b/proxy_extension.py
deleted file mode 100644
index d569065f2..000000000
--- a/proxy_extension.py
+++ /dev/null
@@ -1,78 +0,0 @@
-import zipfile
-import os
-
-
-def create_proxy_extension(proxy):
- """takes proxy looks like login:password@ip:port"""
-
- ip = proxy.split("@")[1].split(":")[0]
- port = int(proxy.split(":")[-1])
- login = proxy.split(":")[0]
- password = proxy.split("@")[0].split(":")[1]
-
- manifest_json = """
- {
- "version": "1.0.0",
- "manifest_version": 2,
- "name": "Chrome Proxy",
- "permissions": [
- "proxy",
- "tabs",
- "unlimitedStorage",
- "storage",
- "",
- "webRequest",
- "webRequestBlocking"
- ],
- "background": {
- "scripts": ["background.js"]
- },
- "minimum_chrome_version":"22.0.0"
- }
- """
-
- background_js = """
- var config = {
- mode: "fixed_servers",
- rules: {
- singleProxy: {
- scheme: "http",
- host: "%s",
- port: parseInt(%s)
- },
- bypassList: ["localhost"]
- }
- };
- chrome.proxy.settings.set({value: config, scope: "regular"},
- function() {});
- function callbackFn(details) {
- return {
- authCredentials: {
- username: "%s",
- password: "%s"
- }
- };
- }
- chrome.webRequest.onAuthRequired.addListener(
- callbackFn,
- {urls: [""]},
- ['blocking']
- );
- """ % (
- ip,
- port,
- login,
- password,
- )
-
- dir_path = "assets/chrome_extensions"
-
- if not os.path.exists(dir_path):
- os.makedirs(dir_path)
-
- pluginfile = "%s/proxy_auth_%s:%s.zip" % (dir_path, ip, port)
- with zipfile.ZipFile(pluginfile, "w") as zp:
- zp.writestr("manifest.json", manifest_json)
- zp.writestr("background.js", background_js)
-
- return pluginfile
diff --git a/quickstart.py b/quickstart.py
deleted file mode 100644
index ab0b26063..000000000
--- a/quickstart.py
+++ /dev/null
@@ -1,20 +0,0 @@
-""" Quickstart script for InstaPy usage """
-
-# imports
-from instapy import InstaPy
-from instapy import smart_run
-from instapy import set_workspace
-
-
-# set workspace folder at desired location (default is at your home folder)
-set_workspace(path=None)
-
-# get an InstaPy session!
-session = InstaPy()
-
-with smart_run(session):
- # general settings
- session.set_dont_include(["friend1", "friend2", "friend3"])
-
- # activity
- session.like_by_tags(["natgeo"], amount=10)
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index 0d4016999..000000000
--- a/requirements.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-api-display-purposes>=0.0.3; python_version > '3.5'
-certifi>=2018.10.15
-chardet>=3.0.4,<4
-clarifai>=2.4.1
-configparser>=3.5.0,<4
-EasyProcess>=0.2.3
-emoji>=0.5.1
-future>=0.17.1
-grpcio>=1.16.1
-idna>=2.7,<3
-jsonschema>=2.6.0,<3
-MeaningCloud-python>=1.1.1
-plyer>=1.3.1
-protobuf>=3.6.1,<4
-python-telegram-bot>=12.0.0; python_version > '3.6'
-PyVirtualDisplay>=0.2.1; sys_platform != 'win32'
-PyYAML>=3.13
-regex>=2018.11.22
-requests>=2.20.1
-selenium>=3.141.0
-setuptools_rust>=0.11.6
-six>=1.11.0
-urllib3>=1.24.1
-webdriverdownloader>=1.1.0.3
\ No newline at end of file
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 7980d1397..000000000
--- a/setup.cfg
+++ /dev/null
@@ -1,13 +0,0 @@
-[tool:pytest]
-testpaths = tests
-
-[flake8]
-max-line-length = 79
-exclude = .tox
-
-[metadata]
-license-file = LICENSE
-
-[bdist_wheel]
-# use py2.py3 tag for pure-python dist
-universal = 1
diff --git a/setup.py b/setup.py
deleted file mode 100644
index b9571c074..000000000
--- a/setup.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# This Python file uses the following encoding: utf-8
-
-from setuptools import setup
-from os import path
-
-# io.open is needed for projects that support Python 2.7
-# It ensures open() defaults to text mode with universal newlines,
-# and accepts an argument to specify the text encoding
-# Python 3 only projects can skip this import and use built-in open()
-from io import open as io_open
-import re
-
-
-summary = "Tool for automated Instagram interactions"
-project_homepage = "https://github.com/InstaPy/InstaPy"
-here = path.abspath(path.dirname(__file__))
-
-
-def readall(*args):
- with io_open(path.join(here, *args), encoding="utf-8") as fp:
- return fp.read()
-
-
-with open("requirements.txt") as f:
- dependencies = f.read().splitlines()
-
-documentation = readall("README.md")
-metadata = dict(
- re.findall(r"""__([a-z]+)__ = "([^"]+)""", readall("instapy", "__init__.py"))
-)
-
-setup(
- name="instapy",
- version=metadata["version"],
- description=summary,
- long_description=documentation,
- long_description_content_type="text/markdown",
- author="Tim Großmann",
- author_email="contact.timgrossmann@gmail.com",
- maintainer="InstaPy Community at Github",
- license="GPLv3",
- url=project_homepage,
- download_url=(project_homepage + "/archive/master.zip"),
- project_urls={
- "How Tos": (project_homepage + "/tree/master/docs"),
- "Examples": (project_homepage + "/tree/master/quickstart_templates"),
- "Bug Reports": (project_homepage + "/issues"),
- "Funding": "https://www.paypal.me/supportInstaPy",
- "Say Thanks!": "http://saythanks.io/to/uluQulu",
- "Source": (project_homepage + "/tree/master/instapy"),
- },
- packages=["instapy"],
- # include_package_data=True, # <- packs every data file in the package
- package_data={ # we need only the files below:
- "instapy": [
- "icons/Windows/*.ico",
- "icons/Linux/*.png",
- "icons/Mac/*.icns",
- "firefox_extension/*",
- "plugins/*",
- ]
- },
- keywords=(
- "instapy python instagram automation \
- marketing promotion bot selenium"
- ),
- classifiers=[
- "Development Status :: 4 - Beta",
- "Environment :: Console",
- "Environment :: Win32 (MS Windows)",
- "Environment :: MacOS X",
- "Environment :: Web Environment",
- "Intended Audience :: End Users/Desktop",
- "Intended Audience :: Developers",
- "Operating System :: Microsoft :: Windows",
- "Operating System :: POSIX :: Linux",
- "Operating System :: MacOS :: MacOS X",
- "Operating System :: Unix",
- "Programming Language :: Python",
- "Programming Language :: JavaScript",
- "Programming Language :: SQL",
- "Topic :: Utilities",
- "Topic :: Software Development :: Build Tools",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.5",
- "Programming Language :: Python :: 3.6",
- "Programming Language :: Python :: 3.7",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Natural Language :: English",
- ],
- install_requires=dependencies,
- extras_require={"test": ["tox", "virtualenv", "tox-venv"]},
- python_requires=">=3.5",
- platforms=["win32", "linux", "linux2", "darwin"],
- zip_safe=False,
- entry_points={"console_scripts": []},
-)
diff --git a/tests/comment_util_tests.py b/tests/comment_util_tests.py
deleted file mode 100644
index 35c485f3c..000000000
--- a/tests/comment_util_tests.py
+++ /dev/null
@@ -1,118 +0,0 @@
-import unittest
-import logging
-from instapy.comment_util import *
-
-# Note: This file is using a different name scheme than existing tests
-# so that unittest can be run with -p *_tests.py to discover all compatible tests in the tests directory
-
-
-class BrowserMock:
- def __init__(self, caption=None, first_comment=None, comment_count=0):
- self.caption = caption
- self.first_comment = first_comment
- self.comment_count = comment_count
-
- def execute_script(self, script, *kwargs):
- if "edge_media_preview_comment.count" in script:
- return self.comment_count
- if ".graphql.shortcode_media.comments_disabled" in script:
- return False
- elif "edge_media_to_caption.edges[0]['node']['text']" in script:
- return self.caption
- elif "edge_media_to_parent_comment.edges[0]['node']['text']" in script:
- return self.first_comment
- else:
- raise ValueError("Unexpected script")
-
-
-class CommentsUtilTests(unittest.TestCase):
- def setUp(self):
- pass
-
- def test_verify_mandatory_words(self):
- browser = BrowserMock(caption="a B c D e F g", comment_count=5)
- mandatory_comments_words = []
- comments = [
- {"mandatory_words": ["x", "y", "z"], "comments": ["1"]},
- {"mandatory_words": [["x", "y", "z"], "v"], "comments": ["2"]},
- {"mandatory_words": [["a", "b", "d"], "v"], "comments": ["3"]},
- {"mandatory_words": [["a", "z", ["d", "x"]], "v"], "comments": ["4"]},
- {"mandatory_words": [["a", "f", "e"]], "comments": ["5"]},
- {"mandatory_words": ["a", "B", "z"], "comments": ["6"]},
- {"comments": ["9"]},
- ]
-
- (
- commenting_approved,
- selected_comments,
- disapproval_reason,
- ) = verify_mandatory_words(mandatory_comments_words, comments, browser, logging)
- self.assertTrue(commenting_approved)
- self.assertEqual(["3"], selected_comments)
-
- comments = [
- {"mandatory_words": ["x", "y", "z"], "comments": ["1"]},
- {"mandatory_words": [["x", "y", "z"], "v"], "comments": ["2"]},
- {"mandatory_words": [["a", "b", "z"], "v"], "comments": ["3"]},
- {"mandatory_words": [["a", "z", ["d", "x"]], "v"], "comments": ["4"]},
- {"mandatory_words": [["a", "f", "e"]], "comments": ["5"]},
- {"mandatory_words": ["a", "B", "z"], "comments": ["6"]},
- {"comments": ["9"]},
- ]
- (
- commenting_approved,
- selected_comments,
- disapproval_reason,
- ) = verify_mandatory_words(mandatory_comments_words, comments, browser, logging)
- self.assertTrue(commenting_approved)
- self.assertEqual(["5"], selected_comments)
-
- comments = [
- {"mandatory_words": ["x", "y", "z"], "comments": ["1"]},
- {"mandatory_words": [["x", "y", "z"], "v"], "comments": ["2"]},
- {"mandatory_words": [["a", "b", "z"], "v"], "comments": ["3"]},
- {"mandatory_words": [["a", "z", ["d", "x"]], "v"], "comments": ["4"]},
- {"mandatory_words": [["a", "f", "z"]], "comments": ["5"]},
- {"mandatory_words": ["a", "B", "z"], "comments": ["6"]},
- {"comments": ["9"]},
- ]
- (
- commenting_approved,
- selected_comments,
- disapproval_reason,
- ) = verify_mandatory_words(mandatory_comments_words, comments, browser, logging)
- self.assertTrue(commenting_approved)
- self.assertEqual(["6"], selected_comments)
-
- comments = [
- {"mandatory_words": ["x", "y", "z"], "comments": ["1"]},
- {"mandatory_words": [["x", "y", "z"], "v"], "comments": ["2"]},
- {"mandatory_words": [["a", "b", "z"], "v"], "comments": ["3"]},
- {"mandatory_words": [["a", "z", ["d", "x"]], "v"], "comments": ["4"]},
- {"mandatory_words": [["a", "f", "z"]], "comments": ["5"]},
- {"mandatory_words": ["x", "Y", "z"], "comments": ["6"]},
- {"comments": ["9"]},
- ]
- (
- commenting_approved,
- selected_comments,
- disapproval_reason,
- ) = verify_mandatory_words(mandatory_comments_words, comments, browser, logging)
- self.assertTrue(commenting_approved)
- self.assertEqual(["9"], selected_comments)
-
- comments = [
- {"mandatory_words": ["x", "y", "z"], "comments": ["1"]},
- {"mandatory_words": [["x", "y", "z"], "v"], "comments": ["2"]},
- {"mandatory_words": [["a", "b", "z"], "v"], "comments": ["3"]},
- {"mandatory_words": [["a", "z", ["d", "x"]], "v"], "comments": ["4"]},
- {"mandatory_words": [["a", "f", "z"]], "comments": ["5"]},
- {"mandatory_words": ["x", "Y", "z"], "comments": ["6"]},
- ]
- (
- commenting_approved,
- selected_comments,
- disapproval_reason,
- ) = verify_mandatory_words(mandatory_comments_words, comments, browser, logging)
- self.assertFalse(commenting_approved)
- self.assertEqual([], selected_comments)
diff --git a/tests/resources/invalid_target_list.txt b/tests/resources/invalid_target_list.txt
deleted file mode 100644
index 40cdc6c36..000000000
--- a/tests/resources/invalid_target_list.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a comment...
-
-photography
-
- portrait
\ No newline at end of file
diff --git a/tests/resources/valid_target_list.txt b/tests/resources/valid_target_list.txt
deleted file mode 100644
index 780802f36..000000000
--- a/tests/resources/valid_target_list.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This is a comment...
-photography
-portrait
\ No newline at end of file
diff --git a/tests/test_action_delays.py b/tests/test_action_delays.py
deleted file mode 100644
index 16997c58b..000000000
--- a/tests/test_action_delays.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from instapy import util
-
-
-def test_default_values_returned():
- assert util.get_action_delay("like") == 2
- assert util.get_action_delay("comment") == 2
- assert util.get_action_delay("follow") == 3
- assert util.get_action_delay("unfollow") == 10
diff --git a/tests/test_file_handling.py b/tests/test_file_handling.py
deleted file mode 100644
index 81349fe82..000000000
--- a/tests/test_file_handling.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import unittest
-
-from instapy import util
-
-
-class TestFileHandling(unittest.TestCase):
- """Unit tests for file_handling function"""
-
- # list of expected entries
- expected_entries = ["This is a comment...", "photography", "portrait"]
-
- def test_valid_entries(self):
- """Check file_handling with valid entries"""
- actual_entries = util.file_handling("tests/resources/valid_target_list.txt")
- self.assertListEqual(actual_entries, TestFileHandling.expected_entries)
-
- def test_invalid_entries(self):
- """Check file_handling with invalid entries"""
- actual_entries = util.file_handling("tests/resources/invalid_target_list.txt")
- self.assertListEqual(actual_entries, TestFileHandling.expected_entries)
-
- def test_invalid_filepath(self):
- """Check whether it raises an exception when the filepath is invalid"""
- actual_entries = util.file_handling("invalid_filepath")
- self.assertListEqual(actual_entries, ["FileNotFoundError"])
diff --git a/tests/test_settings.py b/tests/test_settings.py
deleted file mode 100644
index f12b517e0..000000000
--- a/tests/test_settings.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from instapy import Settings
-
-
-def test_settings():
- assert Settings.log_location == None
diff --git a/tests/util_tests.py b/tests/util_tests.py
deleted file mode 100644
index 69954fe0d..000000000
--- a/tests/util_tests.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import unittest
-from instapy.util import evaluate_mandatory_words
-
-# Note: This file is using a different name scheme than existing tests
-# so that unittest can be run with -p *_tests.py to discover all compatible tests in the tests directory
-
-
-class UtilsTests(unittest.TestCase):
- def setUp(self):
- pass
-
- def test_evaluate_mandatory_words(self):
- text = "a b c d e f g"
-
- self.assertTrue(evaluate_mandatory_words(text, ["a", "B", "c"]))
- self.assertTrue(evaluate_mandatory_words(text, ["a", "B", "z"]))
- self.assertTrue(evaluate_mandatory_words(text, ["x", "B", "z"]))
- self.assertFalse(evaluate_mandatory_words(text, ["x", "y", "z"]))
- self.assertTrue(evaluate_mandatory_words(text, [["a", "f", "e"]]))
- self.assertTrue(evaluate_mandatory_words(text, ["a", ["x", "y", "z"]]))
- self.assertTrue(evaluate_mandatory_words(text, [["x", "y", "z"], "a"]))
- self.assertFalse(evaluate_mandatory_words(text, [["x", "y", "z"], "v"]))
- self.assertTrue(evaluate_mandatory_words(text, [["a", "b", "d"], "v"]))
- self.assertTrue(evaluate_mandatory_words(text, [["a", "b", ["d", "x"]], "v"]))
- self.assertFalse(evaluate_mandatory_words(text, [["a", "z", ["d", "x"]], "v"]))
- self.assertTrue(evaluate_mandatory_words(text, [["a", "b", [["d", "e"], "x"]]]))
- self.assertFalse(
- evaluate_mandatory_words(text, [["a", "b", [["d", "z"], "x"]]])
- )