`,
-`
`,
+ `
`,
-`
`,
+ `
`,
-`
`,
+ `
`,
-`
`,
+ `
`,
-`
`,
+ `
`,
-`
`,
+ `
`,
-`
XSS`,
+ `XSS`,
-` `,
+ ` `,
-` `,
+ ` `,
-` `,
+ ` `,
-``,
+ ``,
-`XSS `,
+ `XSS `,
-`';alert(String.fromCharCode(88,83,83))//';alert(String.fromCharCode(88,83,83))//";
+ `';alert(String.fromCharCode(88,83,83))//';alert(String.fromCharCode(88,83,83))//";
alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//--
>">'>`,
-`'';!--"=&{()}`,
+ `'';!--"=&{()}`,
-``,
+ ``,
-`onnerr w/ clearly invalid img:
+ `onnerr w/ clearly invalid img:
good image:
good url, bad img:
(results will vary if using image proxy -- it rewrites 'src')`,
-`**test**!%3Cimg%20src=%22awsome.jpg%22%20onerror=%22alert(1)%22/%3E`,
-
-`test!%3Cimg%20src=%22awsome.jpg%22%20onerror=%22alert(1)%22/%3E`,
+ `**test**!%3Cimg%20src=%22awsome.jpg%22%20onerror=%22alert(1)%22/%3E`,
-' ',
+ `test!%3Cimg%20src=%22awsome.jpg%22%20onerror=%22alert(1)%22/%3E`,
-'Hax ',
+ ' ',
-'Link to a local page with bad rel attr ',
-'Link to domain (relative protocol) and bad target attr ',
+ 'Hax ',
-]
+ 'Link to a local page with bad rel attr ',
+ 'Link to domain (relative protocol) and bad target attr ',
+];
diff --git a/src/app/help/en/faq.md b/src/app/help/en/faq.md
index a0fde71a6ac296edd6a04222039b56054ed32ca7..72effdcec92289d98290c9c4a5ddf4058c9244e3 100644
--- a/src/app/help/en/faq.md
+++ b/src/app/help/en/faq.md
@@ -1,266 +1,259 @@
-# Steemit FAQ
-
-
-## Table of Contents
-
-
-### General
-- What is Steemit.com?
-- How does Steemit work?
-- How does Steemit differ from other social media websites?
-- Does it cost anything to post, comment, or vote?
-- Can I earn digital tokens on Steemit? How?
-- Where do the tokens come from?
-- Where does the value come from?
-- Why are people getting vastly different rewards?
-
-
-### Accounts
-- How do I create an account?
-- What information do I need to provide in order to create an account?
-- How long does the account approval process take?
-- Why do I need to provide my email and phone number?
-- Can I create a Steem account without an email and phone number?
-- What are other ways to create an account on the blockchain besides using Steemit.com?
-- It is not letting me create an account with my phone number. What should I do?
-- What happens if my email or phone number changes?
-- Am I allowed to create more than one account
-- Can I delete or deactivate my account?
-
-### Community
-- Is there an Etiquette Guide for Steemit?
-- Am I required to verify my identity?
-
-
-### Site Navigation
-- How do I upvote a post or comment?
-- What do the Home, New, Hot, Trending, and Promoted links show?
-- What information is available in my account menu?
-- How do I see my recent rewards?
-- What information is shown in my wallet?
-- How do I transfer my STEEM or Steem Dollars into savings?
-- How do I send money to another user?
-- Will I receive notifications when there is activity with my account?
-- What is shown in my profile?
-- How do I change my avatar image and other profile information?
-- What is the recommend size for the cover image?
-- How can I control whether I see "Not Safe For Work" (NSFW) content?
-- How do I search for content?
-- Can I see which users I have muted?
-- Can I see which users have muted me?
-- Can I see the list of users I am following, and who is following me?
-- What languages are supported?
-
-
-### Posting
-- What can users post to Steemit?
-- What are the different choices for post rewards (50%/50%, Power Up 100%, Decline Payout)?
-- How do I add images and photos to my posts?
-- How do I set the thumbnail image for my post?
-- What is the recommend aspect ratio for thumbnail images?
-- How do I add videos to my posts?
-- Is there a way I can make my images smaller?
-- What are tags?
-- What tags should I use?
-- How many tags can I use?
-- Why is the "Post" button grayed out?
-- How do I format text in Markdown?
-- How often can I post?
-- How long can my post be?
-- If posting in a language other than English, how will I get recognized?
-- Can I delete something I posted?
-- What does "Promoting" a post do?
-- How do I promote a post?
-
-
-### Comments
-- Can I earn digital tokens for commenting?
-- How often can I comment?
-
-
-### Economics
-- Where do the new STEEM tokens come from?
-- How many new tokens are generated by the blockchain?
-- How are the new tokens distributed?
-- What is the reward pool?
-- How is the reward pool split between authors and curators?
-- Will the reward pool pay out more or less depending on who votes?
-- Why do the earnings for my post go up or down?
-- When can I claim my rewards?
-- What is the difference between STEEM, STEEM Power, and Steem Dollars?
-- What is delegated STEEM Power?
-- What determines the price of STEEM?
-- How do I get more STEEM Power?
-- How long does it take STEEM or STEEM Power that I purchased to show up in my account?
-- What is powering up and down?
-- What do the dollar amounts for pending payouts represent?
-- Will 1 Steem Dollar always be worth $1.00 USD?
-- How do Steem Dollar to STEEM conversions work?
-- Is there a way for me to convert my Steem Dollars to STEEM without waiting 3.5 days?
-- What can I do with my STEEM tokens?
-- What can I do with my SBD tokens?
-- What is a MVEST?
-- Can I sell goods and services on Steemit?
-- How can I withdraw my STEEM or SBD coins?
-- Will I get a 1099 from Steemit?
-- How much are the transaction fees for sending tokens to other users?
-- Are there fees for Powering Up, Powering Down, trading on the internal market, or converting SBD to STEEM?
-- How long does it take to transfer STEEM or SBD tokens between users?
-
-
-### Voting and Curating
-- What is my voting power?
-- How many times can I vote without depleting my voting power?
-- Can I vote with less than 100% of my voting strength?
-- Where can I check my voting power?
-- What determines how much of the curation reward goes to the author versus curators?
-- Can I get curation rewards for upvoting comments?
-- Do I get curation rewards for downvoting posts or comments?
-- What are curation trails?
-- Why don't my upvotes have an effect on a post's rewards?
-- Is there a way to make my votes count for more?
-- What are the valid reasons for downvoting?
-- Does a downvote mean that I did something wrong?
-- Will a downvote hurt my reputation?
-- What is the difference between a downvote and a flag?
-
-
-### Plagiarism, Spam, and Abuse
-- What are Steemit’s policies on plagiarism and spam?
-- Is it okay to use random pictures from the internet?
-- What is Steemcleaners?
-- What is @cheetah?
-- Where do I report a post or comment that contains plagiarism, spam, or abuse?
-
-
-### Reputation
-- What is Reputation?
-- How is the Reputation score measured?
-- How do I improve my reputation score?
-- What causes my reputation score to go down?
-- Why does my reputation score matter?
-
-
-### Followers, Feeds, and Resteem
-- What is Resteeming?
-- Can I share on other social media?
-
-
-### Blockchain
-- What is a blockchain?
-- What is the Steem blockchain?
-- What is the difference between Steem and Steemit?
-- How is Steem different from Bitcoin?
-- What is the difference between Proof of Work, Proof of Stake, and Delegated Proof of Stake?
-- How often does the Steem blockchain produce a new block?
-- Is there a way to see the raw data that is stored in the blockchain?
-- Where can I find the information for the official launch of the blockchain?
-- Can I mine STEEM?
-
-
-### Steemit, Inc.
-- Who is the CEO of Steemit?
-- Can I invest in Steemit?
-- What does Steemit’s development roadmap look like?
-- Am I allowed to use the Steemit logo?
-- Can I purchase official Steemit merchandise?
-- Did Steemit "pre-mine" tokens?
-- What is the Steemit Privacy Policy?
-
-
-### Security
-- How can I keep my Steem account secure?
-- Why should I be careful with my master password?
-- Why is the master password a long string of gibberish?
-- What are my different keys for?
-- What do I do if I lost my password/keys?
-- Are my STEEM and Steem Dollar tokens insured in the event of a hack or if someone takes over my account?
-- What should I do if I discover that someone hacked my account?
-- How does the stolen account recovery process work?
-- How do I report a security vulnerability?
-
-
-### Developers
-- Are the Steem blockchain and Steemit.com code open-source?
-- Is there a Github page for Steemit.com?
-- Is there a Github page for the Steem blockchain?
-- What is available for developers interested in Steem and Steemit?
-- How do I use cli_wallet?
-
-
-### Witnesses
-- What are Steem witnesses?
-- How can I vote for witnesses?
-- How many witnesses can I vote for?
-
-
-### Miscellaneous
-- What third-party tools are there for Steemit?
-- Is there an official Steemit Facebook page?
-- Is there an official Steemit Twitter account?
-- What is the Steem Whitepaper and what is its purpose?
-- Where can I ask for help if my question was not answered here?
-
-
-### Disclaimer
-- Third Party References and User Links
+
+# Steemit FAQ
+
+## Table of Contents
+
+### General
+- What is Steemit.com?
+- How does Steemit work?
+- How does Steemit differ from other social media websites?
+- What do I need to do in order to secure my account?
+- Does it cost anything to post, comment, or vote?
+- Can I earn digital tokens on Steemit? How?
+- Where do the tokens come from?
+- Where does the value come from?
+- Why are people getting vastly different rewards?
+- What are Smart Media Tokens (SMTs)?
+
+### Accounts
+- How do I create an account?
+- What information do I need to provide in order to create an account?
+- How long does the account approval process take?
+- Can I speed up the account approval process?
+- Why do I need to provide my email and phone number?
+- Can I create a Steem account without an email and phone number?
+- What are other ways to create an account on the blockchain besides using Steemit.com?
+- It is not letting me create an account with my phone number. What should I do?
+- What happens if my email or phone number changes?
+- Am I allowed to create more than one account?
+- Can I change my username?
+- Can I delete or deactivate my account?
+
+###
+- Is there an Etiquette Guide for Steemit?
+- Am I required to verify my identity?
+
+### Site Navigation
+- How do I upvote a post or comment?
+- What do the Home, New, Hot, Trending, and Promoted links show?
+- What information is available in my account menu?
+- How do I see my recent rewards?
+- What information is shown in my wallet?
+- How do I transfer my STEEM or Steem Dollars into savings?
+- How do I send money to another user?
+- Will I receive notifications when there is activity with my account?
+- What is shown in my profile?
+- How do I change my avatar image and other profile information?
+- What is the recommend size for the cover image?
+- How can I control whether I see "Not Safe For Work" (NSFW) content?
+- How do I search for content?
+- Can I see which users I have muted?
+- Can I see which users have muted me?
+- Can I see the list of users I am following, and who is following me?
+- What languages are supported?
+
+### Posting
+- What can users post to Steemit?
+- What are the different choices for post rewards (50%/50%, Power Up 100%, Decline Payout)?
+- How do I add images and photos to my posts?
+- How do I set the thumbnail image for my post?
+- What is the recommend aspect ratio for thumbnail images?
+- How do I add videos to my posts?
+- Is there a way I can make my images smaller?
+- What are tags?
+- What tags should I use?
+- How many tags can I use?
+- Why is the "Post" button grayed out?
+- How do I format text in Markdown?
+- How often can I post?
+- How long can my post be?
+- If posting in a language other than English, how will I get recognized?
+- Can I delete something I posted?
+- What does "Promoting" a post do?
+- How do I promote a post?
+
+###
+- Can I earn digital tokens for commenting?
+- How often can I comment?
+
+### Economics
+- Where do the new STEEM tokens come from?
+- How many new tokens are generated by the blockchain?
+- How are the new tokens distributed?
+- Which exchanges are STEEM and SBD listed on?
+- What is the reward pool?
+- How is the reward pool split between authors and curators?
+- Will the reward pool pay out more or less depending on who votes?
+- Why do the earnings for my post go up or down?
+- When can I claim my rewards?
+- What is the difference between STEEM, STEEM Power, and Steem Dollars?
+- What is delegated STEEM Power?
+- What determines the price of STEEM?
+- How do I get more STEEM Power?
+- How long does it take STEEM or STEEM Power that I purchased to show up in my account?
+- What is powering up and down?
+- What do the dollar amounts for pending payouts represent?
+- Will 1 Steem Dollar always be worth $1.00 USD?
+- How do Steem Dollar to STEEM conversions work?
+- Is there a way for me to convert my Steem Dollars to STEEM without waiting 3.5 days?
+- What can I do with my STEEM tokens?
+- What can I do with my SBD tokens?
+- What is a MVEST?
+- Can I sell goods and services on Steemit?
+- How can I withdraw my STEEM or SBD coins?
+- Will I get a 1099 from Steemit?
+- How much are the transaction fees for sending tokens to other users?
+- Are there fees for Powering Up, Powering Down, trading on the internal market, or converting SBD to STEEM?
+- How long does it take to transfer STEEM or SBD tokens between users?
+
+### Voting and Curating
+- What is my voting power?
+- How many times can I vote without depleting my voting power?
+- Can I vote with less than 100% of my voting strength?
+- Where can I check my voting power?
+- What determines how much of the curation reward goes to the author versus curators?
+- Can I get curation rewards for upvoting comments?
+- Do I get curation rewards for downvoting posts or comments?
+- What are curation trails?
+- Why don't my upvotes have an effect on a post's rewards?
+- Is there a way to make my votes count for more?
+- What are the valid reasons for downvoting?
+- Does a downvote mean that I did something wrong?
+- Will a downvote hurt my reputation?
+- What is the difference between a downvote and a flag?
+
+### Plagiarism, Spam, and Abuse
+- What is considered spam or abuse?
+- What are Steemit’s policies on plagiarism?
+- Is it okay to use random pictures from the internet?
+- What is Steemcleaners?
+- What is @cheetah?
+- Where do I report a post or comment that contains plagiarism, spam, or abuse?
+
+### Reputation
+- What is Reputation?
+- How is the Reputation score measured?
+- How do I improve my reputation score?
+- What causes my reputation score to go down?
+- Why does my reputation score matter?
+
+### Followers, Feeds, and Resteem
+- What is Resteeming?
+- Can I share on other social media?
+
+### Blockchain
+- What is a blockchain?
+- What is the Steem blockchain?
+- How does bandwidth work on the Steem blockchain?
+- What is the difference between Steem and Steemit?
+- How is Steem different from Bitcoin?
+- What is the difference between Proof of Work, Proof of Stake, and Delegated Proof of Stake?
+- How often does the Steem blockchain produce a new block?
+- Is there a way to see the raw data that is stored in the blockchain?
+- Where can I find the information for the official launch of the blockchain?
+- Can I mine STEEM?
+
+### Steemit, Inc.
+- Who is the CEO of Steemit?
+- Can I invest in Steemit?
+- What does Steemit’s development roadmap look like?
+- Am I allowed to use the Steem and Steemit logos?
+- Can I purchase official Steemit merchandise?
+- Did Steemit "pre-mine" tokens?
+- What is the Steemit Privacy Policy?
+
+### Security
+- How can I keep my Steem account secure?
+- Why should I be careful with my master password?
+- Why is the master password a long string of gibberish?
+- What are my different keys for?
+- What do I do if I lost my password/keys?
+- Are my STEEM and Steem Dollar tokens insured in the event of a hack or if someone takes over my account?
+- What should I do if I discover that someone hacked my account?
+- How does the stolen account recovery process work?
+- How do I report a security vulnerability?
+
+### Developers
+- Are the Steem blockchain and Steemit.com code open-source?
+- Is there a Github page for Steemit.com?
+- Is there a Github page for the Steem blockchain?
+- What is available for developers interested in Steem and Steemit?
+- How do I use cli_wallet?
+
+### Witnesses
+- What are Steem witnesses?
+- How can I vote for witnesses?
+- How many witnesses can I vote for?
+
+### Miscellaneous
+- What third-party tools are there for Steemit?
+- Is there an official Steemit Facebook page?
+- Is there an official Steemit Twitter account?
+- What is the Steem Whitepaper and what is its purpose?
+- Where can I ask for help if my question was not answered here?
+
+### Disclaimer
+- Third Party References and User Links
# General
-
-## What is Steemit.com?
+## What is steemit.com?
-Steemit is a social network and content rewards platform that makes the crowd the beneficiaries of the attention economy. It does this be rewarding users with STEEM.
+Steemit has redefined social media by building a living, breathing, and growing social economy - a community where users are rewarded for sharing their voice. It's a new kind of attention economy.
-Steemit has redefined social media by building a living, breathing, and growing social economy; a community where users are getting rewarded for sharing their voice.
+^
+## How does Steemit work?
-^
-
-## How does Steemit work?
+Steemit.com is one of the many websites (including [Busy.org](https://busy.org/), [DTube](https://d.tube/), and [Utopian.io](https://utopian.io/)) that are powered by the Steem blockchain and STEEM cryptocurrency. All of these websites read and write content to the Steem blockchain, which stores the content in an immutable blockchain ledger, and rewards users for their contributions with digital tokens called STEEM.
-Steemit is a social media platform that works by having the crowd reward the crowd for their content. It does this thanks to the Steem blockchain and cryptocurrency; Steem is 'minted' daily and distributed to content producers according to the votes they get.
+Every day, the Steem blockchain mints new STEEM tokens and adds them to a community's "rewards pool". These tokens are then awarded to users for their contributions, based on the votes that their content receives. Users who hold more tokens in their account as "Steem Power" will get to decide where a larger portion of the rewards pool is distributed.
-^
-
-## How does Steemit differ from other social media websites?
+^
+## How does Steemit differ from other social media websites?
-Most social media sites extract value from their userbase for the benefit of shareholders alone. Steemit is different, it's a new kind of attention economy. By connecting with the Steem blockchain (which is decentralized and controlled by the crowd), Steemit users receive all the benefits and rewards for their attention.
+While most social media sites extract this value for the benefit of their shareholders, Steemit believes that the users of the platform should receive the benefits and rewards for their attention and the contributions they make to the platform.
-^
-
-## Does it cost anything to post, comment, or vote?
+^
+## What do I need to do in order to secure my account?
-No. It is free to post, comment, and vote on content on Steemit.com. You might even get paid for it!
+Unlike most social media websites, **there is no way to recover your account if you lose your password / owner key!** This is why it is extremely important that you save and backup your password somewhere safe. It is strongly recommended that you store an offline copy in case of a hard drive failure or other calamity. Consider digital offline storage, such as an external disk or flash drive, as well as printed paper stored in a fireproof safe. Use a safe deposit box for best redundancy.
-^
-
-## Can I earn digital tokens on Steemit? How?
+If you leak your private key to another user or a third-party website, that user or website will have full access to your account. This means they can steal it, as well as the funds inside of it. It is therefore not recommended to enter your private key information with any other user or third-party website. If you believe your account has been compromised, you should change your password/keys right away.
+
+Each account has multiple keys, which each have different levels of authority: owner, active, posting, and memo. The information on the different types of keys and their purposes, as well as more information on password and key security, can be found in the section on Security .
+
+^
+##
+
+No. It is free to post, comment, and vote on content on steemit.com. You might even get paid for it!
+
+^
+## Can I earn digital tokens on Steemit? How?
You can earn digital tokens on Steemit by:
-**Posting** - By sharing your posts, you can earn upvotes from community members. Depending on the upvotes you receive, you will get a portion of the ongoing Steem reward pool.
+**Posting** - By sharing your posts, you can earn upvotes from community members. Depending on the upvotes you receive, you may get a portion of the "rewards pool".
+
+**Voting and curating** - If you discover a post and upvote it before it becomes popular, you can earn a curation reward. The reward amount will depend on the amount of Steem Power you have.
-**Voting and curating** - If you discover a post and upvote it before it becomes popular, you can earn a curation reward. The reward amount will depend on the amount of STEEM Power you have.
+**Purchasing** - Users can purchase STEEM or Steem Dollar tokens directly through their Steemit wallet using bitcoin, Ether, or BitShares tokens. They are also available from other markets and exchanges including [Binance](https://www.binance.com/), [BitShares](https://openledger.info/), [Bittrex](https://bittrex.com), [BlockTrades](https://blocktrades.us), [Changelly](https://changelly.com), [GOPAX](https://www.gopax.co.kr), [HitBTC](https://hitbtc.com/), [Poloniex](https://poloniex.com), [Shapeshift.io](https://shapeshift.io), and [UpBit](https://upbit.com/).
-**Purchasing** - Users can purchase STEEM or Steem Dollar tokens directly through the Steemit wallet using bitcoin, Ether, or BitShares tokens. They are also available from other markets and exchanges including BlockTrades, Poloniex, Bittrex, Shapeshift.io, and Changelly. STEEM tokens that are powered up to STEEM Power earn a small amount of interest for holding.
+**Interest** - STEEM tokens that are powered up to Steem Power will earn a small amount of interest for holding.
-^
-
-## Where do the tokens come from?
+^
+## Where do the tokens come from?
-The Steem network continually creates digital tokens to reward content creators and curators. Some of the newly-created tokens are transferred to users who add value to Steemit by posting, commenting, and voting on other people's posts. The remainder is distributed to holders of STEEM Power and the witnesses that power the blockchain.
+The Steem network continually creates new digital tokens to reward content creators and curators. Some of the newly-created tokens are transferred to users who add value to Steem by posting, commenting, and voting on other people's posts. The remainder is distributed to holders of Steem Power and the witnesses that power the blockchain.
-^
-
-## Where does the value come from?
+^
+## Where does the value come from?
At its root, Steem is simply a points system. However, because this points system is blockchain-based, the points can be traded on markets as tokens. People buy and sell these tokens, and many hold in anticipation of increased purchasing power for various Steem-related services.
By analogy, Steem is a game system where users compete for attention and rewards by bringing content and adding value to the platform. The rewards people earn are tokens that have market value and are readily tradable. It is similar to how someone playing a video game could obtain a limited item or currency by playing the game. If the currency or items are transferable between users, then they can sell or buy them on game item markets.
-^
-
-## Why are people getting vastly different rewards?
+^
+## Why are people getting vastly different rewards?
Steemit is not a "get rich quick" scheme. While it is possible to post content that goes viral quickly and earn a lot of rewards on a single post, this is not typical for most users.
@@ -268,89 +261,102 @@ Most of the authors that you see earning high rewards are users that have spent
It is best to have realistic expectations, without focusing on rewards when you are first starting out. Work on building a following, making connections, and developing a good reputation. Consistency will pay off in the long run.
-^
+^
+## What are Smart Media Tokens (SMTs)?
+
+A Smart Media Token (SMT) is a native digital asset on the Steem blockchain that can be quickly launched by anyone to help monetize online content and create incentives to encourage desired user behavior.
+
+They're like Ethereum's ERC-20 tokens, but with certain built-in ‘Proof-of-Brain’ properties and a token distribution reward system designed specifically for digital content businesses.
+
+SMTs are planned to be launched in 2018!
+
+More information can be found on the SMTs website: [smt.steem.io](https://smt.steem.io/).
+
+^
# Accounts
-
-## How do I create an account?
+## How do I create an account?
-Click on the "Sign Up" link at the top of Steemit.com to get started.
+Click on the "Sign Up" link at the top of steemit.com to get started.
-You will be asked to verify your email address and phone number. After your email address and phone number have been verified, you will be added to the waiting list. You will be notified via email once your account is approved.
+You will be asked to enter your email address and verify your phone number. After your information has been verified, you will be added to the waiting list to receive an account. You will be notified via email once your account is approved.
-After you receive notification that your account is approved, click on the link in the email to finish the account creation process. Be sure to save and backup your username and password. It is very important that you do not lose your password. There is no way to recover your password or access your account if it is lost. Once your password is saved and backed up, click on the "Create Account" button to create the account.
+After you receive notification that your account is approved, click on the link in the email to finish the account creation process. **Be sure to save and backup your username and password.** It is very important that you do not lose your password. There is no way to recover your password or access your account if it is lost. Once your password is saved and backed up, click on the "Create Account" button to create the account.
-^
-
-## What information do I need to provide in order to create an account?
+^
+## What information do I need to provide in order to create an account?
You will need to provide your email address and phone number.
-^
-
-## How long does the account approval process take?
+^
+## How long does the account approval process take?
-Most accounts are approved within 24 hours. Some may take up to a week.
+Some accounts are approved faster than others. Most accounts are approved within 24 hours. Some may take a week or more to review.
-If your account has not been approved after one week, please ask for help in the #help channel on steemit.chat .
+If your account has not been approved after more than a week, you can ask for help in the #help channel on steem.chat .
-^
-
-## Why do I need to provide my email and phone number?
+^
+## Can I speed up the account approval process?
-To create an account on the blockchain, it costs STEEM tokens. When you create an account through Steemit.com, Steemit Inc. is supplying the tokens to pay the account creation fee. In order to prevent users from abusing the paid-for signup and creating multiple accounts, we need to be able to verify that each user is only signing up for one account.
+There is currently no way to speed up the account approval process. If you are unable to wait, there are third-party websites listed below that allow you to bypass the approval process and pay to open an account.
-^
-
-## Can I create a Steem account without an email and phone number?
+^
+## Why do I need to provide my email and phone number?
-The only way to have an account created via Steemit.com is to supply your email and phone number. Because Steem is an open and permissionless network, there are other ways to create a Steem account. Any Steem blockchain account can be used on Steemit.com
+To create an account on the blockchain, it costs STEEM tokens. When you create an account through steemit.com, Steemit Inc. is supplying the tokens to pay the account creation fee. In order to prevent users from abusing the paid-for signup and creating multiple accounts, we need to be able to verify that each user is only signing up for one account.
-^
-
-## What are other ways to create an account on the blockchain besides using Steemit.com?
+^
+## Can I create a Steem account without an email and phone number?
+
+The only way to have an account created via steemit.com is to supply your email and phone number. Because Steem is an open and permissionless network, there are other ways to create an account. Any Steem blockchain account can be used on steemit.com.
+
+^
+## What are other ways to create an account on the blockchain besides using steemit.com?
If you are willing to pay your own signup fee, then there are other ways to create a new account on the blockchain.
-There is a third-party tool called AnonSteem that accepts bitcoin, Litecoin, STEEM, or SBD to anonymously create a Steem account. You do not need to have an existing Steem blockchain account to use the service, but there is a charge on top of the blockchain account creation fee for using the service.
+There is a third-party tool called SteemCreate that accepts credit cards, or BTC to create a Steem account. You do not need to have an existing Steem blockchain account to use the service, but there is a charge on top of the blockchain account creation fee for using the service.
+
+There is a third-party tool called BlockTrades that accepts bitcoin, Litecoin, STEEM, SBD, BitShares, Dash, Dogecoin, Ethereum, and more to create a Steem account. You can also send extra tokens to pre-load the account with additional Steem Power. You do not need to have an existing Steem blockchain account to use the service, but there is a charge on top of the blockchain account creation fee for using the service.
-There is also a third-party tool called SteemConnect that allows you to create accounts by paying or delegating the account creation fee. There is no additional fee to use the service, but does require an existing Steem blockchain account to pay the account creation fee to create the account.
+There is a third-party tool called AnonSteem that accepts bitcoin, Litecoin, STEEM, or SBD to anonymously create a Steem account. You do not need to have an existing Steem blockchain account to use the service, but there is a charge on top of the blockchain account creation fee for using the service.
-^
-
-## It is not letting me create an account with my phone number. What should I do?
+There is a third-party tool called SteemConnect that allows you to create accounts by paying or delegating the account creation fee. There is no additional fee to use the service, but does require an existing Steem blockchain account to pay the account creation fee to create the account.
-Ask for help in the #help channel on steemit.chat .
+^
+## It is not letting me create an account with my phone number. What should I do?
-^
-
-## What happens if my email or phone number changes?
+Ask for help in the #help channel on steem.chat .
+
+^
+## What happens if my email or phone number changes?
Currently there is no way to change the email or phone number that is linked to your account. Though once your account is created, you can continue to use it even if the email or phone number that is linked to the account has changed.
-^
-
-## Am I allowed to create more than one account?
+^
+## Am I allowed to create more than one account?
+
+Each user is allowed only one paid-for account created via steemit.com, however users are allowed to create as many accounts as they want on the blockchain. Creating additional accounts on the blockchain requires users to pay their own account creation fee using one of the third-party services listed above.
-Each user is allowed only one paid-for account created via Steemit.com, however users are allowed to create multiple accounts on the blockchain. Creating additional accounts on the blockchain requires users to pay their own account creation fee for any additional accounts.
+^
+## Can I change my username?
-^
-
-## Can I delete or deactivate my account?
+Account names can not be changed. If you would like a new account name, you must pay to create a new account using a third-party account creation service.
+
+^
+## Can I delete or deactivate my account?
Accounts can not be deactivated or deleted. The account along with all of its activity is permanently stored in the blockchain.
-^
+^
# Community
-
-## Is there an Etiquette Guide for Steemit?
+## Is there an Etiquette Guide for Steemit?
-There are no official rules for participating on Steemit.com, but one of the users @thecryptofiend has created an Etiquette Guide for the community. While it is not required to follow the suggestions in the guide, they are standards that many users in the community choose to follow.
+There are no official rules for participating on steemit.com, but one of the users @thecryptofiend has created an Etiquette Guide for the community. While it is not required to follow the suggestions in the guide, they are standards that many users in the community choose to follow.
-^
-
-## Am I required to verify my identity?
+^
+## Am I required to verify my identity?
Verification is a process where users give evidence to show that they are the person that they claim to be. This is to reduce fraud and people impersonating known figures. If you would like to remain anonymous, that is perfectly fine. However if you claim to be someone specific, the community may expect that you verify you are who you say you are.
@@ -358,17 +364,15 @@ There are a number of ways to do this. The most common way to verify your identi
Many users also like to post a photo or a video which shows them holding up a sheet of paper with the current date and their Steem account name handwritten on it. This is a great way to add a personal touch to verifying.
-^
+^
# Site Navigation
-
-## How do I upvote a post or comment?
+##
To upvote a post or comment, click on the "upvote" icon at the bottom of the post/comment.
-^
-
-## What do the Home, New, Hot, Trending, and Promoted links show?
+^
+## What do the Home, New, Hot, Trending, and Promoted links show?
These are various ways to sort Steem posts.
@@ -382,11 +386,10 @@ These are various ways to sort Steem posts.
**Promoted** - Listings that are boosted by Steem Dollar payments get promoted for greater visibility.
-^
-
-## What information is available in my account menu?
+^
+##
-You can get to your account menu by clicking on the avatar icon in the top-right corner of a Steemit.com page.
+You can get to your account menu by clicking on the avatar icon in the top-right corner of a steemit.com page.
**Feed** - Here is where you go to see the most recent posts from the people you follow.
@@ -404,9 +407,8 @@ You can get to your account menu by clicking on the avatar icon in the top-right
**Logout** - If you'd like to logout.
-^
-
-## How do I see my recent rewards?
+^
+## How do I see my recent rewards?
The Rewards drop-down menu is available on your profile/blog page. Click it and there are two links:
@@ -416,43 +418,38 @@ The Rewards drop-down menu is available on your profile/blog page. Click it and
You can also view the same information for other users by visiting their profile.
-^
-
-## What information is shown in my wallet?
+^
+## What information is shown in my wallet?
-Your wallet shows how many STEEM and Steem Dollar tokens you have in your account. It shows how much STEEM Power it has, and how much SP is delegated. It also shows how many of your STEEM and Steem Dollar tokens are being held in the savings account, which is a balance that is subject to 3 day withdraw waiting period. The wallet page shows any the progress of any Steem Dollar to STEEM conversions as well as the status of a power down. It also shows an estimated value of all the tokens in your account, based on the recent market prices of STEEM and SBD.
+Your wallet shows how many STEEM and Steem Dollar tokens you have in your account. It shows how much Steem Power it has, and how much SP is delegated. It also shows how many of your STEEM and Steem Dollar tokens are being held in the savings account, which is a balance that is subject to 3 day withdraw waiting period. The wallet page shows any the progress of any Steem Dollar to STEEM conversions as well as the status of a power down. It also shows an estimated value of all the tokens in your account, based on the recent market price of STEEM.
-^
-
-## How do I transfer my STEEM or Steem Dollars into savings?
+^
+## How do I transfer my STEEM or Steem Dollars into savings?
Your savings balance is STEEM and SBD tokens that are subject to 3 day withdraw waiting period. This is an extra security measure in case your account credentials are compromised. To transfer STEEM or SBD tokens into savings, click on the drop-down arrow next to STEEM or STEEM DOLLARS in your wallet, and select "Transfer to Savings".
-^
-
-## How do I send money to another user?
+^
+## How do I send money to another user?
- From your wallet page, click the STEEM or Steem Dollar balances with the down arrow next to them.
-- In the drop-down menu, click 'Transfer'.
-- Type the username of the account you want to send the STEEM or Steem Dollars to. Double and triple check spelling.
+- In the drop-down menu, click 'Transfer'.
+- Type the username of the account you want to send the STEEM or Steem Dollars to. Double and triple check the spelling.
- Enter the amount of STEEM or Steem Dollars to send.
- Enter a memo to go along with the transaction (optional).
- Click Submit.
- You will be prompted for your password. You will need to enter your master password or active key.
-^
-
-## Will I receive notifications when there is activity with my account?
+^
+## Will I receive notifications when there is activity with my account?
When there is new activity in your feed, you receive a reply from another user, or there is a new transfer in your wallet, you will receive a notification in your account menu. It will show a little red number showing the number of new notifications.
Steemit also allows you to subscribe to receive additional notifications when users mention you in a comment or post.
-Currently, there are no options to receive notifications for votes directly on Steemit.com. But, there is a third-party application https://steemstats.com/, developed by @jesta, which has an option to set up additional notifications on your computer.
+Currently, there are no options to receive notifications for votes directly on steemit.com. But, there is a third-party application https://steemstats.com/, developed by @jesta, which has an option to set up additional notifications on your computer.
-^
-
-## What is shown in my profile?
+^
+## What is shown in my profile?
At the top of your profile is your display name and reputation score. Below your display name is the number of followers you have, the number of posts and comments you have written, and the number of people you are following. It also shows the month and year when your account was created.
@@ -460,79 +457,68 @@ You have the option to change your avatar and display name on the Settings page.
You can view your own profile by clicking on the link to your Blog in your account menu.
-^
-
-## How do I change my avatar image and other profile information?
+^
+## How do I change my avatar image and other profile information?
-Your profile info, avatar image, and cover image are set in your Settings page. In order to update your avatar picture and cover image, you will need to host the images somewhere. This can be done by uploading it to a Steemit comment or post, or using a third-party image host such as Postimage . Once your image is uploaded, copy its URL and paste it into the "Profile Picture URL" box for the avatar, or the "Cover Image URL" box for the cover image. Then click the Update button and enter your password or active key.
+Your profile info, avatar image, and cover image are set in your Settings page. In order to update your avatar picture and cover image, you will need to host the images somewhere. This can be done by uploading it to a Steemit comment or post, or using a third-party image hosting site such as Postimage . Once your image is uploaded, copy its URL and paste it into the "Profile Picture URL" box for the avatar, or the "Cover Image URL" box for the cover image. Then click the Update button and enter your password or active key.
-^
-
-## What is the recommend size for the cover image?
+^
+## What is the recommend size for the cover image?
The cover image will be resized/scaled depending on the device being used. Therefore it is recommend to use an image that will still look good when cropped or resized. A 2048x512 image is the optimal size to work for most devices.
-^
-
-## How can I control whether I see "Not Safe For Work" (NSFW) content?
+^
+## How can I control whether I see "Not Safe For Work" (NSFW) content?
By default, content that users have tagged as "NSFW" will be hidden, but a link will be shown to reveal the content.
You can update your display preference with the Settings page so that NSFW content is always shown by default, remains hidden until clicked, or is completely hidden with no option to reveal.
-^
-
-## How do I search for content?
+^
+## How do I search for content?
In the upper right corner of Steemit, there is a magnifying glass search link where you can find posts using a keyword search.
There is also an **Explore** link in the main menu, where you can browse through posts based on tags.
-^
-
-## Can I see which users I have muted?
+^
+## Can I see which users I have muted?
Yes. This can be seen under the Settings page.
-^
-
-## Can I see which users have muted me?
+^
+## Can I see which users have muted me?
-No. This information is not presented on Steemit.com.
+No. This information is not presented on steemit.com.
-^
-
-## Can I see the list of users I am following, and who is following me?
+^
+## Can I see the list of users I am following, and who is following me?
Yes. You can see the list of followers or people you are following by clicking on the links on your profile page.
-^
-
-## What languages are supported?
+^
+## What languages are supported?
-English is the most-used language used on the Steemit platform, but communities are forming that speak other languages.
+Currently steemit.com supports English, Spanish, Russian, French, Italian, Korean, Polish, and Chinese. There are also many communities using the platform that speak other languages. If you are interested in joining our translation team to add additional languages or help support the ones we have, please [email us](mailto:translate@steemit.com).
-^
+^
# Posting
-
-## What can users post to Steemit?
+## What can users post to Steemit?
Steem is an open platform meant to host and welcome any legal content. Users can post anything they want, whether it be phrases, quotes, blogs, anecdotes, photos, videos, memes, songs, and more. Be creative!
-^
-
-## What are the different choices for post rewards (50%/50%, Power Up 100%, Decline Payout)?
+^
+## What are the different choices for post rewards (50%/50%, Power Up 100%, Decline Payout)?
-- **50%/50%** - This rewards in half STEEM Power, and half liquid STEEM / Steem Dollars. The ratio of liquid STEEM to Steem Dollars rewarded is based on network conditions at the time of payout. This is the default payout option.
+- **50%/50%** - This rewards in half Steem Power, and half liquid STEEM / Steem Dollars. The ratio of liquid STEEM to Steem Dollars rewarded is based on network conditions at the time of payout. This is the default payout option.
-- **Power Up 100%** - This option rewards the post in 100% STEEM Power.
+- **Power Up 100%** - This option rewards the post in 100% Steem Power.
- **Decline Payout** - Use this option to receive no post rewards. Votes will affect the post's position on the trending ranking but no rewards are paid from Steem's reward pool. Replies made to the post are still eligible for rewards.
-^
-
-## How do I add images and photos to my posts?
+^
+## How do I add images and photos to my posts?
You can browse your hard drive to add an image by clicking on the "selecting them" link from within the editor.
@@ -540,41 +526,33 @@ If you have an image copied to your clipboard, you can simply paste (`ctrl + v`)
Pictures can also be hosted on an external site. Paste the image's web address (URL) into the editor and it will automatically be added.
-^
-
-## How do I set the thumbnail image for my post?
+^
+## How do I set the thumbnail image for my post?
The first image in the post will automatically be set as the thumbnail image.
-^
-
-## What is the recommend aspect ratio for thumbnail images?
+^
+## What is the recommend aspect ratio for thumbnail images?
The recommend aspect ratio for thumbnail images is 16x9.
-^
-
-## How do I add videos to my posts?
-
-To add a YouTube or Vimeo video to your blog post, simply paste the link to the video into the post.
+^
+## How do I add videos to my posts?
-You can also read this guide from @algimantas, which has more detailed instructions:
+To add a DTube, YouTube, or Vimeo video to your blog post, simply paste the URL link to the video into the post.
-^
-
-## Is there a way I can make my images smaller?
+^
+## Is there a way I can make my images smaller?
-Yes, but the picture must be resized before it is uploaded into the Steemit.com editor. This can be done in your favorite photo editing software, or online by uploading to a third-party website that features editing such as imgur.com.
+Yes, but the picture must be resized before it is uploaded into the steemit.com editor. This can be done in your favorite photo editing software, or online by uploading to a third-party website that features editing such as imgur.com.
-^
-
-## What are tags?
+^
+## What are tags?
Tags are a way to categorize your content, so that others can find it. The more relevant the tags are to the post, the more like-minded people will come across it.
-^
-
-## What tags should I use?
+^
+## What tags should I use?
Try to use tags that are relevant to your post, and that will be popular for other people to browse. For example, "mytriptoalaska" may be relevant to your post, but readers are probably not going to go searching for that. Using "travel" would be a better choice for a tag in this case.
@@ -584,21 +562,18 @@ Be mindful when choosing tags. If your tags aren’t related to your post, your
All tags must be lowercase letters. Spaces aren't allowed, but hyphenated words with a single dash are.
-^
-
-## How many tags can I use?
+^
+## How many tags can I use?
-You can use up to 5 tags per post.
+You can use up to 5 tags per post.
-^
-
-## Why is the "Post" button grayed out?
+^
+## Why is the "Post" button grayed out?
A post must have a title, body, and at least one valid tag. If any of these are missing, then the "Post" button will be disabled.
-^
-
-## How do I format text in Markdown?
+^
+## How do I format text in Markdown?
Some common markdown syntax is:
- `**bold**` **bold**
@@ -617,25 +592,24 @@ Text can be sized using headers:
### H3
#### H4
-For more advanced formatting, a guide describing the common markdown formatting syntax can be found here: Markdown Cheatsheet
+Instructions on how to justify text, as well as wrap text around images pulled to the left or right can be found in [this guide](https://steemit.com/steemit/@steemitblog/new-advanced-formatting-features).
-^
-
-## How often can I post?
+For more advanced formatting, a guide describing the common markdown formatting syntax can be found here: Markdown Cheatsheet .
+
+^
+## How often can I post?
You are allowed to post almost as often as you like. Currently, posts must be spaced 5 minutes apart. However, the community may not find value in users that are posting too frequently. Keep in mind what your audience will be interested in viewing, so that you do not overwhelm your followers with too much content.
-^
-
-## How long can my post be?
+^
+## How long can my post be?
Post sizes are limited to about 64,000 characters including formatting. This is ample for most posts. If writing blogs, consider how much people are willing to read at one time. If you make your posts too long, readers may lose interest which may affect the amount of upvotes and rewards you receive.
-^
-
-## If posting in a language other than English, how will I get recognized?
+^
+## If posting in a language other than English, how will I get recognized?
-You can use language-specific tags to help you to reach the audience that speaks your language.
+You can use language-specific tags to help you to reach the audience that speaks your language.
Language-specific groups include:
- Chinese = cn
@@ -646,15 +620,13 @@ Language-specific groups include:
- French = fr
- Portuguese = pt
-^
-
-## Can I delete something I posted?
+^
+## Can I delete something I posted?
-The blockchain will always contain the full edit history of posts and comments, so it can never be completely deleted. If you would like to update a post so that users cannot see the content via Steemit.com, you can edit the post and replace it with blank content for as long as the post is active. After seven days, the post can no longer be edited.
+The blockchain will always contain the full edit history of posts and comments, so it can never be completely deleted. If you would like to update a post so that users cannot see the content via steemit.com, you can edit the post and replace it with blank content for as long as the post is active. After seven days, the post can no longer be edited.
-^
-
-## What does "Promoting" a post do?
+^
+## What does "Promoting" a post do?
When you make a post, there is the option to promote it with Steem Dollars. It will then show up in the “Promoted” tab. The order that it appears in the list depends on how much the post was promoted for. Posts with a higher promoted amount will be higher than posts with less.
@@ -662,72 +634,82 @@ Steem Dollars spent to promote a post are paid to the account @null, which nobod
You can promote your own posts, or posts that you like from other users.
-^
-
-## How do I promote a post?
+^
+## How do I promote a post?
At the bottom of each post is a button to "Promote". After clicking the button, type the number of Steem Dollars that you want to spend and click “PROMOTE”. The operation will require your master password or active key.
-^
+^
# Comments
-
-## Can I earn digital tokens for commenting?
+##
Yes, comments that are upvoted can earn rewards just like posts!
-^
-
-## How often can I comment?
+^
+##
There is a 20 second wait time in between comments to limit spam.
-^
+^
# Economics
-
-## Where do the new STEEM tokens come from?
+## Where do the new STEEM tokens come from?
-Blockchains like Steem and Bitcoin produce new tokens each time a block is produced. Unlike Bitcoin, where all of the new coins go to the block producers (called miners), the Steem blockchain allocates a majority of the new tokens to a reward fund. The reward fund gives users tokens for participating in the platform.
+Blockchains like Steem and Bitcoin produce new tokens each time a block is produced. Unlike Bitcoin, where all of the new coins go to the block producers (called miners), the Steem blockchain allocates a majority of the new tokens to a reward fund called the "rewards pool". The rewards pool gives users tokens for participating in the platform based on the value they add.
-^
-
-## How many new tokens are generated by the blockchain?
+^
+## How many new tokens are generated by the blockchain?
Starting with the network's 16th hard fork in December 2016, Steem began creating new tokens at a yearly inflation rate of 9.5%. The inflation rate decreases at a rate of 0.01% every 250,000 blocks, or about 0.5% per year. The inflation will continue decreasing at this pace until the overall inflation rate reaches 0.95%. This will take about 20.5 years from the time hard fork 16 went into effect.
-^
-
-## How are the new tokens distributed?
+^
+## How are the new tokens distributed?
Out of the new tokens that are generated:
-- 75% go to the reward pool, which is split between authors and curators.
-- 15% of the new tokens are awarded to holders of STEEM Power.
+- 75% go to the reward pool, which is split between authors and curators.
+- 15% of the new tokens are awarded to holders of Steem Power.
- The remaining 10% pays for the witnesses to power the blockchain.
-^
-
-## What is the reward pool?
+^
+## Which exchanges are STEEM and SBD listed on?
+
+STEEM and SBD are listed on the following exchanges:
+
+| Exchange | STEEM | SBD |
+| ------------- |:-------------:| -----:|
+| [Binance](https://www.binance.com/) | Y | N |
+| [BitShares](https://openledger.info/) | Y | Y |
+| [Bittrex](https://bittrex.com) | Y | Y |
+| [BlockTrades](https://blocktrades.us) | Y | Y |
+| [Changelly](https://changelly.com) | Y | N |
+| [GOPAX](https://www.gopax.co.kr) | Y | Y |
+| [HitBTC](https://hitbtc.com/) | Y | Y |
+| [Poloniex](https://poloniex.com) | Y | Y |
+| [Shapeshift.io](https://shapeshift.io) | Y | N |
+| [UpBit](https://upbit.com/) | Y | Y |
+
+^
+## What is the reward pool?
Every day, a fixed amount of STEEM tokens are allocated to the network reward fund, commonly called the "reward pool." These get distributed to authors and curators for posting and voting on content.
-^
-
-## How is the reward pool split between authors and curators?
+^
+## How is the reward pool split between authors and curators?
+
+Up to 25% of a post's payout is awarded to curators (the people who upvoted the post) as a reward for discovering the content. The other 75% is awarded to the author.
-Up to 25% of a post's payout is awarded to curators (the people who upvoted the post) as a reward for discovering the content. The other 75% is awarded to the author. If curators vote for a post within the first 30 minutes of it being created, a portion of their curation reward is added to the author payout. This portion is linear to the age of the post between 0 and 30 minutes. Therefore upvoting at 15 minutes old will donate half of your potential curation reward to the author.
+If curators vote for a post within the first 30 minutes of it being created, a portion of their curation reward is added to the author payout. This portion is linear to the age of the post between 0 and 30 minutes. As an example: upvoting at 15 minutes will donate half of your potential curation reward to the author.
-^
-
-## Will the reward pool pay out more or less depending on who votes?
+^
+## Will the reward pool pay out more or less depending on who votes?
There is a fixed amount of STEEM coins that gets added to the rewards pool each day. In the short term, the amount of coins that get paid out may be higher or lower depending on the amount of voting activity, but over time it will pay out the full amount of rewards regardless of who votes.
-Votes in Steem are stake-weighted. Therefore voters with more STEEM Power have a greater influence over the allocation than voters with less SP, but their votes do not increase the amount of rewards.
+Votes in Steem are stake-weighted. Therefore voters with more Steem Power have a greater influence over the allocation than voters with less SP, but their votes do not increase the amount of rewards in the rewards pool.
-^
-
-## Why do the earnings for my post go up or down?
+^
+## Why do the earnings for my post go up or down?
The amount that is shown next to a post is a "**Potential Payout**". This is an estimated value of how much money the post will make based on the votes that have occurred so far. Depending on various factors, this value can go up or down until the payout window closes:
@@ -740,141 +722,122 @@ The amount that is shown next to a post is a "**Potential Payout**". This is an
- If the price of STEEM goes up, the potential payout of all posts can go up.
- If the price of STEEM goes down, the potential payout of all posts can go down.
-^
-
-## When can I claim my rewards?
+^
+## When can I claim my rewards?
Posts and comments remain active for 7 days. When the period is over, you are able to claim their earned rewards. In your Wallet, click the Claim Rewards button to add the tokens to your account.
-^
-
-## What is the difference between STEEM, STEEM Power, and Steem Dollars?
+^
+## What is the difference between STEEM, Steem Power, and Steem Dollars?
-**STEEM** - STEEM is the base liquid currency token in the platform. STEEM can be powered up into STEEM Power, traded for Steem Dollars, and transferred to other accounts. It is a cryptocurrency token, similar to bitcoin.
+**STEEM** - STEEM is the base liquid currency token in the platform. STEEM can be powered up into Steem Power, traded for Steem Dollars, or transferred to other accounts. It is a cryptocurrency token, similar to bitcoin.
-**STEEM Power** - STEEM Power (abbreviated SP) is a measurement of how much influence a user has in the Steem network. The more STEEM Power a user holds, the more they can influence the value of posts and comments. STEEM Power is less liquid. If a user wishes to “Power Down” SP, they will receive equal distributions of the STEEM weekly, over a 13 week period.
+**Steem Power** - Steem Power (abbreviated SP) is a measurement of how much influence a user has in the Steem network. The more Steem Power a user holds, the more they can influence the value of posts and comments. Steem Power is less liquid. If a user wishes to “Power Down” SP, they will receive equal distributions of the STEEM weekly, over a 13 week period.
-**Steem Dollars** - Steem Dollars (commonly abbreviated SBD) are liquid stable-value currency tokens designed to be pegged to $1 USD. Steem Dollars can be traded with STEEM, and transferred to other accounts for commerce or exchange. Steem Dollars may also be converted into STEEM in a process that takes 3.5 days. Steem Dollars can be used to buy things in marketplaces, such as PeerHub.com.
+**Steem Dollars** - Steem Dollars (commonly abbreviated SBD) are liquid stable-value currency tokens designed to be pegged to $1 USD. Steem Dollars can be traded with STEEM, and transferred to other accounts for commerce or exchange. Steem Dollars may also be converted into STEEM via a process that takes 3.5 days. Steem Dollars can be used to buy things in marketplaces, such as [The Steemit Shop](https://thesteemitshop.com/).
-^
-
-## What is delegated STEEM Power?
+^
+## What is delegated Steem Power?
-Users have the option to delegate STEEM Power to other users. When a user is delegated STEEM Power, their content votes and curation rewards are calculated as if it were their own STEEM Power. Users are not able to power down or cash out delegated STEEM Power, as it still belongs to the original owner.
+Users have the option to delegate Steem Power to other users. When a user is delegated Steem Power - their bandwidth, content votes, and curation rewards are calculated as if it were their own Steem Power. Users are not able to power down or cash out delegated Steem Power however, as it still belongs to the original owner.
-Most users will have a small amount of STEEM Power delegated to them by the Steemit account after creating an account via Steemit.com.
+Most users will have a small amount of Steem Power delegated to them by the Steemit account after creating an account via steemit.com.
-Delegated STEEM Power shows up in a user's wallet below their actual STEEM Power balance in parentheses.
+Delegated Steem Power shows up in a user's wallet below their actual Steem Power balance in parentheses.
-^
-
-## What determines the price of STEEM?
+^
+## What determines the price of STEEM?
-The price of STEEM is based on the supply and demand of the token, determined by buyers and sellers on the exchanges. It is similar to how the price of a commodity like gold is determined.
+The price of STEEM is based on the supply and demand of the token, as determined by buyers and sellers on the exchanges. It is similar to how the price of a commodity like gold is determined.
-^
-
-## How do I get more STEEM Power?
+^
+## How do I get more Steem Power?
-With STEEM tokens in your wallet, click "Power Up" to turn them into STEEM Power. If you have Steem Dollars, you can convert them to STEEM from your wallet, and then power up the STEEM.
+With STEEM tokens in your wallet, click "Power Up" to turn them into Steem Power. If you have Steem Dollars, you can convert them to STEEM from your wallet, and then power up the STEEM.
-If you don’t already have STEEM or Steem Dollars in your wallet, you can purchase them using bitcoin (BTC), ether (ETH), or BitShares (BTS) tokens. You may purchase BTC on various exchanges, such as Coinbase.com or Localbitcoins.com.
+If you don’t already have STEEM or Steem Dollars in your wallet, you can purchase them using bitcoin (BTC), Ether (ETH), Litecoin (LTC), or BitShares (BTS) tokens. You may purchase BTC on various exchanges, such as Coinbase.com or Localbitcoins.com.
To buy:
-- Click "Buy Steem" from the main menu in the top right corner of Steemit.com, or from your wallet.
+- Click "Buy Steem" from the main menu in the top right corner of steemit.com, or from your wallet.
- Select the currency to deposit, and enter the amount of that currency you wish to use.
- Enter your Steemit account name (without the @) for "Your receive address".
- Click the "Get Deposit Address" button.
- Send the currency to the provided address.
-STEEM purchases made via Steemit.com are facilitated by BlockTrades .
+STEEM purchases made via steemit.com are facilitated by BlockTrades .
-bitcoin can also be exchanged for STEEM on external markets such as Poloniex , Bittrex , ShapeShift.io , and Changelly .
+bitcoin can also be exchanged for STEEM on external markets such as [Binance](https://www.binance.com/), [BitShares](https://openledger.info/), [Bittrex](https://bittrex.com), [Changelly](https://changelly.com), [GOPAX](https://www.gopax.co.kr), [HitBTC](https://hitbtc.com/), [Poloniex](https://poloniex.com), [Shapeshift.io](https://shapeshift.io), and [UpBit](https://upbit.com/).
-^
-
-## How long does it take STEEM or STEEM Power that I purchased to show up in my account?
+^
+## How long does it take STEEM or Steem Power that I purchased to show up in my account?
-Transactions on the Steem blockchain typically only take about three seconds to process, but when you are purchasing the STEEM tokens using bitcoin or some other token, then the transaction must wait for the transaction to be confirmed on the other network. This can often take several hours, and sometimes even days.
+Transactions on the Steem blockchain typically only take about three seconds to process, but when you are purchasing the STEEM tokens using bitcoin or some other token, then the transaction must wait for the transaction to be confirmed on the other network. This can take several hours, and sometimes even days.
If you paid using bitcoin, the third party website bitcoinfees.21.co can estimate the approximate wait time of the transaction based on the fees that were paid. The third party website blockchain.info will lookup the fees that were paid on a specific blockchain transaction.
-^
-
-## What is powering up and down?
+^
+## What is powering up and down?
-**Powering up** - If you have STEEM tokens, you can Power Up to STEEM Power to get more voting influence on posts and comments. Having more STEEM Power also increases the amount of curation rewards and interest that you can earn. More SP also grants more influence on approving Steem witnesses.
+**Powering up** - If you have STEEM tokens, you can Power Up to Steem Power to get more voting influence on posts and comments. Having more Steem Power also increases the amount of curation rewards and interest that you can earn. More SP also grants more influence on approving Steem witnesses.
-**Powering down** - If you have STEEM Power, you can power down to turn it into liquid STEEM over a period of time. The system will transfer 1/13 of your STEEM Power to STEEM each week for about three months (13 weeks), starting 1 week from the time it is started. However, you will lose your influence in the network proportionally to how much is powered down, so think about it carefully. Power downs can be stopped at any time.
+**Powering down** - If you have Steem Power, you can power down to turn it into liquid STEEM over a period of time. The system will transfer 1/13 of your Steem Power to STEEM each week for about three months (13 weeks), starting 1 week from the time it is started. However, you will lose your influence in the network proportionally to how much is powered down, so think about it carefully. Power downs can be stopped at any time.
-^
-
-## What do the dollar amounts for pending payouts represent?
+^
+## What do the dollar amounts for pending payouts represent?
The dollar amounts next to posts and comments are estimates of the potential payout that will occur when the payout period ends, based on the current voting activity and price of STEEM. These potential payout amounts may fluctuate up or down until the payout period ends.
-Payouts occur as a combination of STEEM Power and Steem Dollars. Sometimes the blockchain may substitute STEEM in place of the Steem Dollars based on market conditions.
+Payouts occur as a combination of Steem Power and Steem Dollars. Sometimes the blockchain may substitute STEEM in place of the Steem Dollars based on market conditions.
-The blockchain estimates the dollar value of STEEM and STEEM Power based on the 3.5 day average price of STEEM reported by the witnesses. The blockchain assumes Steem Dollars are worth approximately one USD.
+The blockchain estimates the dollar value of STEEM and Steem Power based on the 3.5 day average price of STEEM reported by the witnesses. The blockchain assumes Steem Dollars are worth approximately one USD.
-^
-
-## Will 1 Steem Dollar always be worth $1.00 USD?
+^
+## Will 1 Steem Dollar always be worth $1.00 USD?
-The market value of a Steem Dollar is dictated by the supply and demand of the token. Therefore it is possible for 1 SBD to be worth more or less than 1 USD depending on market conditions. However, the network's SBD conversion feature serves as a mechanism to hold Steem Dollars within a small margin of the value of USD.
+The market value of a Steem Dollar is dictated by the supply and demand of the token. Therefore it is possible for 1 SBD to be worth more or less than 1 USD depending on market conditions.
-^
-
-## How do Steem Dollar to STEEM conversions work?
+^
+## How do Steem Dollar to STEEM conversions work?
-If you convert Steem Dollars to STEEM on the Wallet page, the blockchain will process the transaction over a period of 3.5 days. At the end of the 3.5 days, the SBD will be gone and replaced by approximately $1 USD worth of STEEM tokens. The "approximately 1 USD worth of STEEM tokens" is based on the median STEEM price over the 3.5 days, using the price feeds from the Steem witnesses. Depending on price fluctuations during the 3.5 days it is possible to end up with more or less than $1 USD worth of STEEM per SBD at the end of the conversion.
+If you convert Steem Dollars to STEEM, the blockchain will process the transaction over a period of 3.5 days. At the end of the 3.5 days, the SBD will be gone and replaced by approximately $1 USD worth of STEEM tokens. The "approximately 1 USD worth of STEEM tokens" is based on the median STEEM price over the 3.5 days, using the price feeds from the Steem witnesses. Depending on price fluctuations during the 3.5 days it is possible to end up with more or less than $1 USD worth of STEEM per SBD at the end of the conversion. This is an advanced user feature, and is currently only available to users using external wallets.
-^
-
-## Is there a way for me to convert my Steem Dollars to STEEM without waiting 3.5 days?
+^
+## Is there a way for me to convert my Steem Dollars to STEEM without waiting 3.5 days?
You can exchange them. Visit the internal Market, found in the main menu. There you can exchange your SBD for STEEM in real-time at whatever the current market price is.
-Depending on market conditions, users may get more STEEM for their SBD by trading them for STEEM on the internal market, rather than using the conversion.
+^
+## What can I do with my STEEM tokens?
-^
-
-## What can I do with my STEEM tokens?
-
-- "Power Up" to STEEM Power
+- "Power Up" to Steem Power
- Exchange for SBD in the internal market
- Withdraw to an exchange, and trade for BTC or other digital tokens
- Purchase items through third-party stores that accept STEEM tokens
-^
-
-## What can I do with my SBD tokens?
+^
+## What can I do with my SBD tokens?
-- Hold them as a stable-value token
- Convert to STEEM via your wallet (takes 3.5 days)
- Exchange for STEEM in the internal market
- Withdraw to an exchange, and trade for BTC or other digital tokens
- Purchase items through third-party stores that accept SBD tokens
-^
-
-## What is a MVEST?
+^
+## What is a MVEST?
-A VEST is a unit of measurement for STEEM Power. A MVEST is one million VESTS. The amount of STEEM Power in one MVEST can be found on steemd.com as `steem_per_mvests`.
+A VEST is a unit of measurement for Steem Power. A MVEST is one million VESTS. The amount of Steem Power in one MVEST can be found on steemd.com as `steem_per_mvests`.
-^
-
-## Can I sell goods and services on Steemit?
+^
+## Can I sell goods and services on Steemit?
-Other than making a post and making sales manually, there is no interface for selling items directly on Steemit.com. You can list goods on the third-party website PeerHub.com . Through PeerHub, you can accept payment in Steem Dollars or STEEM, and you have the option to advertise your items through Steemit posts.
+Other than making a post and making sales manually, there is no interface for selling items directly on steemit.com. You can list goods and services on the third-party websites and accept payment in Steem Dollars or STEEM. You also have the option to advertise your items through Steemit posts.
-^
-
-## How can I withdraw my STEEM or SBD coins?
+^
+## How can I withdraw my STEEM or SBD coins?
-STEEM and SBD tokens are readily tradable to bitcoin, which is readily tradable to the local currency of your choice. There is a link to "Sell" your STEEM and SBD tokens in your wallet, which uses the BlockTrades interface.
+STEEM and SBD tokens are readily tradable to bitcoin, which can be traded for the local currency of your choice. There is a link to "Sell" your STEEM and SBD tokens in your wallet, which uses the BlockTrades interface.
-There are several guides that have been posted by users in the community for using various external exchanges to withdraw STEEM and SBD tokens. Please read the disclaimer before using any of these guides to withdraw your coins. The users, guides, and exchanges listed in the guides are not endorsed by Steemit, Inc. Use the guides below at your own risk.
+There are several guides that have been posted by users in the community for using various external exchanges to withdraw STEEM and SBD tokens. Please read the disclaimer before using any of these guides to withdraw your coins. The users, guides, and exchanges listed in the guides are not endorsed by Steemit, Inc. Use the guides below at your own risk.
It is recommended that you withdraw a small amount first, to verify it works before withdrawing a larger amount.
@@ -890,69 +853,60 @@ https://steemit.com/tutorial/@beanz/how-to-get-my-usdteemit-money-into-my-bank-a
#### Convert STEEM to many other cryptocurrencies via ShapeShift
https://steemit.com/steemit/@shapeshiftio/official-announcement-shapeshift-has-added-steem-to-the-exchange
-^
-
-## Will I get a 1099 from Steemit?
+^
+## Will I get a 1099 from Steemit?
-No, you are not being paid by Steemit. The Steem network rewards you. It is your responsibility to determine what, if any, taxes apply to the transactions you make. Further, it is your responsibility to report and remit the correct tax to the appropriate tax authority. By creating an account, you agree that Steemit Inc is not responsible for determining whether taxes apply to your Steem transactions or for collecting, reporting, withholding, or remitting any taxes arising from any Steem transactions.
+No, you are not being paid by Steemit. The Steem network rewards you. It is your responsibility to determine what, if any, taxes apply to the transactions you make. Further, it is your responsibility to report and remit the correct tax to the appropriate tax authority. By creating an account, you agree that Steemit, Inc. is not responsible for determining whether taxes apply to your Steem transactions, or for collecting, reporting, withholding, or remitting any taxes arising from any Steem transactions.
-^
-
-## How much are the transaction fees for sending tokens to other users?
+^
+## How much are the transaction fees for sending tokens to other users?
-There are never any fees for transfers within the Steem network. However, if you transfer Steem to an exchange and convert it to another currency, you will incur a small fee from the exchange.
+There are never any fees for transfers within the Steem network. However, if you transfer Steem to an exchange and convert it to another currency, you may incur a small fee from the exchange.
-^
-
-## Are there fees for Powering Up, Powering Down, trading on the internal market, or converting SBD to STEEM?
+^
+## Are there fees for Powering Up, Powering Down, trading on the internal market, or converting SBD to STEEM?
No. None of these actions incur any fees.
-^
-
-## How long does it take to transfer STEEM or SBD tokens between users?
+^
+## How long does it take to transfer STEEM or SBD tokens between users?
A transfer of tokens between accounts typically takes 3 seconds. This is far faster than most blockchain tokens.
-^
+^
# Voting and Curating
-
-## What is my voting power?
+## What is my voting power?
Voting power is like an "energy bar" in a computer game that goes down a little bit every time you vote. You start out with 100% voting power. Every time you vote, you will use a small amount of your voting power.
As you use more of your voting power, your votes will carry less influence. A vote with 50% voting power left will be worth 1/2 as much as a vote cast with 100% voting power. Not to worry, the network recharges your voting power by 20% every day.
-^
-
-## How many times can I vote without depleting my voting power?
+^
+## How many times can I vote without depleting my voting power?
Every 100% vote you cast will use 2% of your remaining voting power. Your voting power will recharge by 20% each day. You can vote more than 10 times per day, but each vote will be worth less, and it will take longer to reach full voting power again.
-^
-
-## Can I vote with less than 100% of my voting strength?
+^
+## Can I vote with less than 100% of my voting strength?
-New users can only upvote and downvote with 100% voting strength.
+New users can only upvote and downvote with 100% voting strength.
-Once you reach about 500 STEEM Power, you will see a vote slider appear when you vote. You can use the slider to adjust the weight of your vote, between 1% and 100% voting strength. Voting with less than 100% voting weight will use up less voting power, but it will also have less of an influence on the post or comment's rewards.
+Once you reach about 500 Steem Power, you will see a vote slider appear when you vote. You can use the slider to adjust the weight of your vote, between 1% and 100% voting strength. Voting with less than 100% voting weight will use up less voting power, but it will also have less of an influence on the post or comment's rewards.
Upvotes and downvotes use the same amount of voting power.
-^
-
-## Where can I check my voting power?
+^
+## Where can I check my voting power?
-You can view your current voting power using third party tools such as https://steemd.com/@youraccount or https://steemstats.com.
+You can view your current voting power using third party tools such as https://steemd.com/@youraccount.
-^
-
-## What determines how much of the curation reward goes to the author versus curators?
+^
+## What determines how much of the curation reward goes to the author versus curators?
-The rewards are allocated so that 75% of the payout goes to the author of the post/comment, and 25% goes to the curator.
+The rewards are allocated so that 75% of the payout goes to the author of the post/comment, and 25% goes to the curator.
Of the 25% that goes to the curator, that portion will be split between the author and the curator if the curator votes within the first 30 minutes. The split of the 25% between the author and curator during the first 30 minutes is calculated linearly based on the time the vote is cast.
@@ -962,75 +916,81 @@ Of the 25% that goes to the curator, that portion will be split between the auth
- At 27 minutes, 10% goes to the author and 90% to the curator.
- If a post is upvoted 30 min after posting, 100% of the curation reward goes to the curator.
-^
-
-## Can I get curation rewards for upvoting comments?
+^
+##
Yes. You can earn curation rewards from upvoting both posts and comments!
-^
-
-## Do I get curation rewards for downvoting posts or comments?
+^
+##
No. Since downvoting reduces the rewards on a post/comment, it does not earn curation rewards.
-^
-
-## What are curation trails?
+^
+## What are curation trails?
-Some users decide to use third party applications such as Streemian to automatically cast votes. Users can automatically vote for the same posts and comments that other users does. Typically they will set this up to follow the votes of users who are good at curating. When a user has other users automatically voting for the same content that they do, the people that automatically vote after them are called their "curation trail".
+Some users decide to use third party applications such as Streemian to automatically cast votes. Users can automatically vote for the same posts and comments that other users does. Typically they will set this up to follow the votes of users who are good at curating. When a user has other users automatically voting for the same content that they do, the people that automatically vote after them are called their "curation trail".
-^
-
-## Why don't my upvotes have an effect on a post's rewards?
+^
+## Why don't my upvotes have an effect on a post's rewards?
A user with more SP is going to have a larger influence on the rewards than users with less SP. One vote from a user with a lot of SP can often have more of an effect than 100 votes from users with a small amount of SP.
Even though your vote may not have an immediate effect, when it gets added in along with all the other votes at the end of the payout period, it can still affect the payout. It may also cause more users to vote on the post too, because they saw that you upvoted it - so your votes can have an indirect effect on the payout this way.
-^
-
-## Is there a way to make my votes count for more?
+^
+## Is there a way to make my votes count for more?
-Yes. The more STEEM Power you have, the more influence your votes will have.
+Yes. The more Steem Power you have, the more influence your votes will have.
-The platform does not require that anybody purchase SP in order to participate, and there are many users who have earned a lot of STEEM Power without spending any of their own money. You have the option of purchasing more STEEM Power through your Steemit wallet.
+The platform does not require that anybody purchase SP in order to participate, and there are many users who have earned a lot of Steem Power without spending any of their own money. You have the option of purchasing more Steem Power through your Steemit wallet.
-^
-
-## What are the valid reasons for downvoting?
+^
+## What are the valid reasons for downvoting?
Users are allowed to downvote for any reason that they want. There are many users in the community who recommend only using the downvote on posts that are abusive. It is up to you if you want to follow this etiquette.
-^
-
-## Does a downvote mean that I did something wrong?
+^
+## Does a downvote mean that I did something wrong?
Just because you received a downvote does not mean that you did something wrong. The downvoting person may have just been voting to reallocate the rewards in a way that they felt was more beneficial to the other active posts in the platform. Often users will leave a comment explaining why they downvoted, but sometimes they might not. If they left a reason, it is up to you to determine if you did anything wrong, and if there is anything you want to change.
-^
-
-## Will a downvote hurt my reputation?
+^
+## Will a downvote hurt my reputation?
-Not necessarily. See: What causes my reputation score to go down?
+Not necessarily. See: What causes my reputation score to go down?
-^
-
-## What is the difference between a downvote and a flag?
+^
+## What is the difference between a downvote and a flag?
With the current implementation, there is no difference between a downvote and a flag. They are treated the same at the blockchain level.
-^
+^
# Plagiarism, Spam, and Abuse
-
-## What are Steemit’s policies on plagiarism and spam?
+## What is considered spam or abuse?
+
+- Asking for money, views, upvotes, follows, or resteems.
+- Leaving nearly identical or materially similar comments on multiple posts.
+- Comments that are unrelated to the topic of discussion.
+- Sending unsolicited links or requests to users via wallet memos.
+- Posts that require upvotes to enter or play in a contest or game.
+- Sending users a link to your blog or a post if it is not relevant to the conversation.
+- Posts or comments that include little or nothing more than an offer to trade follows or upvotes.
+- Using tags that are unrelated to the post.
+- Threatening users with any type of physical violence.
+- Not citing sources when using someone else’s material.
+- Posting ‘not safe for work’ content without using the “nsfw” tag.
+- Selling or offering to buy votes/resteems/follows, or schemes that facilitate this.
+- Scams or Fraudulent offers.
+
+^
+## What are Steemit’s policies on plagiarism?
If you are posting plagiarized or copied content, you can get in legal trouble for violating copyright laws. Plagiarized posts and spam are seen as abuse and will be downvoted by community members. If you are posting or using someone else’s content, you must ensure that you have the rights to use the content, and properly reference the sources where you got the material from.
-^
-
-## Is it okay to use random pictures from the internet?
+^
+## Is it okay to use random pictures from the internet?
If you are using an image that is not your own, make sure you are allowed to use the image, and cite the source of the image.
@@ -1039,16 +999,14 @@ Using random pictures from the internet without giving credit is discouraged. Yo
Here is a post from @mindover that has links to many websites that have images you can use:
https://steemit.com/steem-help/@mindover/don-t-plagiarize-images-here-are-13-free-and-legal-ways-to-find-high-quality-photos-you-can-use-on-steemit
-^
-
-## What is Steemcleaners?
+^
+## What is Steemcleaners?
-Steemcleaners are a group of Steemians concerned with plagiarism, copy/paste, spam, scams and other forms of abuse on Steemit.
+Steemcleaners are a group of Steemians concerned with plagiarism, copy/paste, spam, scams and other forms of abuse on Steemit.
https://steemit.com/steemcleaners/@steemcleaners/announcing-steemcleaners-the-steemit-abuse-fighting-team
-^
-
-## What is @cheetah?
+^
+## What is @cheetah?
@cheetah is a bot developed by @anyx that scours Steemit for copy/pasted content. Cheetah will not downvote copied content, but it alerts other users to look into it further.
@@ -1057,27 +1015,24 @@ Abusive accounts (serial plagiarists or identity thieves, for example) will go o
More information on the @cheetah bot can be found in this post:
https://steemit.com/steemit/@cheetah/faq-about-cheetah
-^
-
-## Where do I report a post or comment that contains plagiarism, spam, or abuse?
+^
+##
-You can report any abusive content to the #steemitabuse channel on steemit.chat .
+You can report any abusive content to the #steemitabuse channel on steem.chat .
-^
+^
# Reputation
-
-## What is Reputation?
+## What is Reputation?
-Every user has a reputation score next to their name. The reputation score is one way Steemit measures the amount of value you have brought to the community. It is also a mechanism that is designed to help reduce abuse of the Steemit platform.
+Every user has a reputation score next to their name. The reputation score is one way Steemit measures the amount of value you have brought to the community. It is also a mechanism that is designed to help reduce abuse of the Steemit platform.
Your reputation goes up when accounts vote on your content. Getting downvoted by someone with a higher reputation can push your reputation down and make your posts less visible.
Users with a lower reputation score are unable to affect your reputation.
-^
-
-## How is the Reputation score measured?
+^
+## How is the Reputation score measured?
Every new user starts off with a reputation score of 25.
@@ -1086,24 +1041,21 @@ The reputation score is based off of a `log10` system, which means that a score
More information about the calculation of the reputation score can be found in this post from @digitalnotvir:
https://steemit.com/steemit/@digitalnotvir/how-reputation-scores-are-calculated-the-details-explained-with-simple-math
-^
-
-## How do I improve my reputation score?
+^
+## How do I improve my reputation score?
-Every time another user upvotes one of your posts or comments, it increases your reputation score. Users with a higher reputation than you will have more of a positive effect. The more STEEM Power that the voter has, the larger the effect is as well. The best way to earn upvotes is by adding value to the Steemit community.
+Every time another user upvotes one of your posts or comments, it increases your reputation score. Users with a higher reputation than you will have more of a positive effect. The more Steem Power that the voter has, the larger the effect is as well. The best way to earn upvotes is by adding value to the Steemit community.
-^
-
-## What causes my reputation score to go down?
+^
+## What causes my reputation score to go down?
The only way for your reputation score to go down is to be downvoted by another user. Not all downvotes will cause a reputation loss though.
-- Downvotes from users with a lower reputation score than you will not hurt your score.
+- Downvotes from users with a lower reputation score than you will not hurt your score.
- If your post or comment that was downvoted still received more upvotes than downvotes (weighted by SP), then the net effect on your reputation score will still be positive.
-^
-
-## Why does my reputation score matter?
+^
+## Why does my reputation score matter?
A reputation score is one way Steemit measures the amount of value you have brought to the community. In real estate, they say there are three variables of the utmost importance: location, location, location. On Steemit, those things are: reputation, reputation, reputation. It’s not to say other variables aren’t important, but reputation will be an enormous factor in your level of success.
@@ -1111,53 +1063,64 @@ Many Steemians glance at users’ reputation scores when deciding which articles
It is worth noting that if your reputation score goes below 0, Steemit will hide your posts and comments making it very difficult to gain monetary rewards and followers. This incentivizes online etiquette and respect for your fellow Steemians.
-^
+^
# Followers, Feeds, and Resteem
-
-## What is Resteeming?
+## What is Resteeming?
This is like reblogging or sharing posts on other platforms. Once you resteem a post it will appear in your feed and in your followers' feeds as if you had posted it yourself. Use it conservatively and with caution. It is great to want to share content you like and appreciate with people you follow, but you don't want to overwhelm your followers either.
-^
-
-## Can I share on other social media?
+^
+## Can I share on other social media?
Yes you can use the share button to share on Facebook, Twitter or LinkedIn. You are welcome to post your Steemit links on other websites and social media sites.
-^
+^
# Blockchain
-
-## What is a blockchain?
+## What is a blockchain?
A blockchain is a public ledger of all transactions ever executed. All of the transactions and data are stored in a distributed database. Each time the database is updated, all of updates are done together in a batch called a 'block'. Each time a new block is produced/added, it is appended on to all of the previous blocks - hence the name "blockchain".
-^
-
-## What is the Steem blockchain?
+^
+## What is the Steem blockchain?
The Steem blockchain is the publicly accessible distributed database, which records all posts and votes, and distributes the rewards across the network. It is where all of the text content and voting data is stored, and it is where all of the reward calculations and payouts are performed.
-^
-
-## What is the difference between Steem and Steemit?
+^
+## How does bandwidth work on the Steem blockchain?
+
+Since transacting on the Steem blockchain has zero fees, bandwidth rate-limiting is employed to safeguard the blockchain from spam attacks. Everything action that you take on the blockchain will consume a small amount of bandwidth. This includes posting, commenting, voting, transferring tokens, etc. Viewing content does not consume bandwidth.
+
+Every user has a limited amount of bandwidth to use each week. The more transactions a user does, the less bandwidth they will have left (until it recharges). Users with more Steem Power will have a higher bandwidth allowance.
+
+Normally everyone's bandwidth allowance is quite high, and users are able to use the network freely without any interruptions. Sometimes when the blockchain becomes busy however (due to heavy use), everyone's individual allowances may go down until the network becomes less busy.
+
+You can check how much bandwidth you currently have based on the current limit at:
+https://steemd.com/@youraccount
+
+If users are below their bandwidth limit, they will be unable to transact with the blockchain until their bandwidth recharges or their limit is raised.
+
+If you get an error that you have exceeded your bandwidth allowance, it is normally best to just wait and try again later (when it is less busy). Usually if you wait and try again later, the transaction will likley go through.
+
+If you are unable to transact for extended periods of time, or you are frequently running into bandwidth limits, then you will either need to reduce your usage to stay within your limit, or purchase more Steem Power for your account through a third-party exchange such as [BlockTrades](https://blocktrades.us/?input_coin_type=eth&output_coin_type=steem_power&receive_address=).
+
+^
+## What is the difference between Steem and Steemit?
Steem is the name of the blockchain that stores all of the data and transactions, and processes all of the events that take place. STEEM is also a name for the system’s value token (currency).
-Steemit is a front end web interface to interact with the blockchain, and view the blockchain data.
+Steemit is a front end web interface to interact with the blockchain, and view the blockchain data. Steemit, Inc. is also the name of the company that owns and operates the website steemit.com.
-^
-
-## How is Steem different from Bitcoin?
+^
+## How is Steem different from Bitcoin?
-On a technical level, the two networks rely on the same model of a blockchain, but are built upon different technologies and codebase. Steem is based on a new state-of-the-art blockchain technology called Graphene, which uses "witnesses" instead of "miners" to produce blocks.
+On a technical level, the two networks rely on the same model of a blockchain, but are built upon different technologies and codebase. Steem is based on a new state-of-the-art blockchain technology called Graphene, which uses "witnesses" instead of "miners" to produce blocks.
-The "delegated proof of stake" model of using witnesses instead of miners allows for greater efficiency in block production. With BTC, 100% of the new coins that are created are allocated to block producers (miners). With the Steem blockchain, only 10% of the new coins are paid to block producers (witnesses). The other 90% of new STEEM coins are awarded to content producers, curators, and STEEM Power holders.
+The "delegated proof of stake" model of using witnesses instead of miners allows for greater efficiency in block production. With BTC, 100% of the new coins that are created are allocated to block producers (miners). With the Steem blockchain, only 10% of the new coins are paid to block producers (witnesses). The other 90% of new STEEM coins are awarded to content producers, curators, and Steem Power holders.
-^
-
-## What is the difference between Proof of Work, Proof of Stake, and Delegated Proof of Stake?
+^
+## What is the difference between Proof of Work, Proof of Stake, and Delegated Proof of Stake?
**Proof of work** - Miners solve a complex mathematical problem. The miner that solves the problem first adds the block to the blockchain. The network rewards the miner for doing so.
@@ -1165,83 +1128,75 @@ The "delegated proof of stake" model of using witnesses instead of miners allows
**Delegated proof of stake** - Block-creating accounts, called witnesses, are collectively approved by Steem stakeholders. Instead of relying on proof of work to find blocks, the Steem network actively schedules these accounts to improve the time between blocks to 3 seconds.
-^
-
-## How often does the Steem blockchain produce a new block?
+^
+## How often does the Steem blockchain produce a new block?
The Steem blockchain schedules witnesses to produce a new block every 3 seconds. 21 witness nodes produce 21 blocks in each 63-second round.
-^
-
-## Is there a way to see the raw data that is stored in the blockchain?
+^
+## Is there a way to see the raw data that is stored in the blockchain?
Yes. The blockchain data can be viewed in different ways with third-party tools such as steemd.com and steemdb.com .
-^
-
-## Where can I find the information for the official launch of the blockchain?
+^
+## Where can I find the information for the official launch of the blockchain?
The original launch of Steem was on March 23, 2016, announced on Bitcointalk.org . There was a bug found in the original code though, and a majority of the stakeholders agreed that it would be easier to fix via a re-launch than a hardfork. The blockchain was reset and officially re-launched on March 24, 2016, via Bitcointalk.org .
-^
-
-## Can I mine STEEM?
+^
+## Can I mine STEEM?
No. Proof of work mining has been removed from Steem.
-^
+^
# Steemit, Inc.
-
-## Who is the CEO of Steemit?
+## Who is the CEO of Steemit?
Ned Scott, @ned
https://www.linkedin.com/in/nedscott
-^
-
-## Can I invest in Steemit?
+^
+## Can I invest in Steemit?
Steemit, Inc. is a privately held company and is not available for public investment.
-Though not considered an investment, you can purchase STEEM tokens which can go up or down in value. You can power up these tokens into STEEM Power, which grants more influence in the Steem platform.
+Though not considered an investment, you can purchase STEEM tokens which can go up or down in value. You can power up these tokens into Steem Power, which grants more influence in the Steem platform.
-^
-
-## What does Steemit’s development roadmap look like?
+^
+## What does Steemit’s development roadmap look like?
You can view the 2017 Roadmap here:
https://steemit.com/steemit/@steemitblog/steemit-2017-roadmap
-^
-
-## Am I allowed to use the Steemit logo?
+^
+## Am I allowed to use the Steem and Steemit logos?
+
+The Steemit brand and logo are protected by intellectual property laws, including copyright and other proprietary rights of the United States and other countries. The purpose is to allow Steemit to protect the brand and logo in ways that extend user safety. One may not make unauthorized commercial use of, reproduce, prepare derivative works, distribute copies, perform, or publicly display the Steemit logo or brand, except as permitted by the doctrine of fair use, or as authorized in writing by us.
+
+[Section 107 of the Copyright Act](http://www.copyright.gov/title17/92chap1.html#107) provides the statutory framework for determining whether something is a fair use and identifies certain types of uses—such as criticism, comment, news reporting, teaching, scholarship, and research—as examples of activities that may qualify as fair use. **Steemit considers artistic variations of the Steemit logo that are used for non-commercial purposes, and are not used to harm Steemit users (i.e. through attraction to phishing sites), an instance of fair use.**
-Currently, the Steem and Steemit logos are the same and is free to use. In the future, Steemit, Inc. will have its own logo so that it can be distinguished from Steem. The Steemit logo will be proprietary while Steem and its three S-shaped squiggles will remain open for public use.
+The blue Steem logo with the three S-shaped squiggles is licensed under Creative Commons CC0, meaning you’re free to copy, modify, or distribute (even for commercial purposes) without needing to ask permission or give attribution.
-^
-
-## Can I purchase official Steemit merchandise?
+^
+## Can I purchase official Steemit merchandise?
Yes. Official Steemit merchandise can be purchased from [The Steemit Shop](https://thesteemitshop.com/).
-^
-
-## Did Steemit "pre-mine" tokens?
+^
+## Did Steemit "pre-mine" tokens?
The STEEM tokens mined by Steemit, Inc. were not "pre-mined". All mining took place after the coin was officially and publicly announced on Bitcointalk.org .
-^
-
-## What is the Steemit Privacy Policy?
+^
+## What is the Steemit Privacy Policy?
https://steemit.com/privacy.html
-^
+^
# Security
-
-## How can I keep my Steem account secure?
+## How can I keep my Steem account secure?
Save your master password and keep it somewhere safe.
@@ -1254,175 +1209,151 @@ Again, save your master password and keep it safe! If logging in with you
It is not recommended to share your password or keys with any third party site. Steemit Inc. is developing a login application that can be used on third party Steem front ends.
-^
-
-## Why should I be careful with my master password?
+^
+## Why should I be careful with my master password?
-The master password is used to derive all keys for your account, including the owner key.
+The master password is used to derive all keys for your account, including the owner key. If someone has access to your master password, they can steal your account and all of the tokens in it.
-^
-
-## Why is the master password a long string of gibberish?
+^
+## Why is the master password a long string of gibberish?
The password has to be long and random for maximum account security.
-^
-
-## What are my different keys for?
+^
+## What are my different keys for?
**Posting key** - The posting key allows accounts to post, comment, edit, vote, resteem, and follow or mute other accounts. Most users should be logging into Steemit every day with the posting key. You are more likely to have your password or key compromised the more you use it so a limited posting key exists to restrict the damage that a compromised account key would cause.
-**Active key** - The active key is meant for more sensitive tasks such as transferring funds, power up/down transactions, converting Steem Dollars, voting for witnesses, updating profile details and avatar, and placing a market order.
+**Active key** - The active key is meant for more sensitive tasks such as transferring funds, power up/down transactions, converting Steem Dollars, voting for witnesses, updating profile details and avatar, and placing a market order.
**Memo key** - Currently the memo key is not used.
**Owner key** - The owner key is only meant for use when necessary. It is the most powerful key because it can change any key of an account, including the owner key. Ideally it is meant to be stored offline, and only used to recover a compromised account.
-^
-
-## What do I do if I lost my password/keys?
+^
+## What do I do if I lost my password/keys?
There is no way to recover your account if you lose your password or owner key! Because your account has real value, it is **very important** that you save your master password somewhere safe where you will not lose it.
It is strongly recommended that you store an offline copy of your password somewhere safe in case of a hard drive failure or other calamity. Consider digital offline storage, such as an external disk or flash drive, as well as printed paper. Use a safe deposit box for best redundancy.
-^
-
-## Are my STEEM and Steem Dollar tokens insured in the event of a hack or if someone takes over my account?
+^
+## Are my STEEM and Steem Dollar tokens insured in the event of a hack or if someone takes over my account?
-No, liquid tokens can not be taken back if stolen or sent to the wrong account. If your tokens are in STEEM Power, it is impossible for a hacker to take out more than 1/13 per week. If your tokens are in savings, there is a three-day wait period for them to become transferable.
+No, liquid tokens can not be taken back if stolen or sent to the wrong account. If your tokens are in Steem Power, it is impossible for a hacker to take out more than 1/13 per week. If your tokens are in savings, there is a three-day wait period for them to become transferable.
-^
-
-## What should I do if I discover that someone hacked my account?
+^
+## What should I do if I discover that someone hacked my account?
If you made your account through Steemit and it is compromised, immediately visit the Stolen Account Recovery page. This link is also available in the main site menu. You will need to provide the email address that you used when you signed up, your account name, and a master password that was used in the last 30 days.
-^
-
-## How does the stolen account recovery process work?
+^
+## How does the stolen account recovery process work?
If your password has been changed without your consent, then the account designated as your recovery account can generate a new owner key for the account. The account recovery must be completed within 30 days of the password being changed, and you must supply a recent owner key that was valid within the last 30 days.
-Steemit Inc. owns the default recovery account (@steem) for all users who sign up using Steemit.com. Steemit can identify users by their original email, Facebook, or Reddit logins that were used to signup via Steemit.com.
+Steemit Inc. owns the default recovery account (@steem) for all users who sign up using steemit.com. Steemit can only identify users by their original email, Facebook, or Reddit logins that were used to signup via steemit.com.
If you don't have the master password or owner key that was valid the past 30 days, or are unable to prove that you are the original owner of the account, then your account will be unrecoverable.
-^
-
-## How do I report a security vulnerability?
+^
+## How do I report a security vulnerability?
If you find a security issue please report the details to security@steemit.com.
-^
+^
# Developers
-
-## Are the Steem blockchain and Steemit.com code open-source?
+## Are the Steem blockchain and steemit.com code open-source?
-Yes. Both the Steem blockchain and Steemit.com are open-source projects.
+Yes. Both the Steem blockchain and steemit.com are open-source projects.
-Developers should however avoid the use of the term "Steemit" in their own products, and instead refer to the Steem Blockchain or Steem Platform. Steemit refers to Steemit.com, which is owned by Steemit, Inc.
+Developers should however avoid the use of the term "Steemit" in their own products, and instead refer to the Steem Blockchain or Steem Platform. Steemit refers to steemit.com, which is owned by Steemit, Inc.
-^
-
-## Is there a Github page for Steemit.com?
+^
+## Is there a Github page for steemit.com?
https://github.com/steemit/condenser
-^
-
-## Is there a Github page for the Steem blockchain?
+^
+## Is there a Github page for the Steem blockchain?
https://github.com/steemit/steem
-^
-
-## What is available for developers interested in Steem and Steemit?
+^
+## What is available for developers interested in Steem and Steemit?
Many software engineers are currently leveraging the open-source code to build their applications on Steem. There are more than sixty so far.
This post from the user @fabien has more information about the Steem API:
https://steemit.com/steemjs/@fabien/steem-api-now-released
-^
-
-## How do I use cli_wallet?
+The [Steem Developer Portal](https://developers.steem.io/) also contains documents and resources for developing tools and applications for the Steem blockchain.
+
+^
+## How do I use cli_wallet?
Here is a guide from the user @pfunk explaining how to use the cli_wallet:
https://steemit.com/steemhelp/@pfunk/a-learner-s-guide-to-using-steem-s-cliwallet-part-1
-^
+^
# Witnesses
-
-## What are Steem witnesses?
-
-The Steem blockchain requires a set of people to create blocks and uses a consensus mechanism called delegated proof of stake, or DPOS. The community elects 'witnesses' to act as the network's block producers and governance body. There are 20 full-time witnesses, producing a block every 63-second round. A 21st position is shared by backup witnesses, who are scheduled proportionally to the amount of stake-weighted community approval they have. Witnesses are compensated with STEEM Power for each block they create.
+## What are Steem witnesses?
-Steemit leverages Steem because the founders of Steemit believe Steem’s decentralized text content storage and governance model makes Steem an excellent platform for supporting the long term success of its social network and digital currency tokens.
+The Steem blockchain requires a set of people to create blocks and uses a consensus mechanism called delegated proof of stake, or DPOS. The community elects 'witnesses' to act as the network's block producers and governance body. There are 20 full-time witnesses, producing a block every 63-second round. A 21st position is shared by the backup witnesses, who are scheduled proportionally to the amount of stake-weighted community approval they have. Witnesses are compensated with Steem Power for each block they create.
-^
-
-## How can I vote for witnesses?
+^
+## How can I vote for witnesses?
-Visit https://steemit.com/~witnesses
+Visit https://steemit.com/~witnesses.
-^
-
-## How many witnesses can I vote for?
+^
+## How many witnesses can I vote for?
Each account can vote for up to 30 witnesses.
-^
+^
# Miscellaneous
-
-## What third-party tools are there for Steemit?
+## What third-party tools are there for Steemit?
http://steemtools.com/
-^
-
-## Is there an official Steemit Facebook page?
+^
+## Is there an official Steemit Facebook page?
https://www.facebook.com/steemit/
-^
-
-## Is there an official Steemit Twitter account?
+^
+##
https://twitter.com/steemit
-^
-
-## What is the Steem Whitepaper and what is its purpose?
+^
+## What is the Steem Whitepaper and what is its purpose?
The Steem Whitepaper was written to describe the mechanics of the token system that makes decentralized content incentives and distribution possible in a way that can improve web technologies across the board. It is also applicable to Steemit, the first website to plug into the Steem blockchain. Users who have read the Steem Whitepaper will better understand how their interactions with Steemit are interactions with Steem, the decentralized network.
-It is worth noting that the Whitepaper hasn’t been updated almost since Steem came into existence. Many changes have been made since then, so much of the Whitepaper is now out of date. It is in the process of being rewritten.
-
https://steem.io/SteemWhitePaper.pdf
-^
-
-## Where can I ask for help if my question was not answered here?
+^
+## Where can I ask for help if my question was not answered here?
+
+If you post your question in the #help channel on steem.chat , the users there may be able to help.
-If you post your question in the #help channel on steemit.chat , the users there may be able to help.
+You can also create a post on steemit.com with the tag #help, and someone in the community may be able to answer it.
-You can also create a post on Steemit.com with the tag #help, and someone in the community may be able to answer it.
+^
-^
-
-# Disclaimer
+# Disclaimer
-
-## Third Party References and User Links
+## Third Party References and User Links
-BlockTrades, Poloniex, Bittrex, Changelly, Shapeshift.io, Coinbase, Localbitcoins, SteemDB, PeerHub, Steemit.chat, SteemTools, AnonSteem, SteemConnect, Streemian, SteemStats, Pixabay, Steemcleaners, Pexels, Postimage, Markdown Cheatsheet, @cheetah, Bitcointalk, bitcoinfees, blockchain.info, and steemd are third party applications/services, and are not owned or maintained by Steemit, Inc. Their listing here, as well as any other third party applications or websites that are listed, does not constitute and endorsement or recommendation on behalf of Steemit, Inc.
+AnonSteem, Binance, bitcoinfees, Bitcointalk, BitShares, Bittrex, blockchain.info, BlockTrades, Busy.org, Changelly, @cheetah, Coinbase, DTube, GOPAX, HitBTC, Localbitcoins, Markdown Cheatsheet, Pexels, Pixabay, Poloniex, Postimage, Shapeshift.io, Steemcleaners, SteemConnect, SteemCreate, steemd, SteemDB, steem.chat, SteemStats, SteemTools, Streemian, The Steemit Shop, UpBit, and Utopian.io are third party applications/services, and are not owned or maintained by Steemit, Inc. Their listing here, as well as any other third party applications or websites that are listed, does not constitute and endorsement or recommendation on behalf of Steemit, Inc.
All links to user posts were created by our users and do not necessarily represent the views of Steemit, Inc. or its management. Their listing here does not constitute and endorsement or recommendation on behalf of Steemit, Inc.
Please use the third party tools and content at your own risk.
-^
+^
diff --git a/src/app/help/en/tos.md b/src/app/help/en/tos.md
new file mode 100644
index 0000000000000000000000000000000000000000..cbac3bd637b448a3807ab1a235d79a964b4bd193
--- /dev/null
+++ b/src/app/help/en/tos.md
@@ -0,0 +1,607 @@
+Last Updated February 5, 2018.
+
+Welcome to Steemit! These Terms of Service (“Terms”) apply to your access to
+and use of Steemit.com and any other products or services that link to these
+Terms (the “Service”). Steemit is provided by Steemit, Inc. (“Steemit”, the
+"Company", “we” or “us”). By accessing or using Steemit, you agree to be bound
+by these Terms. If you do not agree to these Terms, including the mandatory
+arbitration provision and class action waiver in Section 23, do not access or
+use the Service. If we make changes to these Terms, we will provide notice of
+those changes by updating the “Last Updated” date above or posting notice on
+Steemit. Your continued use of Steemit will confirm your acceptance of the
+changes.
+
+## 1. Privacy Policy
+
+Please refer to our [Privacy Policy](/privacy.html) for
+information about how we collect, use, and disclose information about you.
+
+## 2. Eligibility
+
+Steemit is not targeted toward, nor intended for use by, anyone under the age
+of 13. You must be at least 13 years of age to access or use Steemit. If you
+are between 13 and 18 years of age (or the age of legal majority where you
+reside), you may only access or use Steemit under the supervision of a parent
+or legal guardian who agrees to be bound by these Terms.
+
+## 3. Copyright and Limited License
+
+We may retain data, text, photographs, images, video, audio, graphics,
+articles, comments, software, code, scripts and other content supplied by us,
+the Steem blockchain or our licensors, which we call “Steemit Content.” Steemit
+Content is protected by intellectual property laws, including copyright and
+other proprietary rights of the United States and foreign countries. Except as
+explicitly stated in these Terms, we do not grant any express or implied rights
+to use Steemit Content.
+
+You are granted a limited, non-exclusive, non-transferable, and
+non-sublicensable license to access and use Steemit and Steemit Content for
+your personal use. You retain ownership of and responsibility for Content you
+create or own ("Your Content"). If you're posting anything you did not create
+yourself or do not own the rights to, you agree that you are responsible for
+any Content you post; that you will only submit Content that you have the right
+to post; and that you will fully comply with any third party licenses relating
+to Content you post.
+
+## 4. Adult-Oriented Content
+
+Steemit is intended for a general audience and, as a result, some Steemit
+Content may discuss or depict adult-oriented topics. We realize that this
+content may not be appropriate or desirable for some of our readers depending
+on their current location, age, background, or personal views. As a result, we
+will attempt to label this content as Not Safe For Work ("NSFW").
+
+Marking Steemit Content as NSFW does not prevent you from being able to access
+this content but, instead, helps you make informed decisions about the type of
+content you view on Steemit.
+
+## 5. Trademarks
+
+"Steem", "Steemit", "SMTs", the Steemit logo and any other product or service
+names, logos or slogans that may appear on Steemit are trademarks of the
+Company and may not be copied, imitated or used, in whole or in part, without
+our prior written permission. You may not use any metatags or other “hidden
+text” utilizing “Steemit” or any other name, trademark or product or service
+name of Steemit without our prior written permission. In addition, the look and
+feel of Steemit, including, without limitation, all page headers, custom
+graphics, button icons and scripts, constitute the service mark, trademark or
+trade dress of Steemit and may not be copied, imitated or used, in whole or in
+part, without our prior written permission. All other trademarks, registered
+trademarks, product names and company names or logos mentioned or used on
+Steemit are the property of their respective owners and may not be copied,
+imitated or used, in whole or in part, without the permission of the applicable
+trademark holder. Reference to any products, services, processes or other
+information by name, trademark, manufacturer, supplier or otherwise does not
+constitute or imply endorsement, sponsorship, or recommendation by the Company.
+
+## 6. Assumption of Risk, Limitations on Liability.
+
+6.1. You accept and acknowledge that there are risks associated with
+utilizing an Internet-based STEEM account service including, but not limited
+to, the risk of failure of hardware, software and Internet connections, the
+risk of malicious software introduction, and the risk that third-parties may
+obtain unauthorized access to information stored within or associated with your
+Account, including, but not limited to your Private Key or Keys (as defined
+below at 10.2.). You accept and acknowledge that we will not be responsible for
+any communication failures, disruptions, errors, distortions, or delays you may
+experience when using the Services, however caused.
+
+6.2. We make no representation or warranty of any kind, express or implied,
+statutory, or otherwise, regarding the contents of the Service, information and
+functions made accessible through the Service, any hyperlinks to third party
+websites, nor for any breach of security associated with the transmission of
+information through the Service or any website linked to by the Service.
+
+6.3. We will not be responsible or liable to you for any loss and take no
+responsibility for and will not be liable to you for any use of our Services,
+including but not limited to any losses, damages or claims arising from: (a)
+User error such as forgotten passwords, incorrectly constructed transactions,
+or mistyped STEEM addresses; (b) Server failure or data loss; (c) Corrupted
+Account files; (d) Unauthorized access to applications; (e) Any unauthorized
+third party activities, including without limitation the use of viruses,
+phishing, brute forcing or other means of attack against the Service or
+Services.
+
+6.4. We make no warranty that the Service or the server that makes it
+available, are free of viruses or errors, that its content is accurate, that it
+will be uninterrupted, or that defects will be corrected. We will not be
+responsible or liable to you for any loss of any kind, from action taken, or
+taken in reliance on material, or information, contained on the Service.
+
+6.5. Subject to 7.1 below, any and all indemnities, warranties, terms and
+conditions (whether express or implied) are hereby excluded to the fullest
+extent permitted under New York law.
+
+6.6. We will not be liable, in contract, or tort (including, without
+limitation, negligence), other than where we have been fraudulent or made
+negligent misrepresentations.
+
+6.7. Nothing in these Terms excludes or limits liability for death or personal
+injury caused by negligence, fraudulent misrepresentation, or any other
+liability which may not otherwise be limited or excluded under United States
+law.
+
+## 7. Agreement to Hold Steemit Harmless
+
+7.1. You agree to hold harmless Steemit (and each of our officers, directors,
+members, employees, agents and affiliates) from any claim, demand, action,
+damage, loss, cost or expense, including without limitation reasonable legal
+fees, arising out or relating to:
+
+7.1.1. Your use of, or conduct in connection with, our Services;
+
+7.1.2. Any feedback or submissions you provide (see 17 below);
+
+7.1.3. Your violation of these Terms; or
+
+7.1.4. Violation of any rights of any other person or entity.
+
+7.2. If you are obligated to indemnify us, we will have the right, in our sole
+discretion, to control any action or proceeding (at our expense) and determine
+whether we will pursue a settlement of any action or proceeding.
+
+## 8. No Liability For Third-Party Services And Content
+
+8.1. In using our Services, you may view content or utilize services provided
+by third parties, including links to web pages and services of such parties
+(“Third-Party Content”). We do not control, endorse or adopt any Third-Party
+Content and will have no responsibility for Third-Party Content including,
+without limitation, material that may be misleading, incomplete, erroneous,
+offensive, indecent or otherwise objectionable in your jurisdiction. In
+addition, your dealings or correspondence with such third parties are solely
+between you and the third parties. We are not responsible or liable for any
+loss or damage of any sort incurred as a result of any such dealings and you
+understand that your use of Third-Party Content, and your interactions with
+third parties, is at your own risk.
+
+## 9. Account Registration
+
+9.1. You need not use a Steemit Account. If you wish to use an Account, you
+must create a Steem Blockchain account to access the Services (“Account”). When
+you create an Account, you are strongly advised to take the following
+precautions, as failure to do so may result in loss of access to, and/or
+control over, your Account: (a) Create a strong password that you do not use
+for any other website or online service; (b) Provide accurate and truthful
+information; (c) Maintain and promptly update your Account information; (d)
+maintain the security of your Account by protecting your Account password and
+access to your computer and your Account; (e) Promptly notify us if you
+discover or otherwise suspect any security breaches related to your Account.
+
+9.2. You hereby accept and acknowledge that you take responsibility for all
+activities that occur under your Account and accept all risks of any authorized
+or unauthorized access to your Account, to the maximum extent permitted by law.
+
+## 10. The Steemit Services
+
+10.1. As described in more detail below, the Services, among other things,
+provide in software that facilitates the submission of STEEM transaction data
+to the Steem Network without requiring you to access the STEEM command line
+interface.
+
+10.2. Account Names and Private Keys. If you create an Account through Steemit,
+the Services generate and store a cryptographic private and public key pair
+that you may use to send and receive STEEM and Steem Dollars via the Steem
+Network, provided however, that you may create an account to the Steem
+blockchain outside the bounds of the Steemit. The Private Key or Keys uniquely
+match the Account Name and must be used in connection with the Account Name to
+authorize the transfer of STEEM and Steem Dollars from that Account. You are
+solely responsible for maintaining the security of your Private Keys and any
+password phrase associated with your Account. You must keep your Account,
+password phrase and Private Key access information secure. Failure to do so may
+result in the loss of control of Steem, Steem Power and Steem Dollars
+associated with your Account.
+
+10.3. No Password Retrieval. The Company does not receive or store your Account
+password, nor your Private Keys. Therefore, we cannot assist you with Account
+password retrieval, reset, or recovery. You are solely responsible for
+remembering your Account password. If you have not safely stored a backup of
+any Account Names and password pairs maintained in your Account, you accept and
+acknowledge that any STEEM, Steem Dollars and Steem Power you have associated
+with such Account will become permanently inaccessible if you do not have your
+Account password.
+
+10.4. Transactions. In order to be completed, all proposed Steem transactions
+must be confirmed and recorded in the Steem public ledger via the Steem
+distributed consensus network (a peer-to-peer economic network that operates on
+a cryptographic protocol), which is not owned, controlled or operated by the
+Company. The Steem Network is operated by a decentralized network of
+independent third parties. The Company has no control over the Steem Network
+and therefore cannot and does not ensure that any transaction details you
+submit via the Services will be confirmed via the Steem Network. You
+acknowledge and agree that the transaction details you submit via the Services
+may not be completed, or may be substantially delayed, by the Steem Network.
+You may use the Services to submit these details to the network.
+
+10.5. No Storage or Transmission of STEEM, Steem Dollars or Steem Power.
+Steem, in any of its forms (STEEM, Steem Dollars and Steem Power) is an
+intangible, digital asset. They exist only by virtue of the ownership record
+maintained in the Steem Network. The Service does not store, send or receive
+Steem. Any transfer of title that might occur in any STEEM, Steem Dollars or
+Steem Power occurs on the decentralized ledger within the Steem Network and not
+within the Services. We do not guarantee that the Service can affect the
+transfer of title or right in any Steem, Steem Dollars or Steem Power.
+
+10.6. Relationship. Nothing in these Terms is intended to nor shall create any
+partnership, joint venture, agency, consultancy or trusteeship, you and the
+Company being with respect to one another independent contractors.
+
+10.7. Accuracy of Information. You represent and warrant that any information
+you provide via the Services is accurate and complete. You accept and
+acknowledge that the Company is not responsible for any errors or omissions
+that you make in connection with any Steem transaction initiated via the
+Services, for instance, if you mistype an Account Name or otherwise provide
+incorrect information. We strongly encourage you to review your transaction
+details carefully before completing them via the Services.
+
+10.8. No Cancellations or Modifications. Once transaction details have been
+submitted to the Steem Network via the Services, The Services cannot assist you
+to cancel or otherwise modify your transaction details. The Company has no
+control over the Steem Network and does not have the ability to facilitate any
+cancellation or modification requests.
+
+10.9. Taxes. It is your responsibility to determine what, if any, taxes apply
+to the transactions you for which you have submitted transaction details via
+the Services, and it is your responsibility to report and remit the correct tax
+to the appropriate tax authority. You agree that the Company is not responsible
+for determining whether taxes apply to your Steem transactions or for
+collecting, reporting, withholding or remitting any taxes arising from any
+Steem transactions.
+
+## 11. Fees for Using the Steemit Services
+
+11.1. Company Fees Creating an Account. The Company does not currently charge
+fees for any Services, however we reserve the right to do so in future, and in
+such case any applicable fees will be displayed prior to you using any Service
+to which a fee applies.
+
+## 12. No Right To Cancel And/Or Reverse Steem Transactions
+
+12.1. If you use a Service to which Steem, Steem Dollars or Steem Power is
+transacted, you will not be able to change your mind once you have confirmed
+that you wish to proceed with the Service or transaction.
+
+## 13. Discontinuation of Services.
+
+13.1. We may, in our sole discretion and without cost to you, with or without
+prior notice and at any time, modify or discontinue, temporarily or
+permanently, any portion of our Services. You are solely responsible for
+storing, outside of the Services, a backup of any Account and Private Key pair
+that you maintain in your Account.
+
+13.2. If you do not maintain a backup of your Account data outside of the
+Services, you will be may not be able to access Steem, Steem Dollars and Steem
+Power associated with any Account Name maintained in your Account in the event
+that we discontinue or deprecate the Services.
+
+## 14. Suspension or Termination of Service.
+
+14.1. We may suspend or terminate your access to the Services in our sole
+discretion, immediately and without prior notice, and delete or deactivate your
+Account and all related information and files in such without cost to you,
+including, for instance, in the event that you breach any term of these Terms.
+In the event of termination, your access to funds will depend on your access to
+your backup of your Account data including your Account Name and Private Keys.
+
+## 15. User Conduct
+
+15.1. When accessing or using the Services, you agree that you will not commit
+any unlawful act, and that you are solely responsible for your conduct while
+using our Services. Without limiting the generality of the foregoing, you agree
+that you will not:
+
+15.1.1. Use of our Services in any manner that could interfere with, disrupt,
+negatively affect or inhibit other users from fully enjoying our Services, or
+that could damage, disable, overburden or impair the functioning of our
+Services in any manner;
+
+15.1.2. Use our Services to pay for, support or otherwise engage in any
+activity prohibited by law, including, but not limited to illegal gambling,
+fraud, money-laundering, or terrorist financing activities.
+
+15.1.3. Use or attempt to use another user’s Account without authorization;
+
+15.1.4. Attempt to circumvent any content filtering techniques we employ, or
+attempt to access any service or area of our Services that you are not
+authorized to access;
+
+15.1.5. Introduce to the Services any virus, Trojan, worms, logic bombs or
+other harmful material;
+
+15.1.6. Encourage or induce any third party to engage in any of the activities
+prohibited under this Section.
+
+## 16. Third-Party Content and Sites
+
+The Company may include links and other content owned or operated by third
+parties, including advertisements and social “widgets” (we call these
+“Third-Party Content”). You agree that the Company is not responsible or liable
+for Third-Party Content and that you access and use Third-Party Content at your
+own risk. Your interactions with Third-Party Content are solely between you and
+the third party providing the content. When you leave Steemit, you should
+understand that these Terms no longer govern and that the terms and policies of
+those third-party sites or services will then apply.
+
+## 17. Feedback
+
+You may submit questions, comments, feedback, suggestions, and other
+information regarding Steemit (we call this “Feedback”). You acknowledge and
+agree that Feedback is non-confidential and will become the sole property of
+the Company. The Company shall own exclusive rights, including, without
+limitation, all intellectual property rights, in and to such Feedback and is
+entitled to the unrestricted use and dissemination of this Feedback for any
+purpose, without acknowledgment or compensation to you. You agree to execute
+any documentation required by the Company to confirm such assignment to the
+Company.
+
+## 18. Copyright Complaints, the DMCA, and Takedowns
+
+18.1 We will respond to legitimate requests under the Digital Millennium
+Copyright Act ("DMCA"), and we retain the right to remove access to user
+content provided via Steemit that we deem to be infringing the copyright of
+others. If you become aware of user content on Steemit that infringes your
+copyright rights, you may submit a properly formatted DMCA request (see 17
+U.S.C. § 512) to Steemit.
+
+Misrepresentations of infringement can result in liability for monetary
+damages. You may want to consult an attorney before taking any action pursuant
+to the DMCA. A DMCA request can be sent to us via the contact information
+below:
+
+> Copyright Agent
+> Steemit, Inc.
+> 251 Little Falls Drive
+> Wilmington, DE 19808
+
+or
+
+> copyright@steemit.com
+
+Please send our Copyright Agent the following information:
+
+1. The electronic or physical signature of the owner of the copyright or the
+person authorized to act on the owner's behalf;
+
+2. Identification of the copyrighted work claimed to have been infringed, or a
+representative list of such works;
+
+3. The URL or Internet location of the materials claimed to be infringing or
+to be the subject of infringing activity, or information reasonably sufficient
+to permit us to locate the material;
+
+4. Your name, address, telephone number, and email address;
+
+5. A statement by you that you have a good faith belief that the disputed use
+of the material is not authorized by the copyright owner, its agent or the law;
+and
+
+6. A statement by you, made under penalty of perjury, that the above
+information in your notice is accurate and that you are the copyright owner or
+are authorized to act on the copyright owner's behalf.
+
+18.2 Your right to file a counter-notice
+
+If we remove your user content in response to a copyright or trademark notice,
+we will notify you. If you believe your user content was wrongly removed due to
+a mistake or misidentification of the material, you can send a counter-notice
+to our Copyright Agent (contact information provided above) that includes the
+following:
+
+1. Your physical or electronic signature;
+
+2. Identification of the material that has been removed or to which access has
+been disabled and where the material was located online before it was removed
+or access to it was disabled;
+
+3. A statement by you, under penalty of perjury, that you have a good faith
+belief that the material was removed or disabled as a result of mistake or
+misidentification of the material to be removed or disabled; and
+
+4. Your name, address, and telephone number, and a statement that you consent
+to the jurisdiction of federal district court for the judicial district in
+which the address is located, or if your address is outside of the United
+States, for any judicial district in which the service provider may be found,
+and that you will accept service of process from the person who provided
+notification under DMCA 512 subsection (c)(1)(c) or an agent of such person.
+
+Upon receiving a counter-notice we will forward it to the complaining party and
+tell them we will restore your content within 10 business days. If that party
+does not notify us that they have filed an action to enjoin your use of that
+content on Steemit before that period passes, we will consider restoring your
+user content to the site.
+
+It is Steemit's policy to deny use of the Service to users we identify as
+repeat infringers. We apply this policy at our discretion and in appropriate
+circumstances, such as when a user has repeatedly been charged with infringing
+the copyrights or other intellectual property rights of others.
+
+## 19. Indemnity
+
+All the things you do and all the information you submit or post to Steemit
+remain your responsibility. Indemnity is basically a way of saying that you
+will not hold us legally liable for any of your user content or actions that
+infringe the law or the rights of a third party or person in any way.
+
+Specifically, you agree to hold Steemit, its affiliates, officers, directors,
+employees, agents, and third party service providers harmless from and defend
+them against any claims, costs, damages, losses, expenses, and any other
+liabilities, including attorneys’ fees and costs, arising out of or related to
+your access to or use of Steemit, your violation of this user agreement, and/or
+your violation of the rights of any third party or person.
+
+## 20. Disclaimers
+
+To the fullest extent permitted by applicable law, Steemit and the Steemit
+content are provided on an “as is” and “as available” basis, without warranties
+of any kind, either express or implied, including, without limitation, implied
+warranties of merchantability, fitness for a particular purpose, title and
+non-infringement and any warranties implied by any course of performance or
+usage of trade. The company does not represent or warrant that Steemit and the
+Steemit content: (a) will be secure or available at any particular time or
+location; (b) are accurate, complete, reliable, current or error-free or that
+any defects or errors will be corrected; and (c) are free of viruses or other
+harmful components. Your use of Steemit and the Steemit content is solely at
+your own risk. Some jurisdictions do not allow the disclaimer of implied terms
+in contracts with consumers, so some or all of the disclaimers in this section
+may not apply to you.
+
+## 21. Limitation of liability
+
+To the fullest extent permitted by applicable law, in no event shall the
+company or the any related party to the company, that includes but is not
+limited to, subsidiaries, vendors, or contractors, be liable for any special,
+indirect, incidental, consequential, exemplary or punitive damages, or any
+other damages of any kind, including, but not limited to, loss of use, loss of
+profits or loss of data, whether in an action in contract, tort (including, but
+not limited to, negligence) or otherwise, arising out of, or in any way
+connected with, the use of, or inability to use, Steemit or the Steemit
+content. To the fullest extent permitted by applicable law, in no event shall
+the aggregate liability of the company or any related party, whether in
+contract, warranty, tort (including negligence, whether active, passive or
+imputed), product liability, strict liability or other theory, arising out of
+or relating to: (a) the use of or inability to use Steemit or the Steemit
+content; or (b) these terms exceed any compensation you pay, if any, to the
+company for access to or use of Steemit.
+
+Some jurisdictions do not allow the exclusion or limitation of certain damages,
+so some or all of the exclusions and limitations in this section may not apply
+to you.
+
+## 22. Modifications to Steemit
+
+The Company reserves the right to modify or discontinue, temporarily or
+permanently, Steemit, or any features or portions of Steemit, without prior
+notice. You agree that the Company will not be liable for any modification,
+suspension or discontinuance of Steemit, or any part of Steemit.
+
+## 23. Arbitration
+
+Please read the following section carefully because it requires you to
+arbitrate certain disputes with Steemit and limits the manner in which you can
+seek relief from Steemit.
+
+23.1. Binding Arbitration
+
+Except for disputes in which either party seeks to bring an individual action
+in small claims court or seeks injunctive or other equitable relief for the
+alleged unlawful use of copyrights, trademarks, trade names, logos, trade
+secrets or patents, you and the Company: (a) waive your right to have any and
+all disputes or Claims arising from these Terms or the Company (collectively,
+“Disputes”) resolved in a court; and (b) waive your right to a jury trial.
+Instead, you and the Company will arbitrate Disputes through binding
+arbitration (which is the referral of a Dispute to one or more persons charged
+with reviewing the Dispute and making a final and binding determination to
+resolve it, instead of having the Dispute decided by a judge or jury in court).
+
+23.2. No Class Arbitrations, Class Actions or Representative Actions
+
+You and the company agree that any dispute is personal to you and Steemit and
+that any such dispute will be resolved solely through individual arbitration
+and will not be brought as a class arbitration, class action or any other type
+of representative proceeding. Neither party agrees to class arbitration or to
+an arbitration in which an individual attempts to resolve a dispute as a
+representative of another individual or group of individuals. Further, you and
+Steemit agree that a dispute cannot be brought as a class, or other type of
+representative action, whether within or outside of arbitration, or on behalf
+of any other individual or group of individuals.
+
+23.3. Federal Arbitration Act
+
+You and the Company agree that these Terms affect interstate commerce and that
+the enforceability of this Section 14 shall be governed by, construed and
+enforced, both substantively and procedurally, by the Federal Arbitration Act,
+9 U.S.C. § 1 et seq. (the “FAA”) to the maximum extent permitted by applicable
+law.
+
+23.4. Process
+
+You and the Company agree that you will notify each other in writing of any
+Dispute within thirty (30) days of when it arises so that the parties can
+attempt, in good faith, to resolve the Dispute informally. Notice to the
+Company shall be provided by sending an email to legal@steemit.com. Your notice
+must include: (1) your name, postal address, and email address; (2) a
+description of the nature or basis of the Dispute; and (3) the specific relief
+that you are seeking. If you and the Company cannot agree how to resolve the
+Dispute within thirty (30) days of the Company receiving the notice, either you
+or Company may, as appropriate pursuant to this Section 14, commence an
+arbitration proceeding or file a claim in court. You and the Company agree that
+any arbitration or claim must be commenced or filed within one (1) year after
+the Dispute arose; otherwise, you and the Company agree that the claim is
+permanently barred (which means that you will no longer have the right to
+assert a claim regarding the Dispute). You and the Company agree that: (a) any
+arbitration will occur in New York County, New York; (b) arbitration will be
+conducted confidentially by a single arbitrator in accordance with the rules of
+JAMS; and (c) the state or federal courts in New York will have exclusive
+jurisdiction over the enforcement of an arbitration award and over any Dispute
+between the parties that is not subject to arbitration. You may also litigate a
+Dispute in small claims court located in the county where you reside if the
+Dispute meets the requirements to be heard in small claims court.
+
+23.5. Authority of Arbitrator
+
+As limited by the FAA, these Terms and applicable JAMS rules, the arbitrator
+will have: (a) the exclusive authority and jurisdiction to make all procedural
+and substantive decisions regarding a Dispute; and (b) the authority to grant
+any remedy that would otherwise be available in court. The arbitrator may only
+conduct an individual arbitration and may not consolidate more than one
+individual’ s claims, preside over any type of class or representative
+proceeding or preside over any proceeding involving more than one individual.
+
+23.6. Rules of JAMS
+
+The rules of, and additional information about, JAMS are available on the
+JAMS website at http://www.jamsadr.com/, as may be updated from time to
+time. By agreeing to be bound by these Terms, you either: (a) acknowledge
+and agree that you have read and understand the rules of JAMS; or (b) waive
+your opportunity to read the rules of JAMS and any claim that the rules of
+JAMS are unfair or should not apply for any reason.
+
+23.7. Severability
+
+If any term, clause or provision of this Section 14 is held invalid or
+unenforceable, it will be so held to the minimum extent required by law and
+all other terms, clauses or provisions will remain valid and enforceable.
+Further, the waivers set forth in Section 24.2 are severable from the other
+provisions of these Terms and will remain valid and enforceable, except as
+prohibited by applicable law.
+
+## 24. Applicable Law and Venue
+
+These Terms and your access to and use of Steemit and the Steemit Content
+will be governed by, and construed in accordance with, the laws of New
+York, without resort to its conflict of law provisions. To the extent the
+arbitration provision in Section 14 does not apply and the Dispute cannot
+be heard in small claims court, you agree that any action at law or in
+equity arising out of, or relating to, these Terms shall be filed only in
+the state and federal courts located in New York County, New York and you
+hereby irrevocably and unconditionally consent and submit to the exclusive
+jurisdiction of such courts over any suit, action or proceeding arising out
+of these Terms.
+
+## 25. Termination
+
+The Company reserves the right, without notice and in our sole discretion,
+to terminate your license to access and use Steemit and to block or prevent
+your future access to, and use of, Steemit.
+
+## 26. Severability
+
+If any term, clause or provision of these Terms is deemed to be unlawful,
+void or for any reason unenforceable, then that term, clause or provision
+shall be deemed severable from these Terms and shall not affect the
+validity and enforceability of any remaining provisions.
+
+## 27. Changes
+
+This Agreement is the entire agreement between you and us concerning
+Steemit. It supersedes all prior or contemporaneous agreements between you
+and us. We may modify this user agreement at any time. If we make changes
+to this agreement that materially affect your rights, we will provide
+advance notice and keep this edition available as an archive on the Steemit
+website. By continuing to use Steemit after a change to this agreement, you
+agree to those changes.
+
+## 28. Contact Information
+
+DMCA requests to Steemit, Inc should be directed to copyright@steemit.com.
+
+All other notices to Steemit, Inc should be directed to legal@steemit.com.
diff --git a/src/app/help/en/welcome.md b/src/app/help/en/welcome.md
index a94d1fc42be01fc655b137766ef3d2dbfa26a569..4178e4edbfd70e01372b86712aa2b560ede75695 100644
--- a/src/app/help/en/welcome.md
+++ b/src/app/help/en/welcome.md
@@ -1,192 +1,205 @@
+
## Welcome to Steemit!
This page is full of information to help you learn about the platform and become a successful Steemian. You can return to this page at any time by clicking on the "Welcome" link in the main menu. There is a table of contents below to help you navigate the page.
-Included on the page is a "Quick Start Guide" with information on how the platform works, and a "To Do List" with recommended steps to get started with your account.
+Included on the page is a "To Do List" with recommended steps to get started with your account, and a "Quick Start Guide" with information on how the platform works.
Below that is a section of "Helpful Posts from Steemit Users", which contains a collection of posts from users in the community that are helpful for new users getting started.
-Below that is a list of recommended users to follow, a collection of other resources including the FAQ Page , and information on where to find live help.
+Below that is a list of recommended users to follow, a collection of other resources including the FAQ Page and [Steem bluepaper](https://steem.io/steem-bluepaper.pdf), as well as information on where to find live help.
-
-## Table of Contents
+## Table of Contents
+
+### To Do List
+
+1. Backup your password
+2. Review the Quick Start Guide
+3. Read the Helpful Posts from Steemit Users
+4. Setup your Profile, Avatar, and Cover Image
+5. Choose your "NSFW" (Not Safe for Work) Display Preference
+6. Sign Up for Steem Chat
+7. Create your "introduceyourself" post
+8. Learn more
### Quick Start Guide
-- No Cost to Participate
-- Upvotes
-- Comments
-- Creating Posts
-- Tags
-- Followers and Feeds
-- Resteem
-- Digital Currencies
-- Curation
-- Payments
-- Home, New, Hot, Trending, Promoted, and Active
-- Profile
-- Reputation
-- Cashing out or Spending SBD
-- Plagiarism
-- Password Security
-- Earning on Steemit
+- No Cost to Participate
+- Upvotes
+- Comments
+- Creating Posts
+- Followers and Feeds
+- Resteem
+- Digital Currencies
+- Curation
+- Payments
+- Reputation
+- Cashing out or Spending SBD
+- Plagiarism
+- Password Security
+- Earning on Steemit
+
+### Helpful Posts from Steemit Users
+### Users to Follow
+### Other Resources
+### Live Help
+### Third Party References
-### To Do List
+***
-1. Backup your password
-2. Sign Up for Steemit Chat
-3. Setup your Profile, Avatar, and Cover Image
-4. Choose your "NSFW" (Not Safe for Work) Display Preference
-5. Create your "introduceyourself" post
+## To Do List
+
+### 1. Backup your password
-### Helpful Posts from Steemit Users
-### Users to Follow
-### Other Resources
-### Live Help
-### Third Party References
+Unlike centralized web services, **the Steem Blockchain has no account password recovery**.
-***
+You are entirely responsible for keeping your password, and keeping it secure.
-## Quick Start Guide
+Save your master key and keep it somewhere safe.
-
-### No Cost to Participate
+It is strongly recommended that you store an offline copy of your password somewhere safe in case of a hard drive failure or other calamity. Consider digital offline storage, such as a flash drive or burned CD, as well as printed paper. Use a safe deposit box for best redundancy.
-It is free to post, comment, or upvote all content on Steemit.com. You might even get paid for it!
+If your account is valuable, treat it like a valuable!
-^
-
-### Upvotes
+^
+### 2. Review the Quick Start Guide
-Upvotes are Steemit's way of saying you like someone's post or comment.
+The Quick Start Guide section of this Welcome page contains basic information to help get you started.
-To upvote, click on the *Upvote* icon at the bottom of the comment/post.
+^
+### 3. Read the Helpful Posts from Steemit Users
-^
-
-### Comments
+The Helpful Posts from Steemit Users section of this Welcome page contains many well written articles from members of the community with tips on how to succeed.
-When you are first starting out, commenting on other people's posts can be a great way to get involved and connect with people!
+^
+### 4. Setup your Profile, Avatar, and Cover Image
-To comment on a post, or reply to an existing comment, click on the "Reply" link at the bottom of the post/comment.
+Under your user settings, you can update your profile. This includes your display name, location, about info, and website.
-^
-
-### Creating Posts
+To set your avatar image, type or paste a link to the URL where the image is located into the "Profile Picture URL" field.
-To create a post, click on the "Post" link in the upper right corner.
+To set your cover image, type or paste a link to the URL where the image is located into the "Cover Image URL" field.
-Posts have three main parts: Title, Content, Tags.
+Once you have made all your changes, click the "Update" button to save your profile.
-You will want to make your title attention grabbing, and relevant to your content.
+^
+### 5. Choose your "NSFW" (Not Safe for Work) Display Preference
-To create your content, you can either use "Editor" or "Markdown" mode.
+By default, content that users have tagged as "NSFW" will be hidden, but a link will be shown to reveal the content.
-There are several guides for creating posts in the "Helpful Posts from Steemit Users" section below.
+You can update your display preference so that NSFW content is always shown by default, or is completely hidden with no option to reveal.
-^
-
-### Tags
+^
+### 6. Sign Up for Steem Chat
-Tags will help people find your posts.
+A lot of users hang out and chat when they are not posting or browsing Steemit. It is a great place to meet people!
-Each post can have up to five tags, separated by spaces.
+There is a link to sign up in the main menu in the upper right corner.
-The first tag in the list will be the main category that the post is in.
+Your [steem.chat](https://steem.chat/home) account is a separate account from your Steem account.
-The tags should all be relevant to the content in the post.
+Some channels allow you to share links, but others don't. For instance, [general](https://steem.chat/channel/general) is for discussion without link promotion, while [postpromotion](https://steem.chat/channel/postpromotion) is for promoting your Steemit posts.
-You can browse content by tags, as well as see a list of popular tags that other users have used in their posts [here](https://steemit.com/tags).
+Each channel will have its rules posted in the "Info" section.
-^
-
-### Followers and Feeds
+^
+### 7. Create your "introduceyourself" post
-To follow an author, click on their username and click the "Follow" button.
+While not required, the tradition for new users is to create an "introduceyourself" post, to let the community know who you are.
-Once you follow someone, all of their posts will show up in your "Feed" on the homepage when you login.
+You can see some examples of what other people have done [here](https://steemit.com/trending30/introduceyourself).
-As other Steemians come across your posts and comments, you will start to gain followers.
+It is not required, but a lot of users will take a picture of themselves holding up a piece of paper that says "Steemit" with the current date, so we know you are a real person.
-You can see all of your followers and the people you are following in your profile page.
+It is not required either, but if you have other social media accounts (Twitter, Facebook, etc.) you can help the community verify that you are who you say you are, by sharing the link to your Steemit introduceyourself post with those accounts. If you are claiming to be someone famous, this is pretty much expected.
-^
-
-### Resteem
+^
+### 8. Learn more
-If you want to share someone else's post with all of your followers, click on the *resteem* icon.
+The Other Resources section of this Welcome page contains additional resouces to learn more about the platform. The FAQ page contains answers to the most commonly asked questions, and the bluepaper explains how the platform works.
-^
-
-### Digital Currencies
+^
-STEEM, Steem Power and Steem Dollars are the three forms of digital currency used by the Steem Blockchain.
+***
-More information on the three types of tokens can be found in the [Steemit FAQ](https://steemit.com/faq.html).
+## Quick Start Guide
-^
-
-### Curation
+### No Cost to Participate
-Up to 25% of the reward for posts goes to the people who voted on it. These people are called curators.
+It is free to post, comment, or upvote all content on Steemit.com. You might even get paid for it!
-The more Steem Power you have in your account, the more your upvotes will be worth, and the more potential curation rewards you can earn!
+^
+### Upvotes
-^
-
-### Payments
+Upvotes are Steemit's way of saying you like someone's post or comment.
-Payouts are made 7 days after the post/comment is created. You can claim your rewards in your wallet after 7 days.
+To upvote, click on the *Upvote* icon at the bottom of the comment/post.
-The payments may fluctuate (up and down) until the final payment is reached.
+^
+###
-Payments for posts are split between the author (at least 75%) and the curators (up to 25%).
+When you are first starting out, commenting on other people's posts can be a great way to get involved and connect with people!
-The author reward is paid 50% in Steem Power, and 50% in liquid STEEM/SBD.
+To comment on a post, or reply to an existing comment, click on the "Reply" link at the bottom of the post/comment.
-Authors also have the option to decline payout, or be paid in 100% Steem Power!
+^
+### Creating Posts
+
+To create a post, click on the "Post" link in the upper right corner.
-^
-
-### Home, New, Hot, Trending, Promoted, and Active
+Posts have three main parts: Title, Content, Tags.
-These are various ways to sort blog posts.
+You will want to make your title attention grabbing, and relevant to your content. The first image that you use will be the thumbnail image.
-**Home** - Most recent posts of the people you follow (your feed).
+Tags will help people find your posts. Each post can have up to five tags, separated by spaces. The tags should all be relevant to the content in the post. You can browse content by tags, as well as see a list of popular tags that other users have used in their posts [here](https://steemit.com/tags).
-**New** - Posts are sorted by the time posted, newest first.
+There are several guides for creating posts in the "Helpful Posts from Steemit Users" section below.
-**Hot** - Popular posts at the moment.
+^
+### Followers and Feeds
-**Trending** - Posts with the highest pending rewards currently.
+To follow an author, click on their username and click the "Follow" button.
-**Promoted** - Listings that are boosted by Steem Dollar payments get "Promoted" for greater visibility.
+Once you follow someone, all of their posts will show up in your "Feed" on the homepage when you login.
-^
-
-### Profile
+As other Steemians come across your posts and comments, you will start to gain followers.
-
+You can see all of your followers and the people you are following in your profile page.
-**Feed** - Here is where you go to see the most recent posts from the people you follow.
+^
+### Resteem
-**Blog** - Here is where you go to see all of your posts and resteems.
+If you want to share someone else's post with all of your followers, click on the *resteem* icon.
-**Comments** - Here is where you go to see all of the comments you have made to other's posts and comments.
+^
+### Digital Currencies
-**Replies** - Here is where you go to see all replies other users have made to your posts and comments.
+STEEM, Steem Power and Steem Dollars are the three forms of digital currency used by the Steem Blockchain.
-**Wallet** - Here is where you go to see your wallet balances, make transfers, exchange STEEM/SBD, and Power Up.
+More information on the three types of tokens can be found in the [Steemit FAQ](https://steemit.com/faq.html#What_is_the_difference_between_STEEM__STEEM_Power__and_Steem_Dollars).
-**Change Password** - Here is where you go to change your password.
+^
+### Curation
-**Settings** - Here is where you go to update your settings.
+Up to 25% of the reward for posts goes to the people who voted on it. These people are called curators.
-**Logout** - Here is where you go to logout.
+The more Steem Power you have in your account, the more your upvotes will be worth, and the more potential curation rewards you can earn!
-^
-
-### Reputation
+^
+### Payments
+
+Payouts are made 7 days after the post/comment is created. You can claim your rewards in your wallet after 7 days.
+
+The payments may fluctuate (up and down) until the final payment is reached.
+
+Payments for posts are split between the author (at least 75%) and the curators (up to 25%).
+
+The author reward is paid 50% in Steem Power, and 50% in liquid STEEM/SBD.
+
+Authors also have the option to decline payout, or be paid in 100% Steem Power!
+
+^
+### Reputation
A reputation score is one way Steemit measures the amount of value you have brought to the community.
@@ -196,19 +209,17 @@ All new users start at 25.
Your reputation will go up as you earn upvotes for your posts and comments, but it can come down if they are flagged.
-^
-
-### Cashing out or Spending SBD
+^
+### Cashing out or Spending SBD
-You can spend your SBD at the [Peerhub Store](https://www.peerhub.com/).
+You can exchange SBD for STEEM in the [Currency Market](https://steemit.com/market). Once you have STEEM, you can "Power Up" in your wallet to gain additional Steem Power.
-You can exchange your STEEM and SBD for bitcoin on an exchange such as [BlockTrades](https://blocktrades.us/) or [Bittrex](https://bittrex.com/).
+You can spend your SBD at the [Peerhub Store](https://www.peerhub.com/).
-You can also "Power Up" and use your STEEM/SBD to gain more Steem Power!
+You can also exchange your STEEM and SBD for bitcoin on a third-party exchange such as [BlockTrades](https://blocktrades.us/) or [Bittrex](https://bittrex.com/).
-^
-
-### Plagiarism
+^
+### Plagiarism
The community is looking for you to add your own personal touch to your articles.
@@ -218,107 +229,40 @@ If you are using anyone else's material as part of your posts (including images)
Also, make sure that you are not violating any copyright laws if you are using someone else's material/images. Limited, sourced material sharing is OK under fair use and fair dealing doctrines.
-^
-
-### Password Security
+^
+### Password Security
-Your Steemit account is worth real money. Treat your Steemit password like you would your bank password, and keep it secure!
+**There is no lost password recovery for Steem accounts**. You are 100% responsible for having it backed up. This means secure digital backups, as well as secured paper backups, off-site if possible.
-Unless your password was recently changed and you possess the old one, **there is no password recovery for Steem accounts**. You are 100% responsible for having it backed up. This means secure digital backups, as well as secured paper backups, off-site if possible.
+Your Steemit account is worth real money. Treat your Steemit password like you would your bank password, and keep it secure!
-^
-
-### Earning on Steemit
+^
+### Earning on Steemit
The best attitude to have is to expect to make nothing. Have fun. Get engaged. Make friends. If along the way you earn something - bonus!
It is possible to earn thousands of dollars, but most authors who are doing this have put in a lot of time and work to contribute to the community and build followings.
-^
-
-***
-
-## To Do List
-
-
-### 1. Backup your password
-
-Unlike centralized web services, **the Steem Blockchain has no account password recovery**.
-
-You are entirely responsible for keeping your password, and keeping it secure.
-
-Save your master key and keep it somewhere safe.
-
-It is strongly recommended that you store an offline copy of your password somewhere safe in case of a hard drive failure or other calamity. Consider digital offline storage, such as a flash drive or burned CD, as well as printed paper. Use a safe deposit box for best redundancy.
-
-If your account is valuable, treat it like a valuable!
-
-^
-
-### 2. Sign Up for Steemit Chat
-
-A lot of users hang out and chat when they are not posting or browsing Steemit. It is a great place to meet people!
-
-There is a link to sign up in the main menu in the upper right corner.
-
-Your [steemit.chat](https://steemit.chat/home) account is a separate account from your Steem account.
-
-Some channels allow you to share links, but others don't. For instance, [general](https://steemit.chat/channel/general) is for discussion without link promotion, while [postpromotion](https://steemit.chat/channel/postpromotion) is for promoting your Steemit posts.
-
-Each channel will have its rules posted in the "Info" section.
-
-^
-
-### 3. Setup your Profile, Avatar, and Cover Image
-
-Under your user settings, you can update your profile. This includes your display name, location, about info, and website.
-
-To set your avatar image, type or paste a link to the URL where the image is located into the "Profile Picture URL" field.
-
-To set your cover image, type or paste a link to the URL where the image is located into the "Cover Image URL" field.
-
-Once you have made all your changes, click the "Update" button to save your profile.
-
-^
-
-### 4. Choose your "NSFW" (Not Safe for Work) Display Preference
-
-By default, content that users have tagged as "NSFW" will be hidden, but a link will be shown to reveal the content.
-
-You can update your display preference so that NSFW content is always shown by default, or is completely hidden with no option to reveal.
-
-^
-
-### 5. Create your "introduceyourself" post
-
-While not required, the tradition for new users is to create an "introduceyourself" post, to let the community know who you are.
-
-You can see some examples of what other people have done [here](https://steemit.com/trending30/introduceyourself).
-
-It is not required, but a lot of users will take a picture of themselves holding up a piece of paper that says "Steemit" with the current date, so we know you are a real person.
-
-It is not required either, but if you have other social media accounts (Twitter, Facebook, etc.) you can help the community verify that you are who you say you are, by sharing the link to your Steemit introduceyourself post with those accounts. If you are claiming to be someone famous, this is pretty much expected.
-
-^
+^
***
-
-## Helpful Posts from Steemit Users
+## Helpful Posts from Steemit Users
- [Posting and Markdown Basics](https://steemit.com/steemit/@thecryptofiend/markdown-basics-for-beginners)
-- [Tons of Ways to Spend Your Hard Earned STEEM/SBD](https://steemit.com/steem/@timcliff/the-steem-economy-tons-of-ways-to-spend-your-hard-earned-steem-sbd)
+- [Ways to Spend Your Hard Earned STEEM/SBD](https://steemit.com/steem/@timcliff/the-steem-economy-tons-of-ways-to-spend-your-hard-earned-steem-sbd)
- [Advice on How To Build a Following](https://steemit.com/steemit/@allasyummyfood/how-i-build-a-following-of-160-k-from-scratch)
- [Steemit Etiquette Guide](https://steemit.com/steemit/@thecryptofiend/the-complete-steemit-etiquette-guide-revision-2-0)
+- [Introduceyourself Example](https://steemit.com/almost-famous/@teamsteem/hello-steemit-coinmaketcap-com-introduced-me)
+- [8 Mistakes to Avoid](https://steemit.com/steemit/@alcibiades/8-mistakes-i-see-beginners-make-on-steemit)
- [Advice on using Tags](https://steemit.com/steemit/@rok-sivante/the-top-3-reasons-to-tag-your-steemit-posts-a-simple-quick-strategy-for-long-term-profits-and-success)
-- [The Ultimate Guide To Steemit Payouts](https://steemit.com/steemit/@shenanigator/the-ultimate-guide-to-steemit-payouts)
+- [Guide To Steemit Payouts](https://steemit.com/steemit/@shenanigator/the-ultimate-guide-to-steemit-payouts)
- [Steemit Succeeds if We Make it Succeed](https://steemit.com/steemit/@krnel/steemit-succeeds-if-we-make-it-succeed)
-- [Professional Formatting Tutorial](https://steemit.com/writing/@minion/professional-tutorial-for-post-formatting-both-for-beginners-and-advanced-users)
-- [Introduceyourself Example](https://steemit.com/almost-famous/@teamsteem/hello-steemit-coinmaketcap-com-introduced-me)
-- [The Steemit Newbie's Comprehensive Guide To Understanding Your Wallet](https://steemit.com/steemit-help/@merej99/the-steemit-newbie-s-comprehensive-guide-to-understanding-your-wallet-by-merej99)
+- [Understanding Your Wallet](https://steemit.com/steemit-help/@merej99/the-steemit-newbie-s-comprehensive-guide-to-understanding-your-wallet-by-merej99)
- [Witness Voting Guide](https://steemit.com/witness-category/@timcliff/witness-voting-guide)
- [Steemit for Artists](https://steemit.com/art/@voronoi/steemit-for-artists-a-new-stage-for-craft)
-- [Steemit Chat Guide](https://steemit.com/steemit/@firepower/dummies-guide-to-using-steemit-chat-effectively-everyday)
+- [Steem Chat Guide](https://steemit.com/steemit/@firepower/dummies-guide-to-using-steemit-chat-effectively-everyday)
+- [Video interview on how to be successful](https://steemit.com/blog/@terrybrock/steemit-success-series--timcliff-on-who-to-target-with-your-content-1512178826-124805)
- [How to use Blocktrades to exchange STEEM/SBD for BTC](https://steemit.com/steem/@thecryptofiend/how-to-use-blocktrades-the-fastest-and-easiest-way-to-buy-and-sell-steem-sd-and-my-review-of-the-experience)
- [SBD to bitcoin (BTC) using Blocktrades, then BTC to Euro or USD Using CEX.io](https://steemit.com/howto/@future24/blocktrades-tutorial-part-2-how-to-exchange-sbd-to-btc-and-sell-them-for-euro-or-usd-english-german)
- [A Guide To Cashing Out Your STEEM/SBD Using PayPal](https://steemit.com/tutorial/@son-of-satire/a-minnows-guide-to-cashing-out-your-steem-sbd-using-paypal-without-using-coinbase-and-their-invasive-identity-checks)
@@ -339,40 +283,37 @@ It is not required either, but if you have other social media accounts (Twitter,
- [Blogging Tools](https://steemit.com/blogging/@munteanu/blogging-tools)
- [How to Create Different Types of Blog Content](https://steemit.com/writing/@jessicanicklos/how-to-create-different-types-of-blog-content-know-here-total-guide-line)
-^
-
-## Users to Follow
+^
+## Users to Follow
- @steemitblog - Official Steemit Announcements
- @ned - Ned Scott, CEO and Co-Founder of Steemit
-^
-
-## Other Resources
+^
+## Other Resources
-- [FAQ](https://steemit.com/faq.html)
-- [Steemit Help](https://www.steemithelp.net/)
-- [The Steem Whitepaper](https://steem.io/SteemWhitePaper.pdf)
-- [Steem App Center](http://steemtools.com/)
-- [Steem Block Explorer](https://steemd.com/)
-- [Steem Blockchain Explorer](https://steemdb.com/)
+- [FAQ](https://steemit.com/faq.html) - Answers to commonly asked questions
+- [Bluepaper](https://steem.io/steem-bluepaper.pdf) - Explanation of how the platform works
+- [Steemit Help](https://www.steemithelp.net/) - Community maintained help pages
+- [The Steem Whitepaper](https://steem.io/SteemWhitePaper.pdf) - Technical details of the Steem blockchain
+- [Steem App Center](http://steemtools.com/) - Community developed tools for the Steem blockchain
+- [Steem Block Explorer](https://steemd.com/) - Shows the raw Steem blockchain data
+- [Steem Blockchain Explorer](https://steemdb.com/) - Analysis pages for the Steem blockchain data
-^
-
-## Live Help
+^
+## Live Help
-Ask your general questions in the [help](https://steemit.chat/channel/help) channel of [steemit.chat](https://steemit.chat/home). Users in the channel will typically respond to questions within a few hours.
+Ask your general questions in the [help](https://steem.chat/channel/help) channel of [steem.chat](https://steem.chat/home). Users in the channel will typically respond to questions within a few hours.
New Member Support Community is a group of people dedicated to helping new users find their way around Steemit. You can find them in the [New Member Support Community](https://discord.gg/HYj4yvw) channel of Discord Chat.
-^
-
-## Third Party References
+^
+## Third Party References
-Peerhub, BlockTrades, Bittrex, Steemit Chat, Steemit Help, New Member Support Community, and Discord Chat, as well as the tools listed under "Other Resources" are third party applications/services, and are not owned or maintained by Steemit, Inc. Their listing here does not constitute and endorsement or recommendation on behalf of Steemit, Inc.
+Peerhub, BlockTrades, Bittrex, Steem Chat, Steemit Help, New Member Support Community, and Discord Chat, as well as the tools listed under "Other Resources" are third party applications/services, and are not owned or maintained by Steemit, Inc. Their listing here does not constitute and endorsement or recommendation on behalf of Steemit, Inc.
All of the links in the "Helpful Posts from Steemit Users" section were created by our users and do not necessarily represent the views of Steemit, Inc. or its management.
Please use the third party tools and content at your own risk.
-^
+^
diff --git a/src/app/locales/counterpart/es.js b/src/app/locales/counterpart/es.js
index a43372846c43149a2e2fbf4d5ff51a3178a0cba2..f5640c7d291d67a21ecefd36eea609af9378d7ec 100644
--- a/src/app/locales/counterpart/es.js
+++ b/src/app/locales/counterpart/es.js
@@ -9,22 +9,22 @@ module.exports = {
formats: {
date: {
- 'default': '%a, %e %b %Y',
- long: '%A, %B %o, %Y',
- short: '%b %e'
+ default: '%a, %e %b %Y',
+ long: '%A, %B %o, %Y',
+ short: '%b %e',
},
time: {
- 'default': '%H:%M',
- long: '%H:%M:%S %z',
- short: '%H:%M'
+ default: '%H:%M',
+ long: '%H:%M:%S %z',
+ short: '%H:%M',
},
datetime: {
- 'default': '%a, %e %b %Y %H:%M',
- long: '%A, %B %o, %Y %H:%M:%S %z',
- short: '%e %b %H:%M'
- }
- }
- }
+ default: '%a, %e %b %Y %H:%M',
+ long: '%A, %B %o, %Y %H:%M:%S %z',
+ short: '%e %b %H:%M',
+ },
+ },
+ },
};
diff --git a/src/app/locales/counterpart/fr.js b/src/app/locales/counterpart/fr.js
index a43372846c43149a2e2fbf4d5ff51a3178a0cba2..f5640c7d291d67a21ecefd36eea609af9378d7ec 100644
--- a/src/app/locales/counterpart/fr.js
+++ b/src/app/locales/counterpart/fr.js
@@ -9,22 +9,22 @@ module.exports = {
formats: {
date: {
- 'default': '%a, %e %b %Y',
- long: '%A, %B %o, %Y',
- short: '%b %e'
+ default: '%a, %e %b %Y',
+ long: '%A, %B %o, %Y',
+ short: '%b %e',
},
time: {
- 'default': '%H:%M',
- long: '%H:%M:%S %z',
- short: '%H:%M'
+ default: '%H:%M',
+ long: '%H:%M:%S %z',
+ short: '%H:%M',
},
datetime: {
- 'default': '%a, %e %b %Y %H:%M',
- long: '%A, %B %o, %Y %H:%M:%S %z',
- short: '%e %b %H:%M'
- }
- }
- }
+ default: '%a, %e %b %Y %H:%M',
+ long: '%A, %B %o, %Y %H:%M:%S %z',
+ short: '%e %b %H:%M',
+ },
+ },
+ },
};
diff --git a/src/app/locales/counterpart/it.js b/src/app/locales/counterpart/it.js
index 88edb1dd0fa1089363764b677ee11da974c39910..0c5799a5bd9035789ea1976a4ad13333d18432a5 100644
--- a/src/app/locales/counterpart/it.js
+++ b/src/app/locales/counterpart/it.js
@@ -9,22 +9,22 @@ module.exports = {
formats: {
date: {
- 'default': '%a, %e %b %Y',
- long: '%A, %B %o, %Y',
- short: '%e %b'
+ default: '%a, %e %b %Y',
+ long: '%A, %B %o, %Y',
+ short: '%e %b',
},
time: {
- 'default': '%H:%M',
- long: '%H:%M:%S %z',
- short: '%H:%M'
+ default: '%H:%M',
+ long: '%H:%M:%S %z',
+ short: '%H:%M',
},
datetime: {
- 'default': '%a, %e %b %Y %H:%M',
- long: '%A, %B %o, %Y %H:%M:%S %z',
- short: '%e %b %H:%M'
- }
- }
- }
+ default: '%a, %e %b %Y %H:%M',
+ long: '%A, %B %o, %Y %H:%M:%S %z',
+ short: '%e %b %H:%M',
+ },
+ },
+ },
};
diff --git a/src/app/locales/counterpart/ko.js b/src/app/locales/counterpart/ko.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5640c7d291d67a21ecefd36eea609af9378d7ec
--- /dev/null
+++ b/src/app/locales/counterpart/ko.js
@@ -0,0 +1,30 @@
+// The translations in this file are added by default.
+
+'use strict';
+
+module.exports = {
+ counterpart: {
+ names: require('date-names/en'),
+ pluralize: require('pluralizers/en'),
+
+ formats: {
+ date: {
+ default: '%a, %e %b %Y',
+ long: '%A, %B %o, %Y',
+ short: '%b %e',
+ },
+
+ time: {
+ default: '%H:%M',
+ long: '%H:%M:%S %z',
+ short: '%H:%M',
+ },
+
+ datetime: {
+ default: '%a, %e %b %Y %H:%M',
+ long: '%A, %B %o, %Y %H:%M:%S %z',
+ short: '%e %b %H:%M',
+ },
+ },
+ },
+};
diff --git a/src/app/locales/counterpart/pl.js b/src/app/locales/counterpart/pl.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5640c7d291d67a21ecefd36eea609af9378d7ec
--- /dev/null
+++ b/src/app/locales/counterpart/pl.js
@@ -0,0 +1,30 @@
+// The translations in this file are added by default.
+
+'use strict';
+
+module.exports = {
+ counterpart: {
+ names: require('date-names/en'),
+ pluralize: require('pluralizers/en'),
+
+ formats: {
+ date: {
+ default: '%a, %e %b %Y',
+ long: '%A, %B %o, %Y',
+ short: '%b %e',
+ },
+
+ time: {
+ default: '%H:%M',
+ long: '%H:%M:%S %z',
+ short: '%H:%M',
+ },
+
+ datetime: {
+ default: '%a, %e %b %Y %H:%M',
+ long: '%A, %B %o, %Y %H:%M:%S %z',
+ short: '%e %b %H:%M',
+ },
+ },
+ },
+};
diff --git a/src/app/locales/counterpart/zh.js b/src/app/locales/counterpart/zh.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5640c7d291d67a21ecefd36eea609af9378d7ec
--- /dev/null
+++ b/src/app/locales/counterpart/zh.js
@@ -0,0 +1,30 @@
+// The translations in this file are added by default.
+
+'use strict';
+
+module.exports = {
+ counterpart: {
+ names: require('date-names/en'),
+ pluralize: require('pluralizers/en'),
+
+ formats: {
+ date: {
+ default: '%a, %e %b %Y',
+ long: '%A, %B %o, %Y',
+ short: '%b %e',
+ },
+
+ time: {
+ default: '%H:%M',
+ long: '%H:%M:%S %z',
+ short: '%H:%M',
+ },
+
+ datetime: {
+ default: '%a, %e %b %Y %H:%M',
+ long: '%A, %B %o, %Y %H:%M:%S %z',
+ short: '%e %b %H:%M',
+ },
+ },
+ },
+};
diff --git a/src/app/locales/en.json b/src/app/locales/en.json
index 37b0e9b78df3f7ab8459b30f1eea6d6207ea8b77..534ff72d1f44732725e1b3c061476404db70c2f7 100644
--- a/src/app/locales/en.json
+++ b/src/app/locales/en.json
@@ -1,653 +1,873 @@
{
- "g": {
- "age": "age",
- "amount": "Amount",
- "and": "and",
- "are_you_sure": "Are you sure?",
- "ask": "Ask",
- "balance": "Balance",
- "balances": "Balances",
- "bid": "Bid",
- "blog": "Blog",
- "browse": "Browse",
- "buy": "Buy",
- "buy_or_sell": "Buy or Sell",
- "by": "by",
- "cancel": "Cancel",
- "change_password": "Change Password",
- "choose_language": "Choose Language",
- "clear": "Clear",
- "close": "Close",
- "collapse_or_expand": "Collapse/Expand",
- "comments": "Comments",
- "confirm": "Confirm",
- "convert": "Convert",
- "date": "Date",
- "delete": "Delete",
- "dismiss": "Dismiss",
- "edit": "Edit",
- "email": "Email",
- "feed": "Feed",
- "follow": "Follow",
- "for": " for ",
- "from": " from ",
- "go_back": "Back",
- "hide": "Hide",
- "in": "in",
- "in_reply_to": "in reply to",
- "insufficient_balance": "Insufficient balance",
- "invalid_amount": "Invalid amount",
- "joined": "Joined",
- "loading": "Loading",
- "login": "Login",
- "logout": "Logout",
- "memo": "Memo",
- "mute": "Mute",
- "myblog": "My blog",
- "mycomments": "My comments",
- "myreplies": "Replies to me",
- "new": "new",
- "newer": "Newer",
- "next": "Next",
- "no": "No",
- "ok": "Ok",
- "older": "Older",
- "or": "or",
- "order_placed": "Order placed",
- "password": "Password",
- "payouts": "Payouts",
- "permissions": "Permissions",
- "phishy_message": "Link expanded to plain text; beware of a potential phishing attempt",
- "post": "Post",
- "post_as": "Post as",
- "posts": "Posts",
- "powered_up_100": "Powered Up 100%%",
- "preview": "Preview",
- "previous": "Previous",
- "price": "Price",
- "print": "Print",
- "promote": "Promote",
- "promoted": "promoted",
- "re": "RE",
- "re_to": "RE: %(topic)s",
- "recent_password": "Recent Password",
- "receive": "Receive ",
- "remove": "Remove",
- "remove_vote": "Remove Vote",
- "replied_to": "replied to %(account)s",
- "replies": "Replies",
- "reply": "Reply",
- "reply_count": {
- "zero": "no replies",
- "one": "1 reply",
- "other": "%(count)s replies"
- },
- "reputation": "Reputation",
- "reveal_comment": "Reveal Comment",
- "request": "request",
- "required": "Required",
- "rewards": "Rewards",
- "save": "Save",
- "saved": "Saved",
- "search": "Search",
- "sell": "Sell",
- "settings": "Settings",
- "share_this_post": "Share this post",
- "show": "Show",
- "sign_in": "Sign in",
- "sign_up": "Sign up",
- "since": "since",
- "submit": "Submit",
- "power_up": "Power Up",
- "submit_a_story": "Post",
- "tag": "Tag",
- "to": " to ",
- "topics": "Topics",
- "toggle_nightmode": "Toggle Night Mode",
- "all_tags": "All tags",
- "transfer": "Transfer ",
- "trending_topics": "Trending Topics",
- "type": "Type",
- "unfollow": "Unfollow",
- "unmute": "Unmute",
- "unknown": "Unknown",
- "upvote": "Upvote",
- "upvote_post": "Upvote post",
- "username": "Username",
- "version": "Version",
- "vote": "Vote",
- "votes": "votes",
- "wallet": "Wallet",
- "warning": "warning",
- "yes": "Yes",
- "posting": "Posting",
- "owner": "Owner",
- "active": "Active",
- "account_not_found": "Account not found",
- "this_is_wrong_password": "This is the wrong password",
- "do_you_need_to": "Do you need to",
- "account_name": "Account Name",
- "recover_your_account": "recover your account",
- "reset_usernames_password": "Reset %(username)s's Password",
- "this_will_update_usernames_authtype_key": "This will update %(username)s %(authType)s key",
- "passwords_do_not_match": "Passwords do not match",
- "you_need_private_password_or_key_not_a_public_key": "You need a private password or key (not a public key)",
- "the_rules_of_APP_NAME": {
- "one": "The first rule of %(APP_NAME)s is: Do not lose your password.",
- "second": "The second rule of %(APP_NAME)s is: Do not lose your password.",
- "third": "The third rule of %(APP_NAME)s is: We cannot recover your password.",
- "fourth": "The fourth rule: If you can remember the password, it's not secure.",
- "fifth": "The fifth rule: Use only randomly-generated passwords.",
- "sixth": "The sixth rule: Do not tell anyone your password.",
- "seventh": "The seventh rule: Always back up your password."
- },
- "recover_password": "Recover Account",
- "current_password": "Current Password",
- "generated_password": "Generated Password",
- "backup_password_by_storing_it": "Back it up by storing in your password manager or a text file",
- "enter_account_show_password": "Enter a valid account name to show the password",
- "click_to_generate_password": "Click to generate password",
- "re_enter_generate_password": "Re-enter Generated Password",
- "understand_that_APP_NAME_cannot_recover_password": "I understand that %(APP_NAME)s cannot recover lost passwords",
- "i_saved_password": "I have securely saved my generated password",
- "update_password": "Update Password",
- "confirm_password": "Confirm Password",
- "account_updated": "Account Updated",
- "password_must_be_characters_or_more": "Password must be %(amount)s characters or more",
- "need_password_or_key": "You need a private password or key (not a public key)",
- "login_to_see_memo": "login to see memo",
- "new_password": "New Password",
- "incorrect_password": "Incorrect password",
- "username_does_not_exist": "Username does not exist",
- "account_name_should_start_with_a_letter": "Account name should start with a letter.",
- "account_name_should_be_shorter": "Account name should be shorter.",
- "account_name_should_be_longer": "Account name should be longer.",
- "account_name_should_have_only_letters_digits_or_dashes": "Account name should have only letters, digits, or dashes.",
- "cannot_increase_reward_of_post_within_the_last_minute_before_payout": "Cannot increase reward of post within the last minute before payout",
- "vote_currently_exists_user_must_be_indicate_a_to_reject_witness": "vote currently exists, user must be indicate a desire to reject witness",
- "only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes": "Only one Steem account allowed per IP address every 10 minutes",
- "resteem_this_post": "Resteem This Post",
- "reblog": "Resteem",
- "write_your_story": "Write your story",
- "remember_voting_and_posting_key": "Remember voting & posting key",
- "auto_login_question_mark": "Auto login?",
- "hide_private_key": "Hide private key",
- "show_private_key": "Show private key",
- "login_to_show": "Login to show",
- "not_valid_email": "Not valid email",
- "thank_you_for_being_an_early_visitor_to_APP_NAME": "Thank you for being an early visitor to %(APP_NAME)s. We will get back to you at the earliest possible opportunity.",
- "author_rewards": "Author rewards",
- "curation_rewards": "Curation rewards",
- "sorry_your_reddit_account_doesnt_have_enough_karma": "Sorry, your Reddit account doesn't have enough Reddit Karma to qualify for a free sign up. Please add your email for a place on the waiting list",
- "register_with_facebook": "Register with Facebook",
- "or_click_the_button_below_to_register_with_facebook": "Or click the button below to register with Facebook",
- "server_returned_error": "server returned error",
- "APP_NAME_support": "%(APP_NAME)s Support",
- "please_email_questions_to": "Please email your questions to",
- "next_7_strings_single_block": {
- "authors_get_paid_when_people_like_you_upvote_their_post": "Authors get paid when people like you upvote their post",
- "if_you_enjoyed_what_you_read_earn_amount": "If you enjoyed what you read here, create your account today and start earning FREE STEEM!",
- "free_steem": "FREE STEEM!",
- "sign_up_earn_steem": "Sign up now to earn "
- },
- "next_3_strings_together": {
- "show_more": "Show more",
- "show_less": "Show fewer",
- "value_posts": "low value posts"
- },
- "read_only_mode": "Due to server maintenance we are running in read only mode. We are sorry for the inconvenience.",
- "tags_and_topics": "Tags",
- "show_more_topics": "View all tags",
- "basic": "Basic",
- "advanced": "Advanced",
- "views": {
- "zero": "No Views",
- "one": "%(count)s View",
- "other": "%(count)s Views"
- },
- "responses": {
- "zero": "No Responses",
- "one": "%(count)s Response",
- "other": "%(count)s Responses"
- },
- "post_key_warning": {
- "confirm": "You are about to publish a STEEM private key or master password. You will probably lose control of the associated account and all its funds.",
- "warning": "Legitimate users, including employees of Steemit Inc., will never ask you for a private key or master password.",
- "checkbox": "I understand"
- }
- },
- "navigation": {
- "about": "About",
- "explore": "Explore",
- "APP_NAME_whitepaper": "%(APP_NAME)s Whitepaper",
- "buy_LIQUID_TOKEN": "Buy %(LIQUID_TOKEN)s",
- "sell_LIQUID_TOKEN": "Sell %(LIQUID_TOKEN)s",
- "currency_market": "Currency Market",
- "stolen_account_recovery": "Stolen Accounts Recovery",
- "change_account_password": "Change Account Password",
- "witnesses": "Witnesses",
- "vote_for_witnesses": "Vote for Witnesses",
- "privacy_policy": "Privacy Policy",
- "terms_of_service": "Terms of Service",
- "sign_up": "Join",
- "learn_more": "Learn More",
- "welcome": "Welcome",
- "faq": "FAQ",
- "shop": "The Steemit Shop",
- "chat": "Steemit Chat",
- "app_center": "Steemit App Center",
- "api_docs": "Steemit API Docs",
- "bluepaper": "Steem Bluepaper",
- "whitepaper": "Steem Whitepaper",
- "intro_tagline": "Money talks",
- "intro_paragraph": "Your voice is worth something. Join the community that pays you to post and curate high quality content."
- },
- "main_menu": {
- "hot": "hot",
- "trending": "trending"
- },
- "reply_editor": {
- "shorten_title": "Shorten title",
- "exceeds_maximum_length": "Exceeds maximum length (%(maxKb)sKB)",
- "including_the_category": " (including the category '%(rootCategory)s')",
- "use_limited_amount_of_tags": "You have %(tagsLength)s tags total%(includingCategory)s. Please use only 5 in your post and category line.",
- "are_you_sure_you_want_to_clear_this_form": "Are you sure you want to clear this form?",
- "uploading": "Uploading",
- "draft_saved": "Draft saved.",
- "editor": "Editor",
- "insert_images_by_dragging_dropping": "Insert images by dragging & dropping, ",
- "pasting_from_the_clipboard": "pasting from the clipboard, ",
- "selecting_them": "selecting them",
- "image_upload": "Image upload",
- "power_up_100": "Power Up 100%%",
- "default_50_50": "Default (50%% / 50%%)",
- "decline_payout": "Decline Payout",
- "check_this_to_auto_upvote_your_post": "Check this to auto-upvote your post",
- "markdown_styling_guide": "Markdown Styling Guide",
- "or_by": "or by",
- "title": "Title",
- "update_post": "Update Post",
- "markdown_not_supported": "Markdown is not supported here"
- },
- "category_selector_jsx": {
- "tag_your_story": "Tag (up to 5 tags), the first tag is your main category.",
- "select_a_tag": "Select a tag",
- "maximum_tag_length_is_24_characters": "Maximum tag length is 24 characters",
- "use_limited_amount_of_categories": "Please use only %(amount)s categories",
- "use_only_lowercase_letters": "Use only lowercase letters",
- "use_one_dash": "Use only one dash",
- "use_spaces_to_separate_tags": "Use spaces to separate tags",
- "use_only_allowed_characters": "Use only lowercase letters, digits and one dash",
- "must_start_with_a_letter": "Must start with a letter",
- "must_end_with_a_letter_or_number": "Must end with a letter or number"
- },
- "postfull_jsx": {
- "this_post_is_not_available_due_to_a_copyright_claim": "This post is not available due to a copyright claim.",
- "share_on_facebook": "Share on Facebook",
- "share_on_twitter": "Share on Twitter",
- "share_on_linkedin": "Share on Linkedin",
- "recent_password": "Recent Password",
- "in_week_convert_DEBT_TOKEN_to_LIQUID_TOKEN": "In 3.5 days, convert %(amount)s %(DEBT_TOKEN)s into %(LIQUID_TOKEN)s",
- "view_the_full_context": "View the full context",
- "view_the_direct_parent": "View the direct parent",
- "you_are_viewing_a_single_comments_thread_from": "You are viewing a single comment's thread from"
- },
- "market_jsx": {
- "action": "Action",
- "date_created": "Date Created",
- "last_price": "Last price",
- "24h_volume": "24h volume",
- "spread": "Spread",
- "total": "Total",
- "available": "Available",
- "lowest_ask": "Lowest ask",
- "highest_bid": "Highest bid",
- "buy_orders": "Buy Orders",
- "sell_orders": "Sell Orders",
- "trade_history": "Trade History",
- "open_orders": "Open Orders",
- "sell_amount_for_atleast": "Sell %(amount_to_sell)s for at least %(min_to_receive)s (%(effectivePrice)s)",
- "buy_atleast_amount_for": "Buy at least %(min_to_receive)s for %(amount_to_sell)s (%(effectivePrice)s)",
- "price_warning_above": "This price is well above the current market price of %(marketPrice)s, are you sure?",
- "price_warning_below": "This price is well below the current market price of %(marketPrice)s, are you sure?",
- "order_cancel_confirm": "Cancel order %(order_id)s from %(user)s?",
- "order_cancelled": "Order %(order_id)s cancelled.",
- "higher": "Higher",
- "lower": "Lower",
- "total_DEBT_TOKEN_SHORT_CURRENCY_SIGN": "Total %(DEBT_TOKEN_SHORT)s (%(CURRENCY_SIGN)s)"
- },
- "recoveraccountstep1_jsx": {
- "begin_recovery": "Begin Recovery",
- "not_valid": "Not valid",
- "account_name_is_not_found": "Account name is not found",
- "unable_to_recover_account_not_change_ownership_recently": "We are unable to recover this account, it has not changed ownership recently.",
- "password_not_used_in_last_days": "This password was not used on this account in the last 30 days.",
- "request_already_submitted_contact_support": "Your request has been already submitted and we are working on it. Please contact %(SUPPORT_EMAIL)s for the status of your request.",
- "recover_account_intro": "From time to time, a Steemian's owner key may be compromised. Stolen Account Recovery gives the rightful account owner 30 days to recover their account from the moment the thief changed their owner key. Stolen Account Recovery can only be used on %(APP_URL)s if the account owner had previously listed '%(APP_NAME)s' as their account trustee and complied with %(APP_NAME)s's Terms of Service.",
- "login_with_facebook_or_reddit_media_to_verify_identity": "Please login with Facebook or Reddit to verify your identity",
- "login_with_social_media_to_verify_identity": "Please login with %(provider)s to verify your identity",
- "enter_email_toverify_identity": "We need to verify your identity. Please enter your email address below to begin the verification.",
- "continue_with_email": "Continue with Email",
- "thanks_for_submitting_request_for_account_recovery": "Thanks for submitting your request for Account Recovery using %(APP_NAME)s's blockchain-based multi factor authentication. We will respond to you as quickly as possible, however, please expect there may be some delay in response due to high volume of emails. Please be prepared to verify your identity.",
- "recovering_account": "Recovering account",
- "recover_account": "Recover Account",
- "checking_account_owner": "Checking account owner",
- "sending_recovery_request": "Sending recovery request",
- "cant_confirm_account_ownership": "We can't confirm account ownership. Check your password",
- "account_recovery_request_not_confirmed": "Account recovery request is not confirmed yet, please get back later, thank you for your patience."
- },
- "user_profile": {
- "unknown_account": "Unknown Account",
- "user_hasnt_made_any_posts_yet": "Looks like %(name)s hasn't made any posts yet!",
- "user_hasnt_started_bloggin_yet": "Looks like %(name)s hasn't started blogging yet!",
- "user_hasnt_followed_anything_yet": "Looks like %(name)s might not be following anyone yet! If %(name)s recently added new users to follow, their personalized feed will populate once new content is available.",
- "user_hasnt_had_any_replies_yet": "%(name)s hasn't had any replies yet",
- "looks_like_you_havent_posted_anything_yet": "Looks like you haven't posted anything yet.",
- "create_a_post": "Create a Post",
- "explore_trending_articles": "Explore Trending Articles",
- "read_the_quick_start_guide": "Read The Quick Start Guide",
- "browse_the_faq": "Browse The FAQ",
- "followers": "Followers",
- "this_is_users_reputations_score_it_is_based_on_history_of_votes": "This is %(name)s's reputation score.\n\nThe reputation score is based on the history of votes received by the account, and is used to hide low quality content.",
- "follower_count": {
- "zero": "No followers",
- "one": "1 follower",
- "other": "%(count)s followers"
- },
- "followed_count": {
- "zero": "Not following anybody",
- "one": "1 following",
- "other": "%(count)s following"
- },
- "post_count": {
- "zero": "No posts",
- "one": "1 post",
- "other": "%(count)s posts"
- }
- },
- "authorrewards_jsx": {
- "estimated_author_rewards_last_week": "Estimated author rewards last week",
- "author_rewards_history": "Author Rewards History"
- },
- "curationrewards_jsx": {
- "estimated_curation_rewards_last_week": "Estimated curation rewards last week",
- "curation_rewards_history": "Curation Rewards History"
- },
- "post_jsx": {
- "now_showing_comments_with_low_ratings": "Now showing comments with low ratings",
- "sort_order": "Sort Order",
- "comments_were_hidden_due_to_low_ratings": "Comments were hidden due to low ratings"
- },
- "voting_jsx": {
- "flagging_post_can_remove_rewards_the_flag_should_be_used_for_the_following": "Flagging a post can remove rewards and make this material less visible. Some common reasons to flag",
- "disagreement_on_rewards": "Disagreement on rewards",
- "fraud_or_plagiarism": "Fraud or Plagiarism",
- "hate_speech_or_internet_trolling": "Hate Speech or Internet Trolling",
- "intentional_miss_categorized_content_or_spam": "Intentional miss-categorized content or Spam",
- "pending_payout": "Pending Payout $%(value)s",
- "payout_declined": "Payout Declined",
- "max_accepted_payout": "Max Accepted Payout $%(value)s",
- "promotion_cost": "Promotion Cost $%(value)s",
- "past_payouts": "Past Payouts $%(value)s",
- "past_payouts_author": " - Author $%(value)s",
- "past_payouts_curators": " - Curators $%(value)s",
- "we_will_reset_curation_rewards_for_this_post": "will reset your curation rewards for this post",
- "removing_your_vote": "Removing your vote",
- "changing_to_an_upvote": "Changing to an Up-Vote",
- "changing_to_a_downvote": "Changing to a Down-Vote",
- "confirm_flag": "Confirm Flag",
- "and_more": "and %(count)s more",
- "votes_plural": {
- "one": "%(count)s vote",
- "other": "%(count)s votes"
- }
- },
- "witnesses_jsx": {
- "witness_thread": "witness thread",
- "top_witnesses": "Witness Voting",
- "you_have_votes_remaining": {
- "zero": "You have no votes remaining",
- "one": "You have 1 vote remaining",
- "other": "You have %(count)s votes remaining"
- },
- "you_can_vote_for_maximum_of_witnesses": "You can vote for a maximum of 30 witnesses",
- "witness": "Witness",
- "information": "Information",
- "if_you_want_to_vote_outside_of_top_enter_account_name": "If you would like to vote for a witness outside of the top 50, enter the account name below to cast a vote",
- "set_witness_proxy": "You can also choose a proxy that will vote for witnesses for you. This will reset your current witness selection.",
- "witness_set": "You have set a voting proxy. If you would like to re-enable manual voting, please clear your proxy.",
- "witness_proxy_current": "Your current proxy is",
- "witness_proxy_set": "Set proxy",
- "witness_proxy_clear": "Clear proxy",
- "proxy_update_error": "Your proxy was not updated"
- },
- "votesandcomments_jsx": {
- "no_responses_yet_click_to_respond": "No responses yet. Click to respond.",
- "response_count_tooltip": {
- "zero": "no responses. Click to respond.",
- "one": "1 response. Click to respond.",
- "other": "%(count)s responses. Click to respond."
- },
- "vote_count": {
- "zero": "no votes",
- "one": "1 vote",
- "other": "%(count)s votes"
+ "g": {
+ "age": "age",
+ "amount": "Amount",
+ "and": "and",
+ "are_you_sure": "Are you sure?",
+ "ask": "Ask",
+ "balance": "Balance: %(balanceValue)s",
+ "balances": "Balances",
+ "bid": "Bid",
+ "blog": "Blog",
+ "browse": "Browse",
+ "buy": "Buy",
+ "buy_or_sell": "Buy or Sell",
+ "by": "by",
+ "cancel": "Cancel",
+ "change_password": "Change Password",
+ "choose_language": "Choose Language",
+ "clear": "Clear",
+ "close": "Close",
+ "collapse_or_expand": "Collapse/Expand",
+ "comments": "Comments",
+ "confirm": "Confirm",
+ "convert": "Convert",
+ "date": "Date",
+ "delete": "Delete",
+ "dismiss": "Dismiss",
+ "edit": "Edit",
+ "email": "Email",
+ "external_link_message":
+ "This link will take you away from steemit.com",
+ "feed": "Feed",
+ "follow": "Follow",
+ "for": " for ",
+ "from": " from ",
+ "go_back": "Back",
+ "hide": "Hide",
+ "in": "in",
+ "in_reply_to": "in reply to",
+ "insufficient_balance": "Insufficient balance",
+ "invalid_amount": "Invalid amount",
+ "joined": "Joined",
+ "loading": "Loading",
+ "login": "Login",
+ "logout": "Logout",
+ "memo": "Memo",
+ "mute": "Mute",
+ "myblog": "My blog",
+ "mycomments": "My comments",
+ "myreplies": "Replies to me",
+ "new": "New",
+ "newer": "Newer",
+ "next": "Next",
+ "no": "No",
+ "ok": "Ok",
+ "older": "Older",
+ "or": "or",
+ "order_placed": "Order placed: %(order)s",
+ "password": "Password",
+ "payouts": "Payouts",
+ "permissions": "Permissions",
+ "phishy_message":
+ "Link expanded to plain text; beware of a potential phishing attempt",
+ "post": "Post",
+ "post_as_user": "Post as %(username)s",
+ "posts": "Posts",
+ "powered_up_100": "Powered Up 100%%",
+ "preview": "Preview",
+ "previous": "Previous",
+ "price": "Price",
+ "print": "Print",
+ "promote": "Promote",
+ "promoted": "Promoted",
+ "re": "RE",
+ "re_to": "RE: %(topic)s",
+ "recent_password": "Recent Password",
+ "receive": "Receive ",
+ "remove": "Remove",
+ "remove_vote": "Remove Vote",
+ "replied_to": "replied to %(account)s",
+ "replies": "Replies",
+ "reply": "Reply",
+ "reply_count": {
+ "zero": "no replies",
+ "one": "1 reply",
+ "other": "%(count)s replies"
+ },
+ "reputation": "Reputation",
+ "reveal_comment": "Reveal Comment",
+ "request": "request",
+ "required": "Required",
+ "rewards": "Rewards",
+ "save": "Save",
+ "saved": "Saved",
+ "search": "Search",
+ "sell": "Sell",
+ "settings": "Settings",
+ "share_this_post": "Share this post",
+ "show": "Show",
+ "sign_in": "Sign in",
+ "sign_up": "Sign up",
+ "since": "since %(date)s",
+ "submit": "Submit",
+ "power_up": "Power Up",
+ "submit_a_story": "Post",
+ "tag": "Tag",
+ "to": " to ",
+ "topics": "Topics",
+ "toggle_nightmode": "Toggle Night Mode",
+ "all_tags": "All tags",
+ "all_tags_mobile": "All content",
+ "my_feed": "My feed",
+ "transfer": "Transfer ",
+ "trending_topics": "Trending Topics",
+ "type": "Type",
+ "unfollow": "Unfollow",
+ "unmute": "Unmute",
+ "unknown": "Unknown",
+ "upvote": "Upvote",
+ "upvote_post": "Upvote post",
+ "username": "Username",
+ "version": "Version",
+ "vote": "Vote",
+ "votes": "votes",
+ "wallet": "Wallet",
+ "warning": "warning",
+ "yes": "Yes",
+ "posting": "Posting",
+ "owner": "Owner",
+ "active": "Active",
+ "account_not_found": "Account not found",
+ "this_is_wrong_password": "This is the wrong password",
+ "do_you_need_to": "Do you need to",
+ "account_name": "Account Name",
+ "recover_your_account": "recover your account",
+ "reset_usernames_password": "Reset %(username)s's Password",
+ "this_will_update_usernames_authtype_key":
+ "This will update %(username)s %(authType)s key",
+ "passwords_do_not_match": "Passwords do not match",
+ "you_need_private_password_or_key_not_a_public_key":
+ "You need a private password or key (not a public key)",
+ "the_rules_of_APP_NAME": {
+ "one":
+ "The first rule of %(APP_NAME)s is: Do not lose your password.",
+ "second":
+ "The second rule of %(APP_NAME)s is: Do not lose your password.",
+ "third":
+ "The third rule of %(APP_NAME)s is: We cannot recover your password.",
+ "fourth":
+ "The fourth rule: If you can remember the password, it's not secure.",
+ "fifth": "The fifth rule: Use only randomly-generated passwords.",
+ "sixth": "The sixth rule: Do not tell anyone your password.",
+ "seventh": "The seventh rule: Always back up your password."
+ },
+ "recover_password": "Recover Account",
+ "current_password": "Current Password",
+ "generated_password": "Generated Password",
+ "backup_password_by_storing_it":
+ "Back it up by storing in your password manager or a text file",
+ "enter_account_show_password":
+ "Enter a valid account name to show the password",
+ "click_to_generate_password": "Click to generate password",
+ "re_enter_generate_password": "Re-enter Generated Password",
+ "understand_that_APP_NAME_cannot_recover_password":
+ "I understand that %(APP_NAME)s cannot recover lost passwords",
+ "i_saved_password": "I have securely saved my generated password",
+ "update_password": "Update Password",
+ "confirm_password": "Confirm Password",
+ "account_updated": "Account Updated",
+ "password_must_be_characters_or_more":
+ "Password must be %(amount)s characters or more",
+ "need_password_or_key":
+ "You need a private password or key (not a public key)",
+ "login_to_see_memo": "login to see memo",
+ "new_password": "New Password",
+ "incorrect_password": "Incorrect password",
+ "username_does_not_exist": "Username does not exist",
+ "account_name_should_start_with_a_letter":
+ "Account name should start with a letter.",
+ "account_name_should_be_shorter": "Account name should be shorter.",
+ "account_name_should_be_longer": "Account name should be longer.",
+ "account_name_should_have_only_letters_digits_or_dashes":
+ "Account name should have only letters, digits, periods or dashes.",
+ "cannot_increase_reward_of_post_within_the_last_minute_before_payout":
+ "Cannot increase reward of post within the last minute before payout",
+ "vote_currently_exists_user_must_be_indicate_a_to_reject_witness":
+ "vote currently exists, user must be indicate a desire to reject witness",
+ "only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes":
+ "Only one Steem account allowed per IP address every 10 minutes",
+ "resteem_this_post": "Resteem This Post",
+ "reblog": "Resteem",
+ "write_your_story": "Write your story...",
+ "remember_voting_and_posting_key": "Remember voting & posting key",
+ "auto_login_question_mark": "Auto login?",
+ "hide_private_key": "Hide private key",
+ "show_private_key": "Show private key",
+ "login_to_show": "Login to show",
+ "not_valid_email": "Not valid email",
+ "thank_you_for_being_an_early_visitor_to_APP_NAME":
+ "Thank you for being an early visitor to %(APP_NAME)s. We will get back to you at the earliest possible opportunity.",
+ "author_rewards": "Author rewards",
+ "curation_rewards": "Curation rewards",
+ "sorry_your_reddit_account_doesnt_have_enough_karma":
+ "Sorry, your Reddit account doesn't have enough Reddit Karma to qualify for a free sign up. Please add your email for a place on the waiting list",
+ "register_with_facebook": "Register with Facebook",
+ "or_click_the_button_below_to_register_with_facebook":
+ "Or click the button below to register with Facebook",
+ "server_returned_error": "server returned error",
+ "APP_NAME_support": "%(APP_NAME)s Support",
+ "please_email_questions_to": "Please email your questions to",
+ "next_7_strings_single_block": {
+ "authors_get_paid_when_people_like_you_upvote_their_post":
+ "Authors get paid when people like you upvote their post",
+ "if_you_enjoyed_what_you_read_earn_amount":
+ "If you enjoyed what you read here, create your account today and start earning FREE STEEM!",
+ "free_steem": "FREE STEEM!",
+ "sign_up_earn_steem": "Sign up now to earn "
+ },
+ "next_3_strings_together": {
+ "show_more": "Show more",
+ "show_less": "Show fewer",
+ "value_posts": "low value posts"
+ },
+ "read_only_mode":
+ "Due to server maintenance we are running in read only mode. We are sorry for the inconvenience.",
+ "tags_and_topics": "Tags",
+ "show_more_topics": "View all tags",
+ "basic": "Basic",
+ "advanced": "Advanced",
+ "views": {
+ "zero": "No Views",
+ "one": "%(count)s View",
+ "other": "%(count)s Views"
+ },
+ "responses": {
+ "zero": "No Responses",
+ "one": "%(count)s Response",
+ "other": "%(count)s Responses"
+ },
+ "post_key_warning": {
+ "confirm":
+ "You are about to publish a STEEM private key or master password. You will probably lose control of the associated account and all its funds.",
+ "warning":
+ "Legitimate users, including employees of Steemit Inc., will never ask you for a private key or master password.",
+ "checkbox": "I understand"
+ }
+ },
+ "navigation": {
+ "about": "About",
+ "explore": "Explore",
+ "APP_NAME_whitepaper": "%(APP_NAME)s Whitepaper",
+ "third_party_exchanges": "Third-party exchanges:",
+ "buy_LIQUID_TOKEN": "Buy %(LIQUID_TOKEN)s",
+ "sell_LIQUID_TOKEN": "Sell %(LIQUID_TOKEN)s",
+ "currency_market": "Currency Market",
+ "stolen_account_recovery": "Stolen Accounts Recovery",
+ "change_account_password": "Change Account Password",
+ "witnesses": "Witnesses",
+ "vote_for_witnesses": "Vote for Witnesses",
+ "privacy_policy": "Privacy Policy",
+ "terms_of_service": "Terms of Service",
+ "sign_up": "Sign up",
+ "learn_more": "Learn more",
+ "welcome": "Welcome",
+ "faq": "FAQ",
+ "shop": "The Steemit Shop",
+ "chat": "Steem Chat",
+ "app_center": "Apps Built on Steem",
+ "api_docs": "Steemit API Docs",
+ "bluepaper": "Steem Bluepaper",
+ "smt_whitepaper": "SMT Whitepaper",
+ "whitepaper": "Steem Whitepaper",
+ "intro_tagline": "Your voice is worth something",
+ "intro_paragraph":
+ "Get paid for good content. Post and upvote articles on Steemit to get your share of the daily rewards pool.",
+ "jobs": "Jobs at Steemit"
+ },
+ "main_menu": {
+ "hot": "Hot",
+ "trending": "Trending"
+ },
+ "reply_editor": {
+ "shorten_title": "Shorten title",
+ "exceeds_maximum_length": "Exceeds maximum length (%(maxKb)sKB)",
+ "including_the_category":
+ " (including the category '%(rootCategory)s')",
+ "use_limited_amount_of_tags":
+ "You have %(tagsLength)s tags total%(includingCategory)s. Please use only 5 in your post and category line.",
+ "are_you_sure_you_want_to_clear_this_form":
+ "Are you sure you want to clear this form?",
+ "uploading": "Uploading...",
+ "draft_saved": "Draft saved.",
+ "editor": "Editor",
+ "insert_images_by_dragging_dropping":
+ "Insert images by dragging & dropping, ",
+ "pasting_from_the_clipboard": "pasting from the clipboard, ",
+ "selecting_them": "selecting them",
+ "image_upload": "Image upload",
+ "power_up_100": "Power Up 100%%",
+ "default_50_50": "Default (50%% / 50%%)",
+ "decline_payout": "Decline Payout",
+ "check_this_to_auto_upvote_your_post":
+ "Check this to auto-upvote your post",
+ "markdown_styling_guide": "Markdown Styling Guide",
+ "or_by": "or by",
+ "title": "Title",
+ "update_post": "Update Post",
+ "markdown_not_supported": "Markdown is not supported here"
+ },
+ "category_selector_jsx": {
+ "tag_your_story":
+ "Tag (up to 5 tags), the first tag is your main category.",
+ "select_a_tag": "Select a tag",
+ "maximum_tag_length_is_24_characters":
+ "Maximum tag length is 24 characters",
+ "use_limited_amount_of_categories":
+ "Please use only %(amount)s categories",
+ "use_only_lowercase_letters": "Use only lowercase letters",
+ "use_one_dash": "Use only one dash",
+ "use_spaces_to_separate_tags": "Use spaces to separate tags",
+ "use_only_allowed_characters":
+ "Use only lowercase letters, digits and one dash",
+ "must_start_with_a_letter": "Must start with a letter",
+ "must_end_with_a_letter_or_number": "Must end with a letter or number"
+ },
+ "postfull_jsx": {
+ "this_post_is_not_available_due_to_a_copyright_claim":
+ "This post is not available due to a copyright claim.",
+ "share_on_facebook": "Share on Facebook",
+ "share_on_twitter": "Share on Twitter",
+ "share_on_linkedin": "Share on Linkedin",
+ "recent_password": "Recent Password",
+ "in_week_convert_DEBT_TOKEN_to_LIQUID_TOKEN":
+ "In 3.5 days, convert %(amount)s %(DEBT_TOKEN)s into %(LIQUID_TOKEN)s",
+ "view_the_full_context": "View the full context",
+ "view_the_direct_parent": "View the direct parent",
+ "you_are_viewing_a_single_comments_thread_from":
+ "You are viewing a single comment's thread from"
+ },
+ "market_jsx": {
+ "action": "Action",
+ "date_created": "Date Created",
+ "last_price": "Last price",
+ "24h_volume": "24h volume",
+ "spread": "Spread",
+ "total": "Total",
+ "available": "Available",
+ "lowest_ask": "Lowest ask",
+ "highest_bid": "Highest bid",
+ "buy_orders": "Buy Orders",
+ "sell_orders": "Sell Orders",
+ "trade_history": "Trade History",
+ "open_orders": "Open Orders",
+ "sell_amount_for_atleast":
+ "Sell %(amount_to_sell)s for at least %(min_to_receive)s (%(effectivePrice)s)",
+ "buy_atleast_amount_for":
+ "Buy at least %(min_to_receive)s for %(amount_to_sell)s (%(effectivePrice)s)",
+ "price_warning_above":
+ "This price is well above the current market price of %(marketPrice)s, are you sure?",
+ "price_warning_below":
+ "This price is well below the current market price of %(marketPrice)s, are you sure?",
+ "order_cancel_confirm": "Cancel order %(order_id)s from %(user)s?",
+ "order_cancelled": "Order %(order_id)s cancelled.",
+ "higher": "Higher",
+ "lower": "Lower",
+ "total_DEBT_TOKEN_SHORT_CURRENCY_SIGN":
+ "Total %(DEBT_TOKEN_SHORT)s (%(CURRENCY_SIGN)s)",
+ "order_placed": "Order placed: %(order)s"
+ },
+ "recoveraccountstep1_jsx": {
+ "begin_recovery": "Begin Recovery",
+ "not_valid": "Not valid",
+ "account_name_is_not_found": "Account name is not found",
+ "unable_to_recover_account_not_change_ownership_recently":
+ "We are unable to recover this account, it has not changed ownership recently.",
+ "password_not_used_in_last_days":
+ "This password was not used on this account in the last 30 days.",
+ "request_already_submitted_contact_support":
+ "Your request has been already submitted and we are working on it. Please contact %(SUPPORT_EMAIL)s for the status of your request.",
+ "recover_account_intro":
+ "From time to time, a Steemian's owner key may be compromised. Stolen Account Recovery gives the rightful account owner 30 days to recover their account from the moment the thief changed their owner key. Stolen Account Recovery can only be used on %(APP_URL)s if the account owner had previously listed '%(APP_NAME)s' as their account trustee and complied with %(APP_NAME)s's Terms of Service.",
+ "login_with_facebook_or_reddit_media_to_verify_identity":
+ "Please login with Facebook or Reddit to verify your identity",
+ "login_with_social_media_to_verify_identity":
+ "Please login with %(provider)s to verify your identity",
+ "enter_email_toverify_identity":
+ "We need to verify your identity. Please enter your email address below to begin the verification.",
+ "continue_with_email": "Continue with Email",
+ "thanks_for_submitting_request_for_account_recovery":
+ "Thanks for submitting your request for Account Recovery using %(APP_NAME)s's blockchain-based multi factor authentication. We will respond to you as quickly as possible, however, please expect there may be some delay in response due to high volume of emails. Please be prepared to verify your identity.",
+ "recovering_account": "Recovering account",
+ "recover_account": "Recover Account",
+ "checking_account_owner": "Checking account owner",
+ "sending_recovery_request": "Sending recovery request",
+ "cant_confirm_account_ownership":
+ "We can't confirm account ownership. Check your password",
+ "account_recovery_request_not_confirmed":
+ "Account recovery request is not confirmed yet, please get back later, thank you for your patience."
+ },
+ "user_profile": {
+ "unknown_account": "Unknown Account",
+ "user_hasnt_made_any_posts_yet":
+ "Looks like %(name)s hasn't made any posts yet!",
+ "user_hasnt_started_bloggin_yet":
+ "Looks like %(name)s hasn't started blogging yet!",
+ "user_hasnt_followed_anything_yet":
+ "Looks like %(name)s might not be following anyone yet! If %(name)s recently added new users to follow, their personalized feed will populate once new content is available.",
+ "user_hasnt_had_any_replies_yet": "%(name)s hasn't had any replies yet",
+ "looks_like_you_havent_posted_anything_yet":
+ "Looks like you haven't posted anything yet.",
+ "create_a_post": "Create a Post",
+ "explore_trending_articles": "Explore Trending Articles",
+ "read_the_quick_start_guide": "Read The Quick Start Guide",
+ "browse_the_faq": "Browse The FAQ",
+ "followers": "Followers",
+ "this_is_users_reputations_score_it_is_based_on_history_of_votes":
+ "This is %(name)s's reputation score.\n\nThe reputation score is based on the history of votes received by the account, and is used to hide low quality content.",
+ "follower_count": {
+ "zero": "No followers",
+ "one": "1 follower",
+ "other": "%(count)s followers"
+ },
+ "followed_count": {
+ "zero": "Not following anybody",
+ "one": "1 following",
+ "other": "%(count)s following"
+ },
+ "post_count": {
+ "zero": "No posts",
+ "one": "1 post",
+ "other": "%(count)s posts"
+ }
+ },
+ "authorrewards_jsx": {
+ "estimated_author_rewards_last_week":
+ "Estimated author rewards last week",
+ "author_rewards_history": "Author Rewards History"
+ },
+ "curationrewards_jsx": {
+ "estimated_curation_rewards_last_week":
+ "Estimated curation rewards last week",
+ "curation_rewards_history": "Curation Rewards History"
+ },
+ "post_jsx": {
+ "now_showing_comments_with_low_ratings":
+ "Now showing comments with low ratings",
+ "sort_order": "Sort Order",
+ "comments_were_hidden_due_to_low_ratings":
+ "Comments were hidden due to low ratings",
+ "comment_sort_order": {
+ "trending": "Trending",
+ "votes": "Votes",
+ "age": "Age",
+ "reputation": "Reputation"
+ }
+ },
+ "voting_jsx": {
+ "flagging_post_can_remove_rewards_the_flag_should_be_used_for_the_following":
+ "Flagging a post can remove rewards and make this material less visible. Some common reasons to flag",
+ "disagreement_on_rewards": "Disagreement on rewards",
+ "fraud_or_plagiarism": "Fraud or Plagiarism",
+ "hate_speech_or_internet_trolling": "Hate Speech or Internet Trolling",
+ "intentional_miss_categorized_content_or_spam":
+ "Intentional miss-categorized content or Spam",
+ "pending_payout": "Pending Payout $%(value)s",
+ "payout_declined": "Payout Declined",
+ "max_accepted_payout": "Max Accepted Payout $%(value)s",
+ "promotion_cost": "Promotion Cost $%(value)s",
+ "past_payouts": "Past Payouts $%(value)s",
+ "past_payouts_author": " - Author $%(value)s",
+ "past_payouts_curators": " - Curators $%(value)s",
+ "removing_your_vote": "Removing your vote",
+ "removing_your_vote_will_reset_curation_rewards_for_this_post":
+ "Removing your vote will reset your curation rewards for this post",
+ "changing_to_an_upvote": "Changing to an Up-Vote",
+ "changing_to_an_upvote_will_reset_curation_rewards_for_this_post":
+ "Changing to an Up-Vote will reset your curation rewards for this post",
+ "changing_to_a_downvote": "Changing to a Down-Vote",
+ "changing_to_a_downvote_will_reset_curation_rewards_for_this_post":
+ "Changing to a Down-Vote will reset your curation rewards for this post",
+ "confirm_flag": "Confirm Flag",
+ "and_more": "and %(count)s more",
+ "votes_plural": {
+ "one": "%(count)s vote",
+ "other": "%(count)s votes"
+ }
+ },
+ "witnesses_jsx": {
+ "witness_thread": "witness thread",
+ "top_witnesses": "Witness Voting",
+ "you_have_votes_remaining": {
+ "zero": "You have no votes remaining",
+ "one": "You have 1 vote remaining",
+ "other": "You have %(count)s votes remaining"
+ },
+ "you_can_vote_for_maximum_of_witnesses":
+ "You can vote for a maximum of 30 witnesses",
+ "witness": "Witness",
+ "information": "Information",
+ "if_you_want_to_vote_outside_of_top_enter_account_name":
+ "If you would like to vote for a witness outside of the top 50, enter the account name below to cast a vote",
+ "set_witness_proxy":
+ "You can also choose a proxy that will vote for witnesses for you. This will reset your current witness selection.",
+ "witness_set":
+ "You have set a voting proxy. If you would like to re-enable manual voting, please clear your proxy.",
+ "witness_proxy_current": "Your current proxy is",
+ "witness_proxy_set": "Set proxy",
+ "witness_proxy_clear": "Clear proxy",
+ "proxy_update_error": "Your proxy was not updated"
+ },
+ "votesandcomments_jsx": {
+ "no_responses_yet_click_to_respond":
+ "No responses yet. Click to respond.",
+ "response_count_tooltip": {
+ "zero": "no responses. Click to respond.",
+ "one": "1 response. Click to respond.",
+ "other": "%(count)s responses. Click to respond."
+ },
+ "vote_count": {
+ "zero": "no votes",
+ "one": "1 vote",
+ "other": "%(count)s votes"
+ }
+ },
+ "userkeys_jsx": {
+ "public": "Public",
+ "private": "Private",
+ "public_something_key": "Public %(key)s Key",
+ "private_something_key": "Private %(key)s Key",
+ "posting_key_is_required_it_should_be_different":
+ "The posting key is used for posting and voting. It should be different from the active and owner keys.",
+ "the_active_key_is_used_to_make_transfers_and_place_orders":
+ "The active key is used to make transfers and place orders in the internal market.",
+ "the_owner_key_is_required_to_change_other_keys":
+ "The owner key is the master key for the account and is required to change the other keys.",
+ "the_private_key_or_password_should_be_kept_offline":
+ "The private key or password for the owner key should be kept offline as much as possible.",
+ "the_memo_key_is_used_to_create_and_read_memos":
+ "The memo key is used to create and read memos."
+ },
+ "suggestpassword_jsx": {
+ "APP_NAME_cannot_recover_passwords_keep_this_page_in_a_secure_location":
+ "%(APP_NAME)s cannot recover passwords. Keep this page in a secure location, such as a fireproof safe or safety deposit box.",
+ "APP_NAME_password_backup": "%(APP_NAME)s Password Backup",
+ "APP_NAME_password_backup_required":
+ "%(APP_NAME)s Password Backup (required)",
+ "after_printing_write_down_your_user_name":
+ "After printing, write down your user name"
+ },
+ "converttosteem_jsx": {
+ "your_existing_DEBT_TOKEN_are_liquid_and_transferable":
+ "Your existing %(DEBT_TOKEN)s are liquid and transferable. Instead you may wish to trade %(DEBT_TOKEN)s directly in this site under %(link)s or transfer to an external market.",
+ "this_is_a_price_feed_conversion":
+ "This is a price feed conversion. The 3.5 day delay is necessary to prevent abuse from gaming the price feed average.",
+ "convert_to_LIQUID_TOKEN": "Convert to %(LIQUID_TOKEN)s",
+ "DEBT_TOKEN_will_be_unavailable":
+ "This action will take place 3.5 days from now and can not be canceled. These %(DEBT_TOKEN)s will immediately become unavailable."
+ },
+ "tips_js": {
+ "liquid_token":
+ "Tradeable tokens that may be transferred anywhere at anytime. %(LIQUID_TOKEN)s can be converted to %(VESTING_TOKEN)s in a process called powering up.",
+ "influence_token":
+ "Influence tokens which give you more control over post payouts and allow you to earn on curation rewards.",
+ "estimated_value":
+ "The estimated value is based on an average value of %(LIQUID_TOKEN)s in US dollars.",
+ "non_transferable":
+ "%(VESTING_TOKEN)s is non-transferable and requires 3 months (13 payments) to convert back to %(LIQUID_TOKEN)s.",
+ "converted_VESTING_TOKEN_can_be_sent_to_yourself_but_can_not_transfer_again":
+ "Converted %(VESTING_TOKEN)s can be sent to yourself or someone else but can not transfer again without converting back to %(LIQUID_TOKEN)s.",
+ "part_of_your_steem_power_is_currently_delegated":
+ "Part of %(user_name)s's STEEM POWER is currently delegated. Delegation is donated for influence or to help new users perform actions on steemit. Your delegation amount can fluctuate."
+ },
+ "promote_post_jsx": {
+ "promote_post": "Promote Post",
+ "spend_your_DEBT_TOKEN_to_advertise_this_post":
+ "Spend your %(DEBT_TOKEN)s's to advertise this post in the promoted content section",
+ "you_successfully_promoted_this_post":
+ "You successfully promoted this post",
+ "this_post_was_hidden_due_to_low_ratings":
+ "This post was hidden due to low ratings"
+ },
+ "about_jsx": {
+ "about_app": "About %(APP_NAME)s",
+ "about_app_details":
+ "%(APP_NAME)s is a social media platform where everyone gets paid for creating and curating content. It leverages a robust digital points system, called Steem, that supports real value for digital rewards through market price discovery and liquidity.",
+ "learn_more_at_app_url": "Learn more at %(APP_URL)s",
+ "resources": "Resources"
+ },
+ "markdownviewer_jsx": {
+ "images_were_hidden_due_to_low_ratings":
+ "Images were hidden due to low ratings."
+ },
+ "postsummary_jsx": {
+ "resteemed": "resteemed",
+ "resteemed_by": "Resteemed by",
+ "reveal_it": "Reveal this post",
+ "adjust_your": "adjust your",
+ "display_preferences": "display preferences",
+ "create_an_account": "create an account",
+ "to_save_your_preferences": "to save your preferences"
+ },
+ "posts_index": {
+ "empty_feed_1": "Looks like you haven't followed anything yet",
+ "empty_feed_2":
+ "If you recently added new users to follow, your personalized feed will populate once new content is available",
+ "empty_feed_3": "Explore Trending Articles",
+ "empty_feed_4": "Read The Quick Start Guide",
+ "empty_feed_5": "Browse The FAQ"
+ },
+ "transferhistoryrow_jsx": {
+ "to_savings": "to savings",
+ "from_savings": "from savings",
+ "cancel_transfer_from_savings":
+ "Cancel transfer from savings (request %(request_id)s)",
+ "stop_power_down": "Stop power down",
+ "withdraw_vesting": "Start power down of %(powerdown_vests)s STEEM",
+ "start_power_down_of": "Start power down of",
+ "receive_interest_of": "Receive interest of",
+ "bad_actor_caution": "Caution",
+ "bad_actor_explained":
+ "This is from an account that looks fraudulent. If you wish, you may temporarily reveal this memo which may contain dangerous links.",
+ "bad_actor_reveal_memo": "I understand the risk; show anyway.",
+ "from_negative_rep_user_caution": "Caution",
+ "from_negative_rep_user_explained":
+ "This is from an account with a bad reputation. If you wish, you may temporarily reveal this memo which may contain dangerous links.",
+ "from_negative_rep_user_reveal_memo":
+ "I understand the risk; show anyway.",
+ "curation_reward": "%(curation_reward)s STEEM POWER for ",
+ "author_reward":
+ "%(sbd_payout)s%(steem_payout)s and %(author_reward)s STEEM POWER for ",
+ "claim_reward_balance": {
+ "three_rewards":
+ "Claim rewards: %(first_reward)s, %(second_reward)s and %(third_reward)s",
+ "two_rewards":
+ "Claim rewards: %(first_reward)s and %(second_reward)s",
+ "one_reward": "Claim rewards: %(reward)s"
+ },
+ "interest": "Receive interest of %(interest)s",
+ "fill_convert_request":
+ "Fill convert request: %(amount_in)s for %(amount_out)s",
+ "fill_order": {
+ "filled_by_current_owner":
+ "Paid %(open_pays)s for %(current_pays)s",
+ "open_owner_filled_my_order":
+ "Paid %(current_pays)s for %(open_pays)s"
+ },
+ "comment_benefactor_reward":
+ "%(benefactor_reward)s STEEM POWER for %(author)s/%(permlink)s",
+ "transfer_to_vesting": {
+ "from_self": {
+ "no_to": "Transfer %(amount)s to STEEM POWER",
+ "to_someone": "Transfer %(amount)s STEEM POWER to "
+ },
+ "to_self": "Receive %(amount)s STEEM POWER from ",
+ "from_user_to_user":
+ " Transfer %(amount)s STEEM POWER from %(from) to "
+ },
+ "transfer": {
+ "from_self": {
+ "to_savings": "Transfer to savings %(amount)s to ",
+ "from_savings": "Transfer from savings %(amount)s to ",
+ "not_savings": "Transfer %(amount)s to "
+ },
+ "to_self": {
+ "to_savings": "Receive from savings %(amount)s from ",
+ "from_savings": "Transfer from savings %(amount)s from ",
+ "not_savings": "Transfer %(amount)s from "
+ },
+ "to_someone_from_someone": {
+ "to_savings":
+ "Transfer to savings %(amount)s from %(from)s to %(to)s",
+ "from_savings":
+ "Transfer from savings %(amount)s from %(from)s to %(to)s",
+ "not_savings": "Transfer %(amount)s from %(from)s to %(to)s"
+ }
+ },
+ "request_id": "Request ID: %(request_id)s"
+ },
+ "savingswithdrawhistory_jsx": {
+ "cancel_this_withdraw_request": "Cancel this withdraw request?",
+ "pending_savings_withdrawals": "PENDING SAVINGS WITHDRAWS",
+ "withdraw": "Withdraw %(amount)s",
+ "to": "to %(to)s",
+ "from_to": "from %(from)s to %(to)s"
+ },
+ "explorepost_jsx": {
+ "copied": "Copied!",
+ "copy": "COPY",
+ "alternative_sources": "Alternative Sources"
+ },
+ "header_jsx": {
+ "home": "home",
+ "create_a_post": "Create a post",
+ "change_account_password": "Change Account Password",
+ "create_account": "Create Account",
+ "stolen_account_recovery": "Stolen Account Recovery",
+ "people_following": "People following %(username)s",
+ "people_followed_by": "People followed by %(username)s",
+ "curation_rewards_by": "Curation rewards by %(username)s",
+ "author_rewards_by": "Author rewards by %(username)s",
+ "replies_to": "Replies to %(username)s",
+ "comments_by": "Comments by %(username)s"
+ },
+ "loginform_jsx": {
+ "you_need_a_private_password_or_key":
+ "You need a private password or key (not a public key)",
+ "cryptography_test_failed": "Cryptography test failed",
+ "unable_to_log_you_in":
+ "We will be unable to log you in with this browser.",
+ "the_latest_versions_of": "The latest versions of ",
+ "are_well_tested_and_known_to_work_with":
+ "are well tested and known to work with %(APP_URL)s.",
+ "due_to_server_maintenance":
+ "Due to server maintenance we are running in read only mode. We are sorry for the inconvenience.",
+ "login_to_vote": "Login to Vote",
+ "login_to_post": "Login to Post",
+ "login_to_comment": "Login to Comment",
+ "posting": "Posting",
+ "active_or_owner": "Active or Owner",
+ "this_password_is_bound_to_your_account_owner_key":
+ "This password is bound to your account's owner key and can not be used to login to this site.",
+ "however_you_can_use_it_to": "However, you can use it to ",
+ "update_your_password": "update your password",
+ "to_obtain_a_more_secure_set_of_keys":
+ "to obtain a more secure set of keys.",
+ "this_password_is_bound_to_your_account_active_key":
+ "This password is bound to your account's active key and can not be used to login to this page.",
+ "you_may_use_this_active_key_on_other_more":
+ "You may use this active key on other more secure pages like the Wallet or Market pages.",
+ "you_account_has_been_successfully_created":
+ "You account has been successfully created!",
+ "you_account_has_been_successfully_recovered":
+ "You account has been successfully recovered!",
+ "password_update_succes":
+ "The password for %(accountName)s was successfully updated",
+ "password_info":
+ "This password or private key was entered incorrectly. There is probably a handwriting or data-entry error. Hint: A password or private key generated by Steemit will never contain 0 (zero), O (capital o), I (capital i) and l (lower case L) characters.",
+ "enter_your_username": "Enter your username",
+ "password_or_wif": "Password or WIF",
+ "this_operation_requires_your_key_or_master_password":
+ "This operation requires your %(authType)s key or Master password.",
+ "keep_me_logged_in": "Keep me logged in",
+ "amazing_community": "amazing community",
+ "to_comment_and_reward_others": " to comment and reward others.",
+ "signup_button": "Sign up now to earn ",
+ "signup_button_emphasis": "FREE STEEM!",
+ "sign_up_get_steem": "Sign up. Get STEEM",
+ "returning_users": "Returning Users: ",
+ "join_our": "Join our"
+ },
+ "chainvalidation_js": {
+ "account_name_should_not_be_empty": "Account name should not be empty.",
+ "account_name_should_be_longer": "Account name should be longer.",
+ "account_name_should_be_shorter": "Account name should be shorter.",
+ "each_account_segment_should_start_with_a_letter":
+ "Each account segment should start with a letter.",
+ "each_account_segment_should_have_only_letters_digits_or_dashes":
+ "Each account segment should have only letters, digits, or dashes.",
+ "each_account_segment_should_have_only_one_dash_in_a_row":
+ "Each account segment should have only one dash in a row.",
+ "each_account_segment_should_end_with_a_letter_or_digit":
+ "Each account segment should end with a letter or digit.",
+ "each_account_segment_should_be_longer":
+ "Each account segment should be longer.",
+ "verified_exchange_no_memo":
+ "You must include a memo for your exchange transfer.",
+ "badactor":
+ "Use caution sending to this account. Please double check your spelling for possible phishing.",
+ "memo_has_privatekey":
+ "Please do not include what appears to be a private key or password.",
+ "memo_is_privatekey": "Do not use private keys in memos.",
+ "memo_is_password": "Do not use passwords in memos."
+ },
+ "settings_jsx": {
+ "invalid_url": "Invalid URL",
+ "name_is_too_long": "Name is too long",
+ "name_must_not_begin_with": "Name must not begin with @",
+ "about_is_too_long": "About is too long",
+ "location_is_too_long": "Location is too long",
+ "website_url_is_too_long": "Website URL is too long",
+ "public_profile_settings": "Public Profile Settings",
+ "preferences": "Preferences",
+ "not_safe_for_work_nsfw_content": "Not safe for work (NSFW) content",
+ "always_hide": "Always hide",
+ "always_warn": "Always warn",
+ "always_show": "Always show",
+ "muted_users": "Muted Users",
+ "update": "Update",
+ "profile_image_url": "Profile picture url",
+ "cover_image_url": "Cover image url",
+ "profile_name": "Display Name",
+ "profile_about": "About",
+ "profile_location": "Location",
+ "profile_website": "Website",
+ "saved": "Saved!"
+ },
+ "transfer_jsx": {
+ "amount_is_in_form": "Amount is in the form 99999.999",
+ "insufficient_funds": "Insufficient funds",
+ "use_only_3_digits_of_precison": "Use only 3 digits of precison",
+ "send_to_account": "Send to account",
+ "asset": "Asset",
+ "this_memo_is_private": "This memo is private",
+ "this_memo_is_public": "This memo is public",
+ "convert_to_VESTING_TOKEN": "Convert to %(VESTING_TOKEN)s",
+ "balance_subject_to_3_day_withdraw_waiting_period":
+ "Balance subject to 3 day withdraw waiting period,",
+ "move_funds_to_another_account":
+ "Move funds to another %(APP_NAME)s account.",
+ "protect_funds_by_requiring_a_3_day_withdraw_waiting_period":
+ "Protect funds by requiring a 3 day withdraw waiting period.",
+ "withdraw_funds_after_the_required_3_day_waiting_period":
+ "Withdraw funds after the required 3 day waiting period.",
+ "from": "From",
+ "to": "To",
+ "asset_currently_collecting":
+ "%(asset)s currently collecting %(interest)s%% APR.",
+ "beware_of_spam_and_phishing_links":
+ "Beware of spam and phishing links in transfer memos. Do not open links from users you do not trust. Do not provide your private keys to any third party websites.",
+ "autocomplete_previous_transfers": "previous transfers",
+ "autocomplete_user_following": "following"
+ },
+ "userwallet_jsx": {
+ "transfer": "Transfer",
+ "conversion_complete_tip": "Will complete on %(date)s",
+ "in_conversion": "%(amount)s in conversion",
+ "transfer_to_savings": "Transfer to Savings",
+ "power_up": "Power Up",
+ "power_down": "Power Down",
+ "market": "Market",
+ "convert_to_LIQUID_TOKEN": "Convert to %(LIQUID_TOKEN)s",
+ "withdraw_LIQUID_TOKEN": "Withdraw %(LIQUID_TOKEN)s",
+ "withdraw_DEBT_TOKENS": "Withdraw %(DEBT_TOKENS)s",
+ "tokens_worth_about_1_of_LIQUID_TICKER":
+ "Tokens worth about $1.00 of %(LIQUID_TICKER)s, currently collecting %(sbdInterest)s%% APR.",
+ "savings": "SAVINGS",
+ "estimated_account_value": "Estimated Account Value",
+ "next_power_down_is_scheduled_to_happen":
+ "The next power down is scheduled to happen",
+ "transfers_are_temporary_disabled": "Transfers are temporary disabled.",
+ "history": "HISTORY",
+ "redeem_rewards": "Redeem Rewards (Transfer to Balance)",
+ "buy_steem_or_steem_power": "Buy STEEM or STEEM POWER"
+ },
+ "powerdown_jsx": {
+ "power_down": "Power Down",
+ "amount": "Amount",
+ "already_power_down":
+ "You are already powering down %(AMOUNT)s %(LIQUID_TICKER)s (%(WITHDRAWN)s %(LIQUID_TICKER)s paid out so far). Note that if you change the power down amount the payout schedule will reset.",
+ "delegating":
+ "You are delegating %(AMOUNT)s %(LIQUID_TICKER)s. That amount is locked up and not available to power down until the delegation is removed and a full reward period has passed.",
+ "per_week": "That's ~%(AMOUNT)s %(LIQUID_TICKER)s per week.",
+ "warning":
+ "Leaving less than %(AMOUNT)s %(VESTING_TOKEN)s in your account is not recommended and can leave your account in a unusable state.",
+ "error": "Unable to power down (ERROR: %(MESSAGE)s)"
+ },
+ "checkloginowner_jsx": {
+ "your_password_permissions_were_reduced":
+ "Your password permissions were reduced",
+ "if_you_did_not_make_this_change":
+ "If you did not make this change please",
+ "ownership_changed_on": "Ownership Changed On ",
+ "deadline_for_recovery_is": "Deadline for recovery is",
+ "i_understand_dont_show_again": "I understand, don't show me again"
+ },
+ "termsagree_jsx": {
+ "i_agree_to_these_terms": "I agree to these terms",
+ "cancel": "Cancel"
+ },
+ "confirmtransactionform_jsx": {
+ "confirm": "Confirm %(transactionType)s"
}
- },
- "userkeys_jsx": {
- "public": "Public",
- "private": "Private",
- "public_something_key": "Public %(key)s Key",
- "private_something_key": "Private %(key)s Key",
- "posting_key_is_required_it_should_be_different": "The posting key is used for posting and voting. It should be different from the active and owner keys.",
- "the_active_key_is_used_to_make_transfers_and_place_orders": "The active key is used to make transfers and place orders in the internal market.",
- "the_owner_key_is_required_to_change_other_keys": "The owner key is the master key for the account and is required to change the other keys.",
- "the_private_key_or_password_should_be_kept_offline": "The private key or password for the owner key should be kept offline as much as possible.",
- "the_memo_key_is_used_to_create_and_read_memos": "The memo key is used to create and read memos."
- },
- "suggestpassword_jsx": {
- "APP_NAME_cannot_recover_passwords_keep_this_page_in_a_secure_location": "%(APP_NAME)s cannot recover passwords. Keep this page in a secure location, such as a fireproof safe or safety deposit box.",
- "APP_NAME_password_backup": "%(APP_NAME)s Password Backup",
- "APP_NAME_password_backup_required": "%(APP_NAME)s Password Backup (required)",
- "after_printing_write_down_your_user_name": "After printing, write down your user name"
- },
- "converttosteem_jsx": {
- "your_existing_DEBT_TOKEN_are_liquid_and_transferable": "Your existing %(DEBT_TOKEN)s are liquid and transferable. Instead you may wish to trade %(DEBT_TOKEN)s directly in this site under %(link)s or transfer to an external market.",
- "this_is_a_price_feed_conversion": "This is a price feed conversion. The 3.5 day delay is necessary to prevent abuse from gaming the price feed average",
- "convert_to_LIQUID_TOKEN": "Convert to %(LIQUID_TOKEN)s",
- "DEBT_TOKEN_will_be_unavailable": "This action will take place 3.5 days from now and can not be canceled. These %(DEBT_TOKEN)s will immediately become unavailable"
- },
- "tips_js": {
- "liquid_token": "Tradeable tokens that may be transferred anywhere at anytime. %(LIQUID_TOKEN)s can be converted to %(VESTING_TOKEN)s in a process called powering up.",
- "influence_token": "Influence tokens which give you more control over post payouts and allow you to earn on curation rewards.",
- "estimated_value": "The estimated value is based on an average value of %(LIQUID_TOKEN)s in US dollars.",
- "non_transferable": "%(VESTING_TOKEN)s is non-transferable and requires 3 months (13 payments) to convert back to %(LIQUID_TOKEN)s.",
- "converted_VESTING_TOKEN_can_be_sent_to_yourself_but_can_not_transfer_again": "Converted %(VESTING_TOKEN)s can be sent to yourself or someone else but can not transfer again without converting back to %(LIQUID_TOKEN)s.",
- "part_of_your_steem_power_is_currently_delegated": "Part of your STEEM POWER is currently delegated to you. Delegation is donated for influence or to help new users perform actions on steemit. Your delegation amount can fluctuate."
- },
- "promote_post_jsx": {
- "promote_post": "Promote Post",
- "spend_your_DEBT_TOKEN_to_advertise_this_post": "Spend your %(DEBT_TOKEN)s's to advertise this post in the promoted content section",
- "you_successfully_promoted_this_post": "You successfully promoted this post",
- "this_post_was_hidden_due_to_low_ratings": "This post was hidden due to low ratings"
- },
- "about_jsx": {
- "about_app": "About %(APP_NAME)s",
- "about_app_details": "%(APP_NAME)s is a social media platform where everyone gets paid for creating and curating content. It leverages a robust digital points system, called Steem, that supports real value for digital rewards through market price discovery and liquidity.",
- "learn_more_at_app_url": "Learn more at %(APP_URL)s",
- "resources": "Resources"
- },
- "markdownviewer_jsx": {
- "images_were_hidden_due_to_low_ratings": "Images were hidden due to low ratings."
- },
- "postsummary_jsx": {
- "resteemed": "resteemed",
- "resteemed_by": "Resteemed by",
- "reveal_it": "Reveal this post",
- "adjust_your": "adjust your",
- "display_preferences": "display preferences",
- "create_an_account": "create an account",
- "to_save_your_preferences": "to save your preferences"
- },
- "posts_index": {
- "empty_feed_1": "Looks like you haven't followed anything yet",
- "empty_feed_2": "If you recently added new users to follow, your personalized feed will populate once new content is available",
- "empty_feed_3": "Explore Trending Articles",
- "empty_feed_4": "Read The Quick Start Guide",
- "empty_feed_5": "Browse The FAQ"
- },
- "transferhistoryrow_jsx": {
- "to_savings": "to savings",
- "from_savings": "from savings",
- "cancel_transfer_from_savings": "Cancel transfer from savings",
- "stop_power_down": "Stop power down",
- "start_power_down_of": "Start power down of",
- "receive_interest_of": "Receive interest of"
- },
- "savingswithdrawhistory_jsx": {
- "cancel_this_withdraw_request": "Cancel this withdraw request?",
- "pending_savings_withdrawals": "PENDING SAVINGS WITHDRAWS",
- "withdraw": "Withdraw %(amount)s",
- "to": "to %(to)s",
- "from_to": "from %(from)s to %(to)s"
- },
- "explorepost_jsx": {
- "copied": "Copied!",
- "copy": "COPY",
- "alternative_sources": "Alternative Sources"
- },
- "header_jsx": {
- "home": "home",
- "create_a_post": "Create a post",
- "change_account_password": "Change Account Password",
- "create_account": "Create Account",
- "stolen_account_recovery": "Stolen Account Recovery",
- "people_following": "People following",
- "people_followed_by": "People followed by",
- "curation_rewards_by": "Curation rewards by",
- "author_rewards_by": "Author rewards by",
- "replies_to": "Replies to",
- "comments_by": "Comments by"
- },
- "loginform_jsx": {
- "you_need_a_private_password_or_key": "You need a private password or key (not a public key)",
- "cryptography_test_failed": "Cryptography test failed",
- "unable_to_log_you_in": "We will be unable to log you in with this browser.",
- "the_latest_versions_of": "The latest versions of ",
- "are_well_tested_and_known_to_work_with": "are well tested and known to work with %(APP_URL)s.",
- "due_to_server_maintenance": "Due to server maintenance we are running in read only mode. We are sorry for the inconvenience.",
- "login_to_vote": "Login to Vote",
- "login_to_post": "Login to Post",
- "login_to_comment": "Login to Comment",
- "posting": "Posting",
- "active_or_owner": "Active or Owner",
- "this_password_is_bound_to_your_account_owner_key": "This password is bound to your account's owner key and can not be used to login to this site.",
- "however_you_can_use_it_to": "However, you can use it to ",
- "update_your_password": "update your password",
- "to_obtain_a_more_secure_set_of_keys": "to obtain a more secure set of keys.",
- "this_password_is_bound_to_your_account_active_key": "This password is bound to your account's active key and can not be used to login to this page.",
- "you_may_use_this_active_key_on_other_more": "You may use this active key on other more secure pages like the Wallet or Market pages.",
- "you_account_has_been_successfully_created": "You account has been successfully created!",
- "you_account_has_been_successfully_recovered": "You account has been successfully recovered!",
- "password_update_succes": "The password for %(accountName)s was successfully updated",
- "password_info": "This password or private key was entered incorrectly. There is probably a handwriting or data-entry error. Hint: A password or private key generated by Steemit will never contain 0 (zero), O (capital o), I (capital i) and l (lower case L) characters.",
- "enter_your_username": "Enter your username",
- "password_or_wif": "Password or WIF",
- "this_operation_requires_your_key_or_master_password": "This operation requires your %(authType)s key or Master password.",
- "keep_me_logged_in": "Keep me logged in",
- "amazing_community": "amazing community",
- "to_comment_and_reward_others": " to comment and reward others.",
- "signup_button": "Sign up now to earn ",
- "signup_button_emphasis": "FREE STEEM!",
- "sign_up_get_steem": "Sign up. Get STEEM",
- "returning_users": "Returning Users: ",
- "join_our": "Join our"
- },
- "chainvalidation_js": {
- "account_name_should": "Account name should ",
- "not_be_empty": "not be empty.",
- "be_longer": "be longer.",
- "be_shorter": "be shorter.",
- "each_account_segment_should": "Each account segment should ",
- "start_with_a_letter": "start with a letter.",
- "have_only_letters_digits_or_dashes": "have only letters, digits, or dashes.",
- "have_only_one_dash_in_a_row": "have only one dash in a row.",
- "end_with_a_letter_or_digit": "end with a letter or digit.",
- "verified_exchange_no_memo": "You must include a memo for your exchange transfer."
- },
- "settings_jsx": {
- "invalid_url": "Invalid URL",
- "name_is_too_long": "Name is too long",
- "name_must_not_begin_with": "Name must not begin with @",
- "about_is_too_long": "About is too long",
- "location_is_too_long": "Location is too long",
- "website_url_is_too_long": "Website URL is too long",
- "public_profile_settings": "Public Profile Settings",
- "private_post_display_settings": "Private Post Display Settings",
- "not_safe_for_work_nsfw_content": "Not safe for work (NSFW) content",
- "always_hide": "Always hide",
- "always_warn": "Always warn",
- "always_show": "Always show",
- "muted_users": "Muted Users",
- "update": "Update",
- "profile_image_url": "Profile picture url",
- "cover_image_url": "Cover image url",
- "profile_name": "Display Name",
- "profile_about": "About",
- "profile_location": "Location",
- "profile_website": "Website"
- },
- "transfer_jsx": {
- "amount_is_in_form": "Amount is in the form 99999.999",
- "insufficient_funds": "Insufficient funds",
- "use_only_3_digits_of_precison": "Use only 3 digits of precison",
- "send_to_account": "Send to account",
- "asset": "Asset",
- "this_memo_is_private": "This memo is private",
- "this_memo_is_public": "This memo is public",
- "convert_to_VESTING_TOKEN": "Convert to %(VESTING_TOKEN)s",
- "balance_subject_to_3_day_withdraw_waiting_period": "Balance subject to 3 day withdraw waiting period,",
- "move_funds_to_another_account": "Move funds to another %(APP_NAME)s account.",
- "protect_funds_by_requiring_a_3_day_withdraw_waiting_period": "Protect funds by requiring a 3 day withdraw waiting period.",
- "withdraw_funds_after_the_required_3_day_waiting_period": "Withdraw funds after the required 3 day waiting period.",
- "from": "From",
- "to": "To",
- "asset_currently_collecting": "%(asset)s currently collecting %(interest)s%% APR.",
- "beware_of_spam_and_phishing_links": "Beware of spam and phishing links in transfer memos. Do not open links from users you do not trust. Do not provide your private keys to any third party websites."
- },
- "userwallet_jsx": {
- "conversion_complete_tip": "Will complete on",
- "in_conversion": "%(amount)s in conversion",
- "transfer_to_savings": "Transfer to Savings",
- "power_up": "Power Up",
- "power_down": "Power Down",
- "market": "Market",
- "convert_to_LIQUID_TOKEN": "Convert to %(LIQUID_TOKEN)s",
- "withdraw_LIQUID_TOKEN": "Withdraw %(LIQUID_TOKEN)s",
- "withdraw_DEBT_TOKENS": "Withdraw %(DEBT_TOKENS)s",
- "tokens_worth_about_1_of_LIQUID_TICKER": "Tokens worth about $1.00 of %(LIQUID_TICKER)s, currently collecting %(sbdInterest)s%% APR.",
- "savings": "SAVINGS",
- "estimated_account_value": "Estimated Account Value",
- "next_power_down_is_scheduled_to_happen": "The next power down is scheduled to happen",
- "transfers_are_temporary_disabled": "Transfers are temporary disabled.",
- "history": "HISTORY",
- "redeem_rewards": "Redeem Rewards (Transfer to Balance)",
- "buy_steem_or_steem_power": "Buy STEEM or STEEM POWER"
- },
- "powerdown_jsx": {
- "power_down": "Power Down",
- "amount": "Amount",
- "already_power_down": "You are already powering down %(AMOUNT)s %(LIQUID_TICKER)s (%(WITHDRAWN)s %(LIQUID_TICKER)s paid out so far). Note that if you change the power down amount the payout schedule will reset.",
- "delegating": "You are delegating %(AMOUNT)s %(LIQUID_TICKER)s. That amount is locked up and not available to power down until the delegation is removed and a full reward period has passed.",
- "per_week": "That's ~%(AMOUNT)s %(LIQUID_TICKER)s per week.",
- "warning": "Leaving less than %(AMOUNT)s %(VESTING_TOKEN)s in your account is not recommended and can leave your account in a unusable state.",
- "error": "Unable to power down (ERROR: %(MESSAGE)s)"
- },
- "checkloginowner_jsx": {
- "your_password_permissions_were_reduced": "Your password permissions were reduced",
- "if_you_did_not_make_this_change": "If you did not make this change please",
- "ownership_changed_on": "Ownership Changed On ",
- "deadline_for_recovery_is": "Deadline for recovery is",
- "i_understand_dont_show_again": "I understand, don't show me again"
- }
}
diff --git a/src/app/locales/es.json b/src/app/locales/es.json
index c6867951ae73086a2debc98e4ac674efd8ff2bf7..a0118140966dd525ac6164481529103c3763ef64 100644
--- a/src/app/locales/es.json
+++ b/src/app/locales/es.json
@@ -1,648 +1,778 @@
{
- "g": {
- "age": "edad",
- "amount": "Cantidad",
- "and": "y",
- "are_you_sure": "¿Estás seguro?",
- "ask": "Preguntar",
- "balance": "Saldo",
- "balances": "Saldos",
- "bid": "Oferta",
- "blog": "Blog",
- "browse": "Navegar",
- "buy": "Comprar",
- "buy_or_sell": "Comprar o Vender",
- "by": "por",
- "cancel": "Cancelar",
- "change_password": "Cambiar Contraseña",
- "choose_language": "Elegir Idioma",
- "clear": "Limpiar",
- "close": "Cerrar",
- "collapse_or_expand": "Plegar/Expandir",
- "comments": "Comentarios",
- "confirm": "Confirmar",
- "convert": "Convertir",
- "date": "Fecha",
- "delete": "Borrar",
- "dismiss": "Descartar",
- "edit": "Editar",
- "email": "Email",
- "feed": "Favoritos",
- "follow": "Seguir",
- "for": "para",
- "from": "de",
- "go_back": "Volver",
- "hide": "Ocultar",
- "in": "en",
- "in_reply_to": "en respuesta a",
- "insufficient_balance": "Saldo insuficiente",
- "invalid_amount": "Cantidad inválida",
- "joined": "Unió",
- "loading": "Cargando",
- "login": "Iniciar sesión",
- "logout": "Cerrar sesión",
- "memo": "Memo",
- "mute": "Silenciar",
- "new": "nuevo",
- "newer": "Nuevo",
- "next": "Próximo",
- "no": "No",
- "ok": "Ok",
- "older": "Más viejo",
- "or": "o",
- "order_placed": "Órden dispuesta",
- "password": "Contraseña",
- "payouts": "Pagos",
- "permissions": "Permisos",
- "phishy_message": "Link expanded to plain text; beware of a potential phishing attempt",
- "post": "Publicación",
- "post_as": "Publicar como",
- "posts": "Publicaciones",
- "powered_up_100": "Powered Up 100 %%",
- "preview": "Vista previa",
- "previous": "Anterior",
- "price": "Precio",
- "print": "Imprimir",
- "promote": "Promocionar",
- "promoted": "promocionado",
- "re": "RE",
- "re_to": "RE %(topic)s",
- "recent_password": "Contraseña reciente",
- "receive": "Recibir",
- "remove": "Quitar",
- "remove_vote": "Quitar voto",
- "replied_to": "Respondido a %(account)s",
- "replies": "Respuestas",
- "reply": "Respuesta",
- "reply_count": {
- "zero": "Sin respuestas",
- "one": "1 respuesta",
- "other": "%(count)s respuestas"
- },
- "reputation": "Reputación",
- "reveal_comment": "Mostrar Comentario",
- "request": "solicitud",
- "required": "Requerido",
- "rewards": "Recompensa",
- "save": "Guardar",
- "saved": "Guardado",
- "search": "Buscar",
- "sell": "Vender",
- "settings": "Configuración",
- "share_this_post": "Compartir esta publicación",
- "show": "Mostrar",
- "sign_in": "Registrarse",
- "sign_up": "Inscribirse",
- "since": "desde",
- "submit": "Enviar",
- "power_up": "Power Up",
- "submit_a_story": "Publicar",
- "tag": "Etiqueta",
- "to": "hasta",
- "all_tags": "All tags",
- "transfer": "Transferir",
- "trending_topics": "Temas Tendencia",
- "type": "Tipo",
- "unfollow": "Dejar de seguir",
- "unmute": "Desmutear",
- "unknown": "Desconocido",
- "upvote": "Votar",
- "upvote_post": "Votar publicación",
- "username": "Nombre de usuario",
- "version": "Versión",
- "vote": "Voto",
- "votes": "votos",
- "wallet": "Monedero",
- "warning": "advertencia",
- "yes": "Sí",
- "posting": "Publicando",
- "owner": "Propietario",
- "active": "Activo",
- "account_not_found": "Cuenta no encontrada",
- "this_is_wrong_password": "Esta es la contraseña errónea",
- "do_you_need_to": "Necesitas",
- "account_name": "Nombre de cuenta",
- "recover_your_account": "recuperar tu cuenta",
- "reset_usernames_password": "Restablecer la contraseña de %(username)s",
- "this_will_update_usernames_authtype_key": "Esto actualizará la clave %(authType)s de %(username)s",
- "passwords_do_not_match": "Las contraseñas no coinciden",
- "you_need_private_password_or_key_not_a_public_key": "Necesitas una contraseña o clave privada (no una clave pública)",
- "the_rules_of_APP_NAME": {
- "one": "La primera regla de %(APP_NAME)ses: No pierdas tu contraseña.",
- "second": "La segunda regla de %(APP_NAME)s es: No pierdas tu contraseña.",
- "third": "La tercera regla de %(APP_NAME)s es: No podemos recuperar tu contraseña.",
- "fourth": "La cuarta regla: Si puedes recordar tu contraseña, esta no es segura.",
- "fifth": "La quinta regla: Usa sólo contraseñas creadas aleatoriamente.",
- "sixth": "La sexta regla: No le digas a nadie tu contraseña.",
- "seventh": "La séptima regla: Haz siempre una copia de seguridad de tu contraseña."
- },
- "recover_password": "Recuperar Cuenta",
- "current_password": "Contraseña Actual",
- "generated_password": "Contraseña Generada",
- "backup_password_by_storing_it": "Haz una copia de seguridad guardándolo en tu monedero de contraseñas o en un archivo de texto",
- "enter_account_show_password": "Introduce un nombre de cuenta correcto para mostrar la contraseña",
- "click_to_generate_password": "Confirmar Contraseña",
- "re_enter_generate_password": "Reintroduce la contraseña generada",
- "understand_that_APP_NAME_cannot_recover_password": "Entiendo que (nombre APP) no puede recuperar contraseñas perdidas",
- "i_saved_password": "He guardado con seguridad mi contraseña generada",
- "update_password": "Actualizar Contraseña",
- "confirm_password": "Confirmar Contraseña",
- "account_updated": "Cuenta Actualizada",
- "password_must_be_characters_or_more": "La contraseña tiene que tener %(amount)s caracteres o más",
- "need_password_or_key": "Necesitas una contraseña o clave privada (no una clave pública)",
- "login_to_see_memo": "accede para ver el memo",
- "new_password": "Nueva Contraseña",
- "incorrect_password": "Contraseña Incorrecta",
- "username_does_not_exist": "El nombre de usuario no existe",
- "account_name_should_start_with_a_letter": "El nombre de usuario debería empezar con una letra.",
- "account_name_should_be_shorter": "El nombre de usuario debería ser más corto.",
- "account_name_should_be_longer": "El nombre de usuario debería ser más largo.",
- "account_name_should_have_only_letters_digits_or_dashes": "El nombre de usuario debería tener sólo letras, dígitos o guiones.",
- "cannot_increase_reward_of_post_within_the_last_minute_before_payout": "No se puede aumentar la recompensa de la publicación dentro del último minuto antes del pago.",
- "vote_currently_exists_user_must_be_indicate_a_to_reject_witness": "Este voto ya existe, el usuario tiene que quitar el voto al witness",
- "only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes": "Sólo una cuenta Steem permitida por dirección IP cada 10 minutos",
- "resteem_this_post": "Reesteemea esta Publicación",
- "reblog": "Reesteemear",
- "write_your_story": "Escribe tu historia",
- "remember_voting_and_posting_key": "Recuerda la clave de voto y de publicación",
- "auto_login_question_mark": "¿Acceso automático?",
- "hide_private_key": "Ocultar clave privada",
- "show_private_key": "Mostrar clave privada",
- "login_to_show": "Acceder para mostrar",
- "not_valid_email": "Correo electrónico no válido",
- "thank_you_for_being_an_early_visitor_to_APP_NAME": "Gracias por ser uno de los primeros en entrar en %(APP_NAME)s. Nos pondremos en contacto tan pronto como sea posible",
- "author_rewards": "Recompensas de autor",
- "curation_rewards": "Recompensas de curación",
- "sorry_your_reddit_account_doesnt_have_enough_karma": "Lo sentimos pero tu cuenta de Reddit no tiene suficiente Karma para un registro gratis. Por favor, añade tu email para entrar en la lista de espera",
- "register_with_facebook": "Regístrate con Facebook",
- "or_click_the_button_below_to_register_with_facebook": "O haz click en el botón de abajo para registrarte con Facebook",
- "server_returned_error": "el servidor devolvió el error",
- "APP_NAME_support": "%(APP_NAME)s Soporte",
- "please_email_questions_to": "Por favor, envía un mail con tus dudas a",
- "next_7_strings_single_block": {
- "authors_get_paid_when_people_like_you_upvote_their_post": "Autores cobran cuando gente como tú vota por sus posts",
- "if_you_enjoyed_what_you_read_earn_amount": "Si te ha gustado lo que has leído aquí, crea tu cuenta hoy mismo y empieza a ganar STEEM!",
- "free_steem": "¡STEEM GRATIS!",
- "sign_up_earn_steem": "Regístrate ahora para ganar"
- },
- "next_3_strings_together": {
- "show_more": "Mostrar más",
- "show_less": "Mostrar menos",
- "value_posts": "Posts de bajo valor"
- },
- "read_only_mode": "Debido a tareas de mantenimiento de los servidores, solo el modo lectura está disponible. Perdonen las molestias",
- "tags_and_topics": "Etiquetas y Temas",
- "show_more_topics": "Mostrar más temas",
- "basic": "Básico",
- "advanced": "Avanzado",
- "views": {
- "zero": "Ninguna visualización",
- "one": "%(count)s Visualización",
- "other": "%(count)s Visualizaciones"
- },
- "responses": {
- "zero": "Sin Respuestas",
- "one": "%(count)s Respuesta",
- "other": "%(count)s Respuestas"
- },
- "post_key_warning": {
- "confirm": "You are about to publish a STEEM private key or master password. You will probably lose control of the associated account and all its funds.",
- "warning": "Legitimate users, including employees of Steemit Inc., will never ask you for a private key or master password.",
- "checkbox": "I understand"
- }
- },
- "navigation": {
- "about": "Sobre",
- "explore": "Explorar",
- "APP_NAME_whitepaper": "%(APP_NAME)s Documentación técnica",
- "buy_LIQUID_TOKEN": "Comprar %(LIQUID_TOKEN)s",
- "sell_LIQUID_TOKEN": "Vender %(LIQUID_TOKEN)s",
- "currency_market": "Mercado de monedas",
- "stolen_account_recovery": "Recuperación de cuentas robadas",
- "change_account_password": "Cambia la contraseña de la cuenta",
- "witnesses": "Testigos",
- "vote_for_witnesses": "Vota a los testigos",
- "privacy_policy": "Política de Privacidad",
- "terms_of_service": "Términos del Servicio",
- "sign_up": "Unirse",
- "learn_more": "Para saber más",
- "welcome": "Bienvenido",
- "faq": "Preguntas Frecuentes",
- "shop": "The Steemit Shop",
- "chat": "Chat de Steemit",
- "app_center": "Centro de Aplicaciones Steemit",
- "api_docs": "Documentos API de Steemit",
- "bluepaper": "Steem Bluepaper",
- "whitepaper": "Libro blanco de Steem",
- "intro_tagline": "El dinero habla.",
- "intro_paragraph": "Tu voz tiene valor. Únete a la comunidad que te paga por publicar y votar contenido de alta calidad"
- },
- "main_menu": {
- "hot": "en alza",
- "trending": "tendencia"
- },
- "reply_editor": {
- "shorten_title": "Abreviar el título",
- "exceeds_maximum_length": "Excede la capacidad máxima (%(maxKb)sKB)",
- "including_the_category": "(incluyendo categoría '%(rootCategory)s')",
- "use_limited_amount_of_tags": "Tienes %(tagsLength)s tags totales %(includingCategory)s. Por favor usa solo 5 tags en tu post y en la línea de categorías",
- "are_you_sure_you_want_to_clear_this_form": "¿Estás seguro de que quieres limpiar este formulario?",
- "uploading": "Subiendo",
- "draft_saved": "Borrador guardado.",
- "editor": "Editor",
- "insert_images_by_dragging_dropping": "Inserta imágenes arrastrando y soltando,",
- "pasting_from_the_clipboard": "pegando desde el portapapeles,",
- "selecting_them": "Seleccionándolos",
- "image_upload": "Subir imagen",
- "power_up_100": "Power Up 100%%",
- "default_50_50": "Por defecto (50 1%% / 50 1%%)",
- "decline_payout": "Rechazar Pago",
- "check_this_to_auto_upvote_your_post": "Seleciona para autovotarte el post",
- "markdown_styling_guide": "Guía para el Markdown",
- "or_by": "o por",
- "title": "Título",
- "update_post": "Actualizar Publicación",
- "markdown_not_supported": "Markdown no soportado aquí"
- },
- "category_selector_jsx": {
- "tag_your_story": "Etiqueta (hasta 5 etiquetas), la primera etiqueta es tu principal categoría.",
- "select_a_tag": "Selecciona una etiqueta",
- "maximum_tag_length_is_24_characters": "La longitud máxima de la etiqueta es de 24 caracteres",
- "use_limited_amount_of_categories": "Por favor usa sólo %(amount)s categorías",
- "use_only_lowercase_letters": "Usa sólo letras minúsculas",
- "use_one_dash": "Usa sólo un guión",
- "use_spaces_to_separate_tags": "Usa espacios para separar las etiquetas",
- "use_only_allowed_characters": "Usa sólo letras minúsculas, dígitos y un guión",
- "must_start_with_a_letter": "Debe empezar con una letra",
- "must_end_with_a_letter_or_number": "Debe terminar con una letra o número"
- },
- "postfull_jsx": {
- "this_post_is_not_available_due_to_a_copyright_claim": "Este post no está disponible por reclamación de derechos de autor.",
- "share_on_facebook": "Compartir en Facebook",
- "share_on_twitter": "Compartir en Twitter",
- "share_on_linkedin": "Compartir en Linkedin",
- "recent_password": "Contraseña reciente",
- "in_week_convert_DEBT_TOKEN_to_LIQUID_TOKEN": "En 3.5 días, convertir 1 %(amount)s 2 %(DEBT_TOKEN)s a 3 %(LIQUID_TOKEN)s",
- "view_the_full_context": "Ver todo el contexto",
- "view_the_direct_parent": "Ver el comentario relacionado",
- "you_are_viewing_a_single_comments_thread_from": "Estás viendo los comentarios relacionados de"
- },
- "market_jsx": {
- "action": "Acción",
- "date_created": "Fecha de creación",
- "last_price": "Último precio",
- "24h_volume": "Volumen de 24 horas",
- "spread": "Difundir",
- "total": "Total",
- "available": "Disponible",
- "lowest_ask": "Oferta más baja",
- "highest_bid": "Oferta más alta",
- "buy_orders": "Comprar órdenes",
- "sell_orders": "Vender órdenes",
- "trade_history": "Historia de compra venta",
- "open_orders": "Órdenes abiertas",
- "sell_amount_for_atleast": "Vender %(amount_to_sell)s al menos por %(min_to_receive)s (%(effectivePrice)s)",
- "buy_atleast_amount_for": "Comprar al menos %(min_to_receive)s for %(amount_to_sell)s (%(effectivePrice)s)",
- "price_warning_above": "Este precio está por debajo del precio de mercado que es %(marketPrice)s, estás seguro?",
- "price_warning_below": "Este precio está por debajo del precio de mercado que es %(marketPrice)s, estás seguro?",
- "order_cancel_confirm": "Cancelar órden %(order_id)s de %(user)s?",
- "order_cancelled": "Órden %(order_id)s cancelada",
- "higher": "Más alta",
- "lower": "Más baja",
- "total_DEBT_TOKEN_SHORT_CURRENCY_SIGN": "Total %(DEBT_TOKEN_SHORT)s (%(CURRENCY_SIGN)s)"
- },
- "recoveraccountstep1_jsx": {
- "begin_recovery": "Empezar Recuperación",
- "not_valid": "No es válido",
- "account_name_is_not_found": "Nombre de usuario no encontrado",
- "unable_to_recover_account_not_change_ownership_recently": "No podemos recuperar esta cuenta, esta no ha cambiado su propiedad recientemente.",
- "password_not_used_in_last_days": "Esta contraseña no ha sido usada en esta cuenta en los últimos 30 días.",
- "request_already_submitted_contact_support": "Tu petición ha sido enviada y estamos trabajando en ella. Por favor contacta %(SUPPORT_EMAIL)s para ver el estado de la misma.",
- "recover_account_intro": "Puede ocurrir que la owner key de algún usuario se vea comprometida. La funcionalidad de recuperación de contraseñas robadas le da al propietario de la cuenta 30 días para recuperar su cuenta desde el mismo momento que el delincuente ha cambiado la owner key. Esta funcionalidad sólo puede ser usada en %(APP_URL)s si el propietario de la cuenta ha incluído %(APP_NAME)s como su cuenta de confianza y además a comulgado con las condiciones y términos de servicio de %(APP_NAME)s",
- "login_with_facebook_or_reddit_media_to_verify_identity": "Por favor accede con Fabebook o Reddit para verificar tu identidad",
- "login_with_social_media_to_verify_identity": "Por favor entra con %(provider)s para verificar tu identidad",
- "enter_email_toverify_identity": "Necesitamos verificar tu identidad. Por favor introduce tu dirección de correo electrónico debajo para empezar la verificación.",
- "continue_with_email": "Continuar con correo electrónico",
- "thanks_for_submitting_request_for_account_recovery": "Gracias por enviar tu petición a nuestro sistema de recuperación de contraseñas usando %(APP_NAME)s basado en la autentificación multi factor. Tan pronto como sea posible recibirás una respuesta, sim embargo, puede que haya algún retraso debido al alto volumen de peticiones. Por favor, esté preparado para verificar su identidad.",
- "recovering_account": "Recuperando cuenta",
- "recover_account": "Recuperar Cuenta",
- "checking_account_owner": "Comprobando propietario de la cuenta",
- "sending_recovery_request": "Enviando solicitud de recuperación ",
- "cant_confirm_account_ownership": "No podemos confirmar la propiedad de la cuenta. Comprueba tu contraseña",
- "account_recovery_request_not_confirmed": "La solicitud de recuperación de cuenta no está confirmada todavía, por favor vuelve más tarde, gracias por tu paciencia."
- },
- "user_profile": {
- "unknown_account": "Cuenta desconocida",
- "user_hasnt_made_any_posts_yet": "Parece que %(name)s aún no ha comenzado a postear",
- "user_hasnt_started_bloggin_yet": "Parece que %(name)s aún no ha comenzado su blog",
- "user_hasnt_followed_anything_yet": "Parece que %(name)s aún no está siguiendo a nadie. Si %(name)s acaba de añadir nuevas cuentas para seguir, el feed personalizado aparecerá cuando el nuevo contenido esté disponible.",
- "user_hasnt_had_any_replies_yet": "%(name)s todavía no ha tenido ninguna respuesta",
- "looks_like_you_havent_posted_anything_yet": "Looks like you haven't posted anything yet.",
- "create_a_post": "Create a Post",
- "explore_trending_articles": "Explore Trending Articles",
- "read_the_quick_start_guide": "Read The Quick Start Guide",
- "browse_the_faq": "Browse The FAQ",
- "followers": "Seguidores",
- "this_is_users_reputations_score_it_is_based_on_history_of_votes": "Esto es la reputación de %(name)s's. La reputación está basada en la historia de votos recibidos por la cuenta y se usa para esconder contenido de baja calidad.",
- "follower_count": {
- "zero": "Sin seguidores",
- "one": "1 seguidor",
- "other": "%(count)s seguidores"
- },
- "followed_count": {
- "zero": "No sigue a nadie",
- "one": "1 siguiendo",
- "other": "%(count)s siguiendo"
- },
- "post_count": {
- "zero": "Sin publicaciones",
- "one": "1 publicación",
- "other": "%(count)s posts"
- }
- },
- "authorrewards_jsx": {
- "estimated_author_rewards_last_week": "Recompensas de autor estimadas la semana pasada",
- "author_rewards_history": "Historial de recompensas de autor"
- },
- "curationrewards_jsx": {
- "estimated_curation_rewards_last_week": "Recompensas de curación aproximadas de la semana pasada",
- "curation_rewards_history": "Historial de recompensas de curación"
- },
- "post_jsx": {
- "now_showing_comments_with_low_ratings": "Mostrando ahora comentarios con bajas calificaciones",
- "sort_order": "Clase de órden",
- "comments_were_hidden_due_to_low_ratings": "Los comentarios fueron ocultados debido a las bajas calificaciones"
- },
- "voting_jsx": {
- "flagging_post_can_remove_rewards_the_flag_should_be_used_for_the_following": "Flagear un posts puede hacer desaparecer las recompensas y hacer el contenido menos visible. Usar el sentido común para flagear",
- "disagreement_on_rewards": "Desacuerdo en las recompensas",
- "fraud_or_plagiarism": "Fraude o Plagio",
- "hate_speech_or_internet_trolling": "Discurso de odio o trolear en internat",
- "intentional_miss_categorized_content_or_spam": "Uso erróneo de los tags o Spam",
- "pending_payout": "Pago pendiente $ %(value)s",
- "payout_declined": "Pago rehusado",
- "max_accepted_payout": "Máximo pago aceptado $ %(value)s",
- "promotion_cost": "Coste de promoción $ %(value)s",
- "past_payouts": "Pagos pasados $ %(value)s",
- "past_payouts_author": "Autor $ %(value)s",
- "past_payouts_curators": "Curador $ %(value)s",
- "we_will_reset_curation_rewards_for_this_post": "Reseteará tus recompensas de curación para este post",
- "removing_your_vote": "Quitando tu voto",
- "changing_to_an_upvote": "Cambiando a Up-vote",
- "changing_to_a_downvote": "Cambiando a Down-Vote",
- "confirm_flag": "Confirmar Flag",
- "and_more": "y %(count)s más",
- "votes_plural": {
- "one": "%(count)s voto",
- "other": "%(count)s votos"
- }
- },
- "witnesses_jsx": {
- "witness_thread": "tema testigo",
- "top_witnesses": "Votación para testigo",
- "you_have_votes_remaining": {
- "zero": "No tienes votos restantes",
- "one": "Tienes 1 voto restante",
- "other": "Te quedan %(count)s votos disponibles"
- },
- "you_can_vote_for_maximum_of_witnesses": "Puedes votar como máximo a 30 testigos",
- "witness": "Testigos",
- "information": "Información",
- "if_you_want_to_vote_outside_of_top_enter_account_name": "SI quieres votar a un testigo que está fuera de los top 50, por favor introduce el nombre de la cuenta para votarle",
- "set_witness_proxy": "También puedes elegir un proxy que votará a los testigos por ti. Esta actividad reseteará tu actual selección de witness",
- "witness_set": "Has seleccionado un proxy de votación. Si quieres volver a habilitar el voto manual, por favor borra el proxy.",
- "witness_proxy_current": "Tu proxy actual es",
- "witness_proxy_set": "Crear proxy",
- "witness_proxy_clear": "Borrar proxy",
- "proxy_update_error": "Tu proxy no fue actualizado"
- },
- "votesandcomments_jsx": {
- "no_responses_yet_click_to_respond": "Todavía sin respuestas. Pincha para responder.",
- "response_count_tooltip": {
- "zero": "sin respuestas. Pincha para responder.",
- "one": "1 respuesta. Pincha para responder.",
- "other": "%(count)s respuestas. Pincha para responder."
- },
- "vote_count": {
- "zero": "sin votos",
- "one": "1 voto",
- "other": "%(count)s votos"
+ "g": {
+ "age": "edad",
+ "amount": "Cantidad",
+ "and": "y",
+ "are_you_sure": "¿Estás seguro?",
+ "ask": "Preguntar",
+ "balance": "Saldo",
+ "balances": "Saldos",
+ "bid": "Oferta",
+ "blog": "Blog",
+ "browse": "Navegar",
+ "buy": "Comprar",
+ "buy_or_sell": "Comprar o Vender",
+ "by": "por",
+ "cancel": "Cancelar",
+ "change_password": "Cambiar Contraseña",
+ "choose_language": "Elegir Idioma",
+ "clear": "Limpiar",
+ "close": "Cerrar",
+ "collapse_or_expand": "Plegar/Expandir",
+ "comments": "Comentarios",
+ "confirm": "Confirmar",
+ "convert": "Convertir",
+ "date": "Fecha",
+ "delete": "Borrar",
+ "dismiss": "Descartar",
+ "edit": "Editar",
+ "email": "Email",
+ "feed": "Favoritos",
+ "follow": "Seguir",
+ "for": "para",
+ "from": "de",
+ "go_back": "Volver",
+ "hide": "Ocultar",
+ "in": "en",
+ "in_reply_to": "en respuesta a",
+ "insufficient_balance": "Saldo insuficiente",
+ "invalid_amount": "Cantidad inválida",
+ "joined": "Unió",
+ "loading": "Cargando",
+ "login": "Iniciar sesión",
+ "logout": "Cerrar sesión",
+ "memo": "Memo",
+ "mute": "Silenciar",
+ "new": "nuevo",
+ "newer": "Nuevo",
+ "next": "Próximo",
+ "no": "No",
+ "ok": "Ok",
+ "older": "Más viejo",
+ "or": "o",
+ "order_placed": "Órden dispuesta",
+ "password": "Contraseña",
+ "payouts": "Pagos",
+ "permissions": "Permisos",
+ "phishy_message":
+ "Enlace expuesto a texto sin formato; cuidado con un posible intento de phishing",
+ "post": "Publicación",
+ "post_as": "Publicar como",
+ "posts": "Publicaciones",
+ "powered_up_100": "Powered Up 100 %%",
+ "preview": "Vista previa",
+ "previous": "Anterior",
+ "price": "Precio",
+ "print": "Imprimir",
+ "promote": "Promocionar",
+ "promoted": "promocionado",
+ "re": "RE",
+ "re_to": "RE %(topic)s",
+ "recent_password": "Contraseña reciente",
+ "receive": "Recibir",
+ "remove": "Quitar",
+ "remove_vote": "Quitar voto",
+ "replied_to": "Respondido a %(account)s",
+ "replies": "Respuestas",
+ "reply": "Respuesta",
+ "reply_count": {
+ "zero": "Sin respuestas",
+ "one": "1 respuesta",
+ "other": "%(count)s respuestas"
+ },
+ "reputation": "Reputación",
+ "reveal_comment": "Mostrar Comentario",
+ "request": "solicitud",
+ "required": "Requerido",
+ "rewards": "Recompensa",
+ "save": "Guardar",
+ "saved": "Guardado",
+ "search": "Buscar",
+ "sell": "Vender",
+ "settings": "Configuración",
+ "share_this_post": "Compartir esta publicación",
+ "show": "Mostrar",
+ "sign_in": "Registrarse",
+ "sign_up": "Inscribirse",
+ "since": "desde",
+ "submit": "Enviar",
+ "power_up": "Power Up",
+ "submit_a_story": "Publicar",
+ "tag": "Etiqueta",
+ "to": "hasta",
+ "all_tags": "All tags",
+ "transfer": "Transferir",
+ "trending_topics": "Temas Tendencia",
+ "type": "Tipo",
+ "unfollow": "Dejar de seguir",
+ "unmute": "Desmutear",
+ "unknown": "Desconocido",
+ "upvote": "Votar",
+ "upvote_post": "Votar publicación",
+ "username": "Nombre de usuario",
+ "version": "Versión",
+ "vote": "Voto",
+ "votes": "votos",
+ "wallet": "Monedero",
+ "warning": "advertencia",
+ "yes": "Sí",
+ "posting": "Publicando",
+ "owner": "Propietario",
+ "active": "Activo",
+ "account_not_found": "Cuenta no encontrada",
+ "this_is_wrong_password": "Esta es la contraseña errónea",
+ "do_you_need_to": "Necesitas",
+ "account_name": "Nombre de cuenta",
+ "recover_your_account": "recuperar tu cuenta",
+ "reset_usernames_password": "Restablecer la contraseña de %(username)s",
+ "this_will_update_usernames_authtype_key":
+ "Esto actualizará la clave %(authType)s de %(username)s",
+ "passwords_do_not_match": "Las contraseñas no coinciden",
+ "you_need_private_password_or_key_not_a_public_key":
+ "Necesitas una contraseña o clave privada (no una clave pública)",
+ "the_rules_of_APP_NAME": {
+ "one":
+ "La primera regla de %(APP_NAME)ses: No pierdas tu contraseña.",
+ "second":
+ "La segunda regla de %(APP_NAME)s es: No pierdas tu contraseña.",
+ "third":
+ "La tercera regla de %(APP_NAME)s es: No podemos recuperar tu contraseña.",
+ "fourth":
+ "La cuarta regla: Si puedes recordar tu contraseña, esta no es segura.",
+ "fifth":
+ "La quinta regla: Usa sólo contraseñas creadas aleatoriamente.",
+ "sixth": "La sexta regla: No le digas a nadie tu contraseña.",
+ "seventh":
+ "La séptima regla: Haz siempre una copia de seguridad de tu contraseña."
+ },
+ "recover_password": "Recuperar Cuenta",
+ "current_password": "Contraseña Actual",
+ "generated_password": "Contraseña Generada",
+ "backup_password_by_storing_it":
+ "Haz una copia de seguridad guardándolo en tu monedero de contraseñas o en un archivo de texto",
+ "enter_account_show_password":
+ "Introduce un nombre de cuenta correcto para mostrar la contraseña",
+ "click_to_generate_password": "Confirmar Contraseña",
+ "re_enter_generate_password": "Reintroduce la contraseña generada",
+ "understand_that_APP_NAME_cannot_recover_password":
+ "Entiendo que (nombre APP) no puede recuperar contraseñas perdidas",
+ "i_saved_password": "He guardado con seguridad mi contraseña generada",
+ "update_password": "Actualizar Contraseña",
+ "confirm_password": "Confirmar Contraseña",
+ "account_updated": "Cuenta Actualizada",
+ "password_must_be_characters_or_more":
+ "La contraseña tiene que tener %(amount)s caracteres o más",
+ "need_password_or_key":
+ "Necesitas una contraseña o clave privada (no una clave pública)",
+ "login_to_see_memo": "accede para ver el memo",
+ "new_password": "Nueva Contraseña",
+ "incorrect_password": "Contraseña Incorrecta",
+ "username_does_not_exist": "El nombre de usuario no existe",
+ "account_name_should_start_with_a_letter":
+ "El nombre de usuario debería empezar con una letra.",
+ "account_name_should_be_shorter":
+ "El nombre de usuario debería ser más corto.",
+ "account_name_should_be_longer":
+ "El nombre de usuario debería ser más largo.",
+ "account_name_should_have_only_letters_digits_or_dashes":
+ "El nombre de usuario debería tener sólo letras, dígitos o guiones.",
+ "cannot_increase_reward_of_post_within_the_last_minute_before_payout":
+ "No se puede aumentar la recompensa de la publicación dentro del último minuto antes del pago.",
+ "vote_currently_exists_user_must_be_indicate_a_to_reject_witness":
+ "Este voto ya existe, el usuario tiene que quitar el voto al witness",
+ "only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes":
+ "Sólo una cuenta Steem permitida por dirección IP cada 10 minutos",
+ "resteem_this_post": "Reesteemea esta Publicación",
+ "reblog": "Reesteemear",
+ "write_your_story": "Escribe tu historia",
+ "remember_voting_and_posting_key":
+ "Recuerda la clave de voto y de publicación",
+ "auto_login_question_mark": "¿Acceso automático?",
+ "hide_private_key": "Ocultar clave privada",
+ "show_private_key": "Mostrar clave privada",
+ "login_to_show": "Acceder para mostrar",
+ "not_valid_email": "Correo electrónico no válido",
+ "thank_you_for_being_an_early_visitor_to_APP_NAME":
+ "Gracias por ser uno de los primeros en entrar en %(APP_NAME)s. Nos pondremos en contacto tan pronto como sea posible",
+ "author_rewards": "Recompensas de autor",
+ "curation_rewards": "Recompensas de curación",
+ "sorry_your_reddit_account_doesnt_have_enough_karma":
+ "Lo sentimos pero tu cuenta de Reddit no tiene suficiente Karma para un registro gratis. Por favor, añade tu email para entrar en la lista de espera",
+ "register_with_facebook": "Regístrate con Facebook",
+ "or_click_the_button_below_to_register_with_facebook":
+ "O haz click en el botón de abajo para registrarte con Facebook",
+ "server_returned_error": "el servidor devolvió el error",
+ "APP_NAME_support": "%(APP_NAME)s Soporte",
+ "please_email_questions_to": "Por favor, envía un mail con tus dudas a",
+ "next_7_strings_single_block": {
+ "authors_get_paid_when_people_like_you_upvote_their_post":
+ "Autores cobran cuando gente como tú vota por sus posts",
+ "if_you_enjoyed_what_you_read_earn_amount":
+ "Si te ha gustado lo que has leído aquí, crea tu cuenta hoy mismo y empieza a ganar STEEM!",
+ "free_steem": "¡STEEM GRATIS!",
+ "sign_up_earn_steem": "Regístrate ahora para ganar"
+ },
+ "next_3_strings_together": {
+ "show_more": "Mostrar más",
+ "show_less": "Mostrar menos",
+ "value_posts": "Posts de bajo valor"
+ },
+ "read_only_mode":
+ "Debido a tareas de mantenimiento de los servidores, solo el modo lectura está disponible. Perdonen las molestias",
+ "tags_and_topics": "Etiquetas y Temas",
+ "show_more_topics": "Mostrar más temas",
+ "basic": "Básico",
+ "advanced": "Avanzado",
+ "views": {
+ "zero": "Ninguna visualización",
+ "one": "%(count)s Visualización",
+ "other": "%(count)s Visualizaciones"
+ },
+ "responses": {
+ "zero": "Sin Respuestas",
+ "one": "%(count)s Respuesta",
+ "other": "%(count)s Respuestas"
+ },
+ "post_key_warning": {
+ "confirm":
+ "Está a punto de publicar una clave privada STEEM o una contraseña maestra. Probablemente perderá el control de la cuenta asociada y todos sus fondos.",
+ "warning":
+ "Los usuarios legítimos, incluidos los empleados de Steemit Inc., nunca le pedirán una clave privada o contraseña maestra.",
+ "checkbox": "Entiendo"
+ }
+ },
+ "navigation": {
+ "about": "Sobre",
+ "explore": "Explorar",
+ "APP_NAME_whitepaper": "%(APP_NAME)s Documentación técnica",
+ "buy_LIQUID_TOKEN": "Comprar %(LIQUID_TOKEN)s",
+ "sell_LIQUID_TOKEN": "Vender %(LIQUID_TOKEN)s",
+ "currency_market": "Mercado de monedas",
+ "stolen_account_recovery": "Recuperación de cuentas robadas",
+ "change_account_password": "Cambia la contraseña de la cuenta",
+ "witnesses": "Testigos",
+ "vote_for_witnesses": "Vota a los testigos",
+ "privacy_policy": "Política de Privacidad",
+ "terms_of_service": "Términos del Servicio",
+ "sign_up": "Unirse",
+ "learn_more": "Para saber más",
+ "welcome": "Bienvenido",
+ "faq": "Preguntas Frecuentes",
+ "shop": "The Steemit Shop",
+ "chat": "Chat de Steemit",
+ "app_center": "Centro de Aplicaciones Steemit",
+ "api_docs": "Documentos API de Steemit",
+ "bluepaper": "Steem Bluepaper",
+ "smt_whitepaper": "Libro blanco de SMT",
+ "whitepaper": "Libro blanco de Steem",
+ "intro_tagline": "El dinero habla.",
+ "intro_paragraph":
+ "Tu voz tiene valor. Únete a la comunidad que te paga por publicar y votar contenido de alta calidad"
+ },
+ "main_menu": {
+ "hot": "en alza",
+ "trending": "tendencia"
+ },
+ "reply_editor": {
+ "shorten_title": "Abreviar el título",
+ "exceeds_maximum_length": "Excede la capacidad máxima (%(maxKb)sKB)",
+ "including_the_category": "(incluyendo categoría '%(rootCategory)s')",
+ "use_limited_amount_of_tags":
+ "Tienes %(tagsLength)s tags totales %(includingCategory)s. Por favor usa solo 5 tags en tu post y en la línea de categorías",
+ "are_you_sure_you_want_to_clear_this_form":
+ "¿Estás seguro de que quieres limpiar este formulario?",
+ "uploading": "Subiendo",
+ "draft_saved": "Borrador guardado.",
+ "editor": "Editor",
+ "insert_images_by_dragging_dropping":
+ "Inserta imágenes arrastrando y soltando,",
+ "pasting_from_the_clipboard": "pegando desde el portapapeles,",
+ "selecting_them": "Seleccionándolos",
+ "image_upload": "Subir imagen",
+ "power_up_100": "Power Up 100%%",
+ "default_50_50": "Por defecto (50 1%% / 50 1%%)",
+ "decline_payout": "Rechazar Pago",
+ "check_this_to_auto_upvote_your_post":
+ "Seleciona para autovotarte el post",
+ "markdown_styling_guide": "Guía para el Markdown",
+ "or_by": "o por",
+ "title": "Título",
+ "update_post": "Actualizar Publicación",
+ "markdown_not_supported": "Markdown no soportado aquí"
+ },
+ "category_selector_jsx": {
+ "tag_your_story":
+ "Etiqueta (hasta 5 etiquetas), la primera etiqueta es tu principal categoría.",
+ "select_a_tag": "Selecciona una etiqueta",
+ "maximum_tag_length_is_24_characters":
+ "La longitud máxima de la etiqueta es de 24 caracteres",
+ "use_limited_amount_of_categories":
+ "Por favor usa sólo %(amount)s categorías",
+ "use_only_lowercase_letters": "Usa sólo letras minúsculas",
+ "use_one_dash": "Usa sólo un guión",
+ "use_spaces_to_separate_tags":
+ "Usa espacios para separar las etiquetas",
+ "use_only_allowed_characters":
+ "Usa sólo letras minúsculas, dígitos y un guión",
+ "must_start_with_a_letter": "Debe empezar con una letra",
+ "must_end_with_a_letter_or_number":
+ "Debe terminar con una letra o número"
+ },
+ "postfull_jsx": {
+ "this_post_is_not_available_due_to_a_copyright_claim":
+ "Este post no está disponible por reclamación de derechos de autor.",
+ "share_on_facebook": "Compartir en Facebook",
+ "share_on_twitter": "Compartir en Twitter",
+ "share_on_linkedin": "Compartir en Linkedin",
+ "recent_password": "Contraseña reciente",
+ "in_week_convert_DEBT_TOKEN_to_LIQUID_TOKEN":
+ "En 3.5 días, convertir 1 %(amount)s 2 %(DEBT_TOKEN)s a 3 %(LIQUID_TOKEN)s",
+ "view_the_full_context": "Ver todo el contexto",
+ "view_the_direct_parent": "Ver el comentario relacionado",
+ "you_are_viewing_a_single_comments_thread_from":
+ "Estás viendo los comentarios relacionados de"
+ },
+ "market_jsx": {
+ "action": "Acción",
+ "date_created": "Fecha de creación",
+ "last_price": "Último precio",
+ "24h_volume": "Volumen de 24 horas",
+ "spread": "Difundir",
+ "total": "Total",
+ "available": "Disponible",
+ "lowest_ask": "Oferta más baja",
+ "highest_bid": "Oferta más alta",
+ "buy_orders": "Comprar órdenes",
+ "sell_orders": "Vender órdenes",
+ "trade_history": "Historia de compra venta",
+ "open_orders": "Órdenes abiertas",
+ "sell_amount_for_atleast":
+ "Vender %(amount_to_sell)s al menos por %(min_to_receive)s (%(effectivePrice)s)",
+ "buy_atleast_amount_for":
+ "Comprar al menos %(min_to_receive)s for %(amount_to_sell)s (%(effectivePrice)s)",
+ "price_warning_above":
+ "Este precio está por debajo del precio de mercado que es %(marketPrice)s, estás seguro?",
+ "price_warning_below":
+ "Este precio está por debajo del precio de mercado que es %(marketPrice)s, estás seguro?",
+ "order_cancel_confirm": "Cancelar órden %(order_id)s de %(user)s?",
+ "order_cancelled": "Órden %(order_id)s cancelada",
+ "higher": "Más alta",
+ "lower": "Más baja",
+ "total_DEBT_TOKEN_SHORT_CURRENCY_SIGN":
+ "Total %(DEBT_TOKEN_SHORT)s (%(CURRENCY_SIGN)s)"
+ },
+ "recoveraccountstep1_jsx": {
+ "begin_recovery": "Empezar Recuperación",
+ "not_valid": "No es válido",
+ "account_name_is_not_found": "Nombre de usuario no encontrado",
+ "unable_to_recover_account_not_change_ownership_recently":
+ "No podemos recuperar esta cuenta, esta no ha cambiado su propiedad recientemente.",
+ "password_not_used_in_last_days":
+ "Esta contraseña no ha sido usada en esta cuenta en los últimos 30 días.",
+ "request_already_submitted_contact_support":
+ "Tu petición ha sido enviada y estamos trabajando en ella. Por favor contacta %(SUPPORT_EMAIL)s para ver el estado de la misma.",
+ "recover_account_intro":
+ "Puede ocurrir que la owner key de algún usuario se vea comprometida. La funcionalidad de recuperación de contraseñas robadas le da al propietario de la cuenta 30 días para recuperar su cuenta desde el mismo momento que el delincuente ha cambiado la owner key. Esta funcionalidad sólo puede ser usada en %(APP_URL)s si el propietario de la cuenta ha incluído %(APP_NAME)s como su cuenta de confianza y además a comulgado con las condiciones y términos de servicio de %(APP_NAME)s",
+ "login_with_facebook_or_reddit_media_to_verify_identity":
+ "Por favor accede con Fabebook o Reddit para verificar tu identidad",
+ "login_with_social_media_to_verify_identity":
+ "Por favor entra con %(provider)s para verificar tu identidad",
+ "enter_email_toverify_identity":
+ "Necesitamos verificar tu identidad. Por favor introduce tu dirección de correo electrónico debajo para empezar la verificación.",
+ "continue_with_email": "Continuar con correo electrónico",
+ "thanks_for_submitting_request_for_account_recovery":
+ "Gracias por enviar tu petición a nuestro sistema de recuperación de contraseñas usando %(APP_NAME)s basado en la autentificación multi factor. Tan pronto como sea posible recibirás una respuesta, sim embargo, puede que haya algún retraso debido al alto volumen de peticiones. Por favor, esté preparado para verificar su identidad.",
+ "recovering_account": "Recuperando cuenta",
+ "recover_account": "Recuperar Cuenta",
+ "checking_account_owner": "Comprobando propietario de la cuenta",
+ "sending_recovery_request": "Enviando solicitud de recuperación ",
+ "cant_confirm_account_ownership":
+ "No podemos confirmar la propiedad de la cuenta. Comprueba tu contraseña",
+ "account_recovery_request_not_confirmed":
+ "La solicitud de recuperación de cuenta no está confirmada todavía, por favor vuelve más tarde, gracias por tu paciencia."
+ },
+ "user_profile": {
+ "unknown_account": "Cuenta desconocida",
+ "user_hasnt_made_any_posts_yet":
+ "Parece que %(name)s aún no ha comenzado a postear",
+ "user_hasnt_started_bloggin_yet":
+ "Parece que %(name)s aún no ha comenzado su blog",
+ "user_hasnt_followed_anything_yet":
+ "Parece que %(name)s aún no está siguiendo a nadie. Si %(name)s acaba de añadir nuevas cuentas para seguir, el feed personalizado aparecerá cuando el nuevo contenido esté disponible.",
+ "user_hasnt_had_any_replies_yet":
+ "%(name)s todavía no ha tenido ninguna respuesta",
+ "looks_like_you_havent_posted_anything_yet":
+ "Looks like you haven't posted anything yet.",
+ "create_a_post": "Create a Post",
+ "explore_trending_articles": "Explore Trending Articles",
+ "read_the_quick_start_guide": "Read The Quick Start Guide",
+ "browse_the_faq": "Browse The FAQ",
+ "followers": "Seguidores",
+ "this_is_users_reputations_score_it_is_based_on_history_of_votes":
+ "Esto es la reputación de %(name)s's. La reputación está basada en la historia de votos recibidos por la cuenta y se usa para esconder contenido de baja calidad.",
+ "follower_count": {
+ "zero": "Sin seguidores",
+ "one": "1 seguidor",
+ "other": "%(count)s seguidores"
+ },
+ "followed_count": {
+ "zero": "No sigue a nadie",
+ "one": "1 siguiendo",
+ "other": "%(count)s siguiendo"
+ },
+ "post_count": {
+ "zero": "Sin publicaciones",
+ "one": "1 publicación",
+ "other": "%(count)s posts"
+ }
+ },
+ "authorrewards_jsx": {
+ "estimated_author_rewards_last_week":
+ "Recompensas de autor estimadas la semana pasada",
+ "author_rewards_history": "Historial de recompensas de autor"
+ },
+ "curationrewards_jsx": {
+ "estimated_curation_rewards_last_week":
+ "Recompensas de curación aproximadas de la semana pasada",
+ "curation_rewards_history": "Historial de recompensas de curación"
+ },
+ "post_jsx": {
+ "now_showing_comments_with_low_ratings":
+ "Mostrando ahora comentarios con bajas calificaciones",
+ "sort_order": "Clase de órden",
+ "comments_were_hidden_due_to_low_ratings":
+ "Los comentarios fueron ocultados debido a las bajas calificaciones"
+ },
+ "voting_jsx": {
+ "flagging_post_can_remove_rewards_the_flag_should_be_used_for_the_following":
+ "Flagear un posts puede hacer desaparecer las recompensas y hacer el contenido menos visible. Usar el sentido común para flagear",
+ "disagreement_on_rewards": "Desacuerdo en las recompensas",
+ "fraud_or_plagiarism": "Fraude o Plagio",
+ "hate_speech_or_internet_trolling":
+ "Discurso de odio o trolear en internat",
+ "intentional_miss_categorized_content_or_spam":
+ "Uso erróneo de los tags o Spam",
+ "pending_payout": "Pago pendiente $ %(value)s",
+ "payout_declined": "Pago rehusado",
+ "max_accepted_payout": "Máximo pago aceptado $ %(value)s",
+ "promotion_cost": "Coste de promoción $ %(value)s",
+ "past_payouts": "Pagos pasados $ %(value)s",
+ "past_payouts_author": "Autor $ %(value)s",
+ "past_payouts_curators": "Curador $ %(value)s",
+ "we_will_reset_curation_rewards_for_this_post":
+ "Reseteará tus recompensas de curación para este post",
+ "removing_your_vote": "Quitando tu voto",
+ "changing_to_an_upvote": "Cambiando a Up-vote",
+ "changing_to_a_downvote": "Cambiando a Down-Vote",
+ "confirm_flag": "Confirmar Flag",
+ "and_more": "y %(count)s más",
+ "votes_plural": {
+ "one": "%(count)s voto",
+ "other": "%(count)s votos"
+ }
+ },
+ "witnesses_jsx": {
+ "witness_thread": "tema testigo",
+ "top_witnesses": "Votación para testigo",
+ "you_have_votes_remaining": {
+ "zero": "No tienes votos restantes",
+ "one": "Tienes 1 voto restante",
+ "other": "Te quedan %(count)s votos disponibles"
+ },
+ "you_can_vote_for_maximum_of_witnesses":
+ "Puedes votar como máximo a 30 testigos",
+ "witness": "Testigos",
+ "information": "Información",
+ "if_you_want_to_vote_outside_of_top_enter_account_name":
+ "SI quieres votar a un testigo que está fuera de los top 50, por favor introduce el nombre de la cuenta para votarle",
+ "set_witness_proxy":
+ "También puedes elegir un proxy que votará a los testigos por ti. Esta actividad reseteará tu actual selección de witness",
+ "witness_set":
+ "Has seleccionado un proxy de votación. Si quieres volver a habilitar el voto manual, por favor borra el proxy.",
+ "witness_proxy_current": "Tu proxy actual es",
+ "witness_proxy_set": "Crear proxy",
+ "witness_proxy_clear": "Borrar proxy",
+ "proxy_update_error": "Tu proxy no fue actualizado"
+ },
+ "votesandcomments_jsx": {
+ "no_responses_yet_click_to_respond":
+ "Todavía sin respuestas. Pincha para responder.",
+ "response_count_tooltip": {
+ "zero": "sin respuestas. Pincha para responder.",
+ "one": "1 respuesta. Pincha para responder.",
+ "other": "%(count)s respuestas. Pincha para responder."
+ },
+ "vote_count": {
+ "zero": "sin votos",
+ "one": "1 voto",
+ "other": "%(count)s votos"
+ }
+ },
+ "userkeys_jsx": {
+ "public": "Público",
+ "private": "Privado",
+ "public_something_key": "Contraseña %(key)s pública",
+ "private_something_key": "Contraseña %(key)s privada",
+ "posting_key_is_required_it_should_be_different":
+ "La contraseña de posteado se usa para postear y para votar. Debería ser diferente a la contraseña activa y a la contraseña de propietario.",
+ "the_active_key_is_used_to_make_transfers_and_place_orders":
+ "La contraseña activa se usa para hacer transferencias y poner órdenes de compra o venta en el mercado interno.",
+ "the_owner_key_is_required_to_change_other_keys":
+ "La contraseña propia es la contraseña maestra para la cuenta y se requiere para cambiar el resto de las contraseñas.",
+ "the_private_key_or_password_should_be_kept_offline":
+ "La contraseña privada para la cuenta propia debería estar fuera del acceso a internet. Se recomienda imprimirla y guardarla en lugar seguro.",
+ "the_memo_key_is_used_to_create_and_read_memos":
+ "La contraseña memo se usa para crear y leer memos."
+ },
+ "suggestpassword_jsx": {
+ "APP_NAME_cannot_recover_passwords_keep_this_page_in_a_secure_location":
+ "%(APP_NAME)s no puede recuperar contraseñas. Guarda está página en lugar seguro, como en una caja fuerte o una caja de depósito",
+ "APP_NAME_password_backup":
+ "%(APP_NAME)s Contraseña de apoyo o seguridad",
+ "APP_NAME_password_backup_required":
+ "%(APP_NAME)s Contraseña de apoyo o seguridad (requerida)",
+ "after_printing_write_down_your_user_name":
+ "Después de imprimir, escribe tu nombre de usuario"
+ },
+ "converttosteem_jsx": {
+ "your_existing_DEBT_TOKEN_are_liquid_and_transferable":
+ "La cantidad de %(DEBT_TOKEN)s son líquidos y transferibles. Si lo deseas también puedes comprar o vender %(DEBT_TOKEN)s directamente en esta página en el %(link)s o transferir a un mercado externo",
+ "this_is_a_price_feed_conversion":
+ "Esto es la conversión de precio. Los 3.5 días de retraso son necesarios para prevenir el abuso con las medias del precio",
+ "convert_to_LIQUID_TOKEN": "Convertir a %(LIQUID_TOKEN)s",
+ "DEBT_TOKEN_will_be_unavailable":
+ "Esta acción tardará 3.5 días en procesarse y no puede ser cancelada. Estos %(DEBT_TOKEN)s dejarán inmediatamente de estar disponibles"
+ },
+ "tips_js": {
+ "liquid_token":
+ "Tokens canjeables pueden ser transferidos a cualquier sitio en cualquier momento.1%(LIQUID_TOKEN)s y pueden ser convertidos a %(VESTING_TOKEN)s en un proceso llamado power up.",
+ "influence_token":
+ "Tokens con influencia te dan más control sobre los pagos de los posts y te permiten ganar recompensas de curación",
+ "estimated_value":
+ "El valor estimado está basado en el valor medio de 1%(LIQUID_TOKEN)s en US dollars.",
+ "non_transferable":
+ "%(VESTING_TOKEN)s es intransferible y requiere 3 meses (13 pagos) para convertir de vuelta a %(LIQUID_TOKEN)s.",
+ "converted_VESTING_TOKEN_can_be_sent_to_yourself_but_can_not_transfer_again":
+ "Los %(VESTING_TOKEN)s convertidos pueden ser enviados a ti mismo o a otras personas pero no pueden ser transferidos de nuevo sin convertirlos de vuelta a %(LIQUID_TOKEN)s.",
+ "part_of_your_steem_power_is_currently_delegated":
+ "Part of %(user_name)s's STEEM POWER is currently delegated. Delegation is donated for influence or to help new users perform actions on steemit. Your delegation amount can fluctuate."
+ },
+ "promote_post_jsx": {
+ "promote_post": "Promociona el Post",
+ "spend_your_DEBT_TOKEN_to_advertise_this_post":
+ "Gasta tu %(DEBT_TOKEN)s para promocionar tu contenido en la sección de promoción",
+ "you_successfully_promoted_this_post":
+ "Has promocionado satisfactoriamente este post",
+ "this_post_was_hidden_due_to_low_ratings":
+ "El post ha sido ocultado por bajas calificaciones"
+ },
+ "about_jsx": {
+ "about_app": "Sobre %(APP_NAME)s",
+ "about_app_details":
+ "%(APP_NAME)s es una plataforma social online donde todo el mundo genera ingresos creando y votando contenido. Usa un sistema muy sólido de puntos digitales llamado Steem que soporta valor real gracias al precio de mercado y gracias a su liquidez.",
+ "learn_more_at_app_url": "Aprende más en %(APP_URL)s",
+ "resources": "Recursos"
+ },
+ "markdownviewer_jsx": {
+ "images_were_hidden_due_to_low_ratings":
+ "Las imágenes fueron ocultadas por bajas calificaciones."
+ },
+ "postsummary_jsx": {
+ "resteemed": "reesteemeado",
+ "resteemed_by": "Resteemeado por",
+ "reveal_it": "revelarlo",
+ "adjust_your": "ajustar tu",
+ "display_preferences": "Visualizar preferencias",
+ "create_an_account": "crea una cuenta",
+ "to_save_your_preferences": "para guardar tus preferencias"
+ },
+ "posts_index": {
+ "empty_feed_1": "Parece que no has seguido nada todavía",
+ "empty_feed_2":
+ "Si recientemente has añadido a gente para seguir, tu feed personalizado aparecerá una vez que el contenido esté disponible",
+ "empty_feed_3": "Explorar artículos en tendencia",
+ "empty_feed_4": "leer la guía básica para comenzar",
+ "empty_feed_5": "Explorar la FAQ"
+ },
+ "transferhistoryrow_jsx": {
+ "to_savings": "a ahorros",
+ "from_savings": "desde ahorros",
+ "cancel_transfer_from_savings": "Cancela transferencia desde ahorros",
+ "stop_power_down": "Para power down",
+ "start_power_down_of": "Comenzar power down",
+ "receive_interest_of": "Recibir interés de"
+ },
+ "savingswithdrawhistory_jsx": {
+ "cancel_this_withdraw_request": "¿Cancelar la petición de retirada?",
+ "pending_savings_withdrawals": "AHORROS PENDIENTES DE RETIRADA",
+ "withdraw": "Retirar %(amount)s",
+ "to": "a %(to)s",
+ "from_to": "de %(from)s a %(to)s"
+ },
+ "explorepost_jsx": {
+ "copied": "¡Copiado!",
+ "copy": "COPIAR",
+ "alternative_sources": "Fuentes alternativas"
+ },
+ "header_jsx": {
+ "home": "inicio",
+ "create_a_post": "Crear una publicación",
+ "change_account_password": "Cambiar Contraseña de la Cuenta",
+ "create_account": "Crear cuenta",
+ "stolen_account_recovery": "Recuperación de cuentas robadas",
+ "people_following": "Gente que sigues",
+ "people_followed_by": "Gente seguida por",
+ "curation_rewards_by": "Recompensas de curación de",
+ "author_rewards_by": "Recompensas de autor de",
+ "replies_to": "Respuestas a",
+ "comments_by": "Comentarios de"
+ },
+ "loginform_jsx": {
+ "you_need_a_private_password_or_key":
+ "Necesitas la contraseña privada (no la contraseña pública)",
+ "cryptography_test_failed": "El test cryptográfico no tuvo éxito",
+ "unable_to_log_you_in": "No puedes acceder con este navegador",
+ "the_latest_versions_of": "Las últimas versiones de",
+ "are_well_tested_and_known_to_work_with":
+ "han sido testeados con éxito y están preparados para trabajar con %(APP_URL)s.",
+ "due_to_server_maintenance":
+ "Debido a tareas de mantenimiento sólo estamos disponibles en modo lectura. Pedimos disculpas por los inconvenientes",
+ "login_to_vote": "Acceso para Votar",
+ "login_to_post": "Acceso para postear",
+ "login_to_comment": "Acceso para comentar",
+ "posting": "Postear",
+ "active_or_owner": "Activa o propietaria",
+ "this_password_is_bound_to_your_account_owner_key":
+ "Esta contraseña está ligada a tu contraseña owner o propia y no puede ser usada para acceder a esta página.",
+ "however_you_can_use_it_to": "Sin embargo, puedes usarla para",
+ "update_your_password": "cambiar tu contraseña",
+ "to_obtain_a_more_secure_set_of_keys":
+ "obtener un grupo más seguro de contraseñas.",
+ "this_password_is_bound_to_your_account_active_key":
+ "Esta contraseña está ligada tu contraseña activa y no puede ser usada para acceder a esta página.",
+ "you_may_use_this_active_key_on_other_more":
+ "Puede usar la contraseña activa en otras páginas más seguras como el Monedero.",
+ "you_account_has_been_successfully_created":
+ "Tu cuenta se ha creado con éxito!",
+ "you_account_has_been_successfully_recovered":
+ "Tu cuenta ha sido recuperada con éxito!",
+ "password_update_succes":
+ "La contraseña %(accountName)s ha sido cambiada correctamente",
+ "password_info":
+ "La contraseña o la contraseña privada fue introducida incorrectamente. Probablemente. Ayuda: Las contraseñas generadas por Steemit nunca contendrán 0 (cero), O (o mayúscula), I (i mayúscula), l (L minúscula).",
+ "enter_your_username": "Introduce tu nombre de usuario",
+ "password_or_wif": "Contraseña o WIF",
+ "this_operation_requires_your_key_or_master_password":
+ "Esta operación requiere %(authType)s contraseña o la contraseña maestra",
+ "keep_me_logged_in": "Manténme logeado",
+ "amazing_community": "comunidad increíble",
+ "to_comment_and_reward_others": "para comentar y recompensar a otros",
+ "sign_up_get_steem": "Crea una cuenta. Comienza en STEEM",
+ "signup_button": "Crea una cuenta, comienza a ganar ",
+ "signup_button_emphasis": "FREE STEEM!",
+ "returning_users": "Inicia sesion",
+ "join_our": "Únete a nuestro"
+ },
+ "chainvalidation_js": {
+ "account_name_should": "El nombre de la cuenta debería",
+ "not_be_empty": "No estar vacío",
+ "be_longer": "ser más largo",
+ "be_shorter": "ser más corto.",
+ "each_account_segment_should": "Cada segmento de la cuenta debería",
+ "start_with_a_letter": "comenzar con una letra.",
+ "have_only_letters_digits_or_dashes":
+ "tener sólo letras, dígitos o guiones.",
+ "have_only_one_dash_in_a_row": "tener sólo un guión consecutivo.",
+ "end_with_a_letter_or_digit": "terminar con una legra o dígito.",
+ "verified_exchange_no_memo":
+ "Tienes que incluir un memo para la transferencia al exchange"
+ },
+ "settings_jsx": {
+ "invalid_url": "URL inválida",
+ "name_is_too_long": "El nombre es demasiado largo.",
+ "name_must_not_begin_with": "El nombre no debe empezar con @",
+ "about_is_too_long": "Sobre es demasiado largo",
+ "location_is_too_long": "Localización es demasiado largo",
+ "website_url_is_too_long": "La URL de la página web es muy larga",
+ "public_profile_settings": "Herramientas para el perfil público",
+ "preferences": "Herramientas privadas para la visualización del post",
+ "not_safe_for_work_nsfw_content": "(NSFW) contenido para adultos",
+ "always_hide": "Ocultar siempre",
+ "always_warn": "Advertir siempre",
+ "always_show": "Mostrar siempre",
+ "muted_users": "Usuarios silenciados",
+ "update": "Actualizar",
+ "profile_image_url": "Link para la foto de perfil",
+ "cover_image_url": "Link para la imagen de fondo",
+ "profile_name": "Nombre de visualización",
+ "profile_about": "Sobre",
+ "profile_location": "Localización",
+ "profile_website": "Página Web"
+ },
+ "transfer_jsx": {
+ "amount_is_in_form": "La cantidad está en el formato 99999.999",
+ "insufficient_funds": "Saldo insuficiente",
+ "use_only_3_digits_of_precison": "Usa solo 3 dígitos",
+ "send_to_account": "Mandar a cuenta",
+ "asset": "Activo",
+ "this_memo_is_private": "Esta memo es privada",
+ "this_memo_is_public": "Esta memo es pública",
+ "convert_to_VESTING_TOKEN": "Convertir a %(VESTING_TOKEN)s",
+ "balance_subject_to_3_day_withdraw_waiting_period":
+ "El saldo está sujeto a 3 días de espera para la retirada",
+ "move_funds_to_another_account":
+ "Mover fondos a otra %(APP_NAME)scuenta.",
+ "protect_funds_by_requiring_a_3_day_withdraw_waiting_period":
+ "Protege los fondos al pedir la retirada con un periodo de 3 días de espera",
+ "withdraw_funds_after_the_required_3_day_waiting_period":
+ "Retirada de fondos después del periodo de 3 días de espera",
+ "from": "De",
+ "to": "Para",
+ "asset_currently_collecting":
+ "%(asset)s recolectando actualmente %(interest)s%% APR.",
+ "beware_of_spam_and_phishing_links":
+ "Tenga cuidado con los enlaces de spam y phishing en los memos de transferencia. No abra enlaces de usuarios en los que no confíe. No proporcione sus claves privadas a sitios web de terceros."
+ },
+ "userwallet_jsx": {
+ "conversion_complete_tip": "Se completará el",
+ "in_conversion": "%(amount)s en conversión",
+ "transfer_to_savings": "Transferir a ahorros",
+ "power_up": "Power up",
+ "power_down": "Power down",
+ "market": "Mercado",
+ "convert_to_LIQUID_TOKEN": "Convertir a %(LIQUID_TOKEN)s",
+ "withdraw_LIQUID_TOKEN": "Retirar %(LIQUID_TOKEN)s",
+ "withdraw_DEBT_TOKENS": "Retirar %(DEBT_TOKENS)s",
+ "tokens_worth_about_1_of_LIQUID_TICKER":
+ "Los tokens valen alrededor de $1.00 de %(LIQUID_TICKER)s, ahora mismo recolectando %(sbdInterest)s%% APR.",
+ "savings": "AHORROS",
+ "estimated_account_value": "Valor de cuenta aproximado",
+ "next_power_down_is_scheduled_to_happen":
+ "El siguiente power down ocurrirá en ",
+ "transfers_are_temporary_disabled":
+ "Las transferencias están temporalmente inhabilitadas.",
+ "history": "HISTORIA",
+ "redeem_rewards": "Liquidar recompensas (Transferir al saldo)",
+ "buy_steem_or_steem_power": "Compra STEEM o STEEM POWER."
+ },
+ "powerdown_jsx": {
+ "power_down": "Power Down",
+ "amount": "Cantidad",
+ "already_power_down":
+ "Estás haciendo un power down de %(AMOUNT)s%(LIQUID_TICKER)s (%(WITHDRAWN)s%(LIQUID_TICKER)shan sido pagados hasta ahora). Ten en cuenta que si cambias la cantidad de \"power down\" la fecha de pago se reinicializará.",
+ "delegating":
+ "Estás delegando %(AMOUNT)s%(LIQUID_TICKER)s. Esa cantidad está \"bloquedada\" y no podrás hacer \"power down\" con ella hasta que hayas cancelado la delegación y el periodo de pagos haya vencido.",
+ "per_week": "Eso es %(AMOUNT)s%(LIQUID_TICKER)spor semana",
+ "warning":
+ "Dejar menos de %(AMOUNT)s%(VESTING_TOKEN)s en su cuenta no es recomendable y puede dejarla en un estado inutilizable.",
+ "error": "Imposible hacer \"power down\" (ERROR: %(MESSAGE)s)"
+ },
+ "checkloginowner_jsx": {
+ "your_password_permissions_were_reduced":
+ "Sus permisos de identificacion han sido limitados.",
+ "if_you_did_not_make_this_change": "Si no ha hecho el cambio por favor",
+ "ownership_changed_on": "Pertenencia cambio el",
+ "deadline_for_recovery_is": "La fecha límite para la recuperación es",
+ "i_understand_dont_show_again": "Lo entiendo, no mostrarmelo de nuevo."
}
- },
- "userkeys_jsx": {
- "public": "Público",
- "private": "Privado",
- "public_something_key": "Contraseña %(count)s pública",
- "private_something_key": "Contraseña %(count)s privada",
- "posting_key_is_required_it_should_be_different": "La contraseña de posteado se usa para postear y para votar. Debería ser diferente a la contraseña activa y a la contraseña de propietario.",
- "the_active_key_is_used_to_make_transfers_and_place_orders": "La contraseña activa se usa para hacer transferencias y poner órdenes de compra o venta en el mercado interno.",
- "the_owner_key_is_required_to_change_other_keys": "La contraseña propia es la contraseña maestra para la cuenta y se requiere para cambiar el resto de las contraseñas.",
- "the_private_key_or_password_should_be_kept_offline": "La contraseña privada para la cuenta propia debería estar fuera del acceso a internet. Se recomienda imprimirla y guardarla en lugar seguro.",
- "the_memo_key_is_used_to_create_and_read_memos": "La contraseña memo se usa para crear y leer memos."
- },
- "suggestpassword_jsx": {
- "APP_NAME_cannot_recover_passwords_keep_this_page_in_a_secure_location": "%(APP_NAME)s no puede recuperar contraseñas. Guarda está página en lugar seguro, como en una caja fuerte o una caja de depósito",
- "APP_NAME_password_backup": "%(APP_NAME)s Contraseña de apoyo o seguridad",
- "APP_NAME_password_backup_required": "%(APP_NAME)s Contraseña de apoyo o seguridad (requerida)",
- "after_printing_write_down_your_user_name": "Después de imprimir, escribe tu nombre de usuario"
- },
- "converttosteem_jsx": {
- "your_existing_DEBT_TOKEN_are_liquid_and_transferable": "La cantidad de %(DEBT_TOKEN)s son líquidos y transferibles. Si lo deseas también puedes comprar o vender %(DEBT_TOKEN)s directamente en esta página en el %(link)s o transferir a un mercado externo",
- "this_is_a_price_feed_conversion": "Esto es la conversión de precio. Los 3.5 días de retraso son necesarios para prevenir el abuso con las medias del precio",
- "convert_to_LIQUID_TOKEN": "Convertir a %(LIQUID_TOKEN)s",
- "DEBT_TOKEN_will_be_unavailable": "Esta acción tardará 3.5 días en procesarse y no puede ser cancelada. Estos %(DEBT_TOKEN)s dejarán inmediatamente de estar disponibles"
- },
- "tips_js": {
- "liquid_token": "Tokens canjeables pueden ser transferidos a cualquier sitio en cualquier momento.1%(LIQUID_TOKEN)s y pueden ser convertidos a %(VESTING_TOKEN)s en un proceso llamado power up.",
- "influence_token": "Tokens con influencia te dan más control sobre los pagos de los posts y te permiten ganar recompensas de curación",
- "estimated_value": "El valor estimado está basado en el valor medio de 1%(LIQUID_TOKEN)s en US dollars.",
- "non_transferable": "%(VESTING_TOKEN)s es intransferible y requiere 3 meses (13 pagos) para convertir de vuelta a %(LIQUID_TOKEN)s.",
- "converted_VESTING_TOKEN_can_be_sent_to_yourself_but_can_not_transfer_again": "Los %(VESTING_TOKEN)s convertidos pueden ser enviados a ti mismo o a otras personas pero no pueden ser transferidos de nuevo sin convertirlos de vuelta a %(LIQUID_TOKEN)s.",
- "part_of_your_steem_power_is_currently_delegated": "Parte de tu STEEM POWER te ha sido delegado. La delegación es influencia donada que ayuda a los nuevos usuarios a interactuar en steemit. La cantidad de tu delegación puede fluctuar."
- },
- "promote_post_jsx": {
- "promote_post": "Promociona el Post",
- "spend_your_DEBT_TOKEN_to_advertise_this_post": "Gasta tu %(DEBT_TOKEN)s para promocionar tu contenido en la sección de promoción",
- "you_successfully_promoted_this_post": "Has promocionado satisfactoriamente este post",
- "this_post_was_hidden_due_to_low_ratings": "El post ha sido ocultado por bajas calificaciones"
- },
- "about_jsx": {
- "about_app": "Sobre %(APP_NAME)s",
- "about_app_details": "%(APP_NAME)s es una plataforma social online donde todo el mundo genera ingresos creando y votando contenido. Usa un sistema muy sólido de puntos digitales llamado Steem que soporta valor real gracias al precio de mercado y gracias a su liquidez.",
- "learn_more_at_app_url": "Aprende más en %(APP_URL)s",
- "resources": "Recursos"
- },
- "markdownviewer_jsx": {
- "images_were_hidden_due_to_low_ratings": "Las imágenes fueron ocultadas por bajas calificaciones."
- },
- "postsummary_jsx": {
- "resteemed": "reesteemeado",
- "resteemed_by": "Resteemeado por",
- "reveal_it": "revelarlo",
- "adjust_your": "ajustar tu",
- "display_preferences": "Visualizar preferencias",
- "create_an_account": "crea una cuenta",
- "to_save_your_preferences": "para guardar tus preferencias"
- },
- "posts_index": {
- "empty_feed_1": "Parece que no has seguido nada todavía",
- "empty_feed_2": "Si recientemente has añadido a gente para seguir, tu feed personalizado aparecerá una vez que el contenido esté disponible",
- "empty_feed_3": "Explorar artículos en tendencia",
- "empty_feed_4": "leer la guía básica para comenzar",
- "empty_feed_5": "Explorar la FAQ"
- },
- "transferhistoryrow_jsx": {
- "to_savings": "a ahorros",
- "from_savings": "desde ahorros",
- "cancel_transfer_from_savings": "Cancela transferencia desde ahorros",
- "stop_power_down": "Para power down",
- "start_power_down_of": "Comenzar power down",
- "receive_interest_of": "Recibir interés de"
- },
- "savingswithdrawhistory_jsx": {
- "cancel_this_withdraw_request": "¿Cancelar la petición de retirada?",
- "pending_savings_withdrawals": "AHORROS PENDIENTES DE RETIRADA",
- "withdraw": "Retirar %(amount)s",
- "to": "a %(to)s",
- "from_to": "de %(from)s a %(to)s"
- },
- "explorepost_jsx": {
- "copied": "¡Copiado!",
- "copy": "COPIAR",
- "alternative_sources": "Fuentes alternativas"
- },
- "header_jsx": {
- "home": "inicio",
- "create_a_post": "Crear una publicación",
- "change_account_password": "Cambiar Contraseña de la Cuenta",
- "create_account": "Crear cuenta",
- "stolen_account_recovery": "Recuperación de cuentas robadas",
- "people_following": "Gente que sigues",
- "people_followed_by": "Gente seguida por",
- "curation_rewards_by": "Recompensas de curación de",
- "author_rewards_by": "Recompensas de autor de",
- "replies_to": "Respuestas a",
- "comments_by": "Comentarios de"
- },
- "loginform_jsx": {
- "you_need_a_private_password_or_key": "Necesitas la contraseña privada (no la contraseña pública)",
- "cryptography_test_failed": "El test cryptográfico no tuvo éxito",
- "unable_to_log_you_in": "No puedes acceder con este navegador",
- "the_latest_versions_of": "Las últimas versiones de",
- "are_well_tested_and_known_to_work_with": "han sido testeados con éxito y están preparados para trabajar con %(APP_URL)s.",
- "due_to_server_maintenance": "Debido a tareas de mantenimiento sólo estamos disponibles en modo lectura. Pedimos disculpas por los inconvenientes",
- "login_to_vote": "Acceso para Votar",
- "login_to_post": "Acceso para postear",
- "login_to_comment": "Acceso para comentar",
- "posting": "Postear",
- "active_or_owner": "Activa o propietaria",
- "this_password_is_bound_to_your_account_owner_key": "Esta contraseña está ligada a tu contraseña owner o propia y no puede ser usada para acceder a esta página.",
- "however_you_can_use_it_to": "Sin embargo, puedes usarla para",
- "update_your_password": "cambiar tu contraseña",
- "to_obtain_a_more_secure_set_of_keys": "obtener un grupo más seguro de contraseñas.",
- "this_password_is_bound_to_your_account_active_key": "Esta contraseña está ligada tu contraseña activa y no puede ser usada para acceder a esta página.",
- "you_may_use_this_active_key_on_other_more": "Puede usar la contraseña activa en otras páginas más seguras como el Monedero.",
- "you_account_has_been_successfully_created": "Tu cuenta se ha creado con éxito!",
- "you_account_has_been_successfully_recovered": "Tu cuenta ha sido recuperada con éxito!",
- "password_update_succes": "La contraseña %(accountName)s ha sido cambiada correctamente",
- "password_info": "La contraseña o la contraseña privada fue introducida incorrectamente. Probablemente. Ayuda: Las contraseñas generadas por Steemit nunca contendrán 0 (cero), O (o mayúscula), I (i mayúscula), l (L minúscula).",
- "enter_your_username": "Introduce tu nombre de usuario",
- "password_or_wif": "Contraseña o WIF",
- "this_operation_requires_your_key_or_master_password": "Esta operación requiere %(authType)s contraseña o la contraseña maestra",
- "keep_me_logged_in": "Manténme logeado",
- "amazing_community": "comunidad increíble",
- "to_comment_and_reward_others": "para comentar y recompensar a otros",
- "sign_up_get_steem": "Sign up. Get STEEM",
- "signup_button": "Sign up now to earn ",
- "signup_button_emphasis": "FREE STEEM!",
- "returning_users": "Usuarios que vuelven",
- "join_our": "Únete a nuestro"
- },
- "chainvalidation_js": {
- "account_name_should": "El nombre de la cuenta debería",
- "not_be_empty": "No estar vacío",
- "be_longer": "ser más largo",
- "be_shorter": "ser más corto.",
- "each_account_segment_should": "Cada segmento de la cuenta debería",
- "start_with_a_letter": "comenzar con una letra.",
- "have_only_letters_digits_or_dashes": "tener sólo letras, dígitos o guiones.",
- "have_only_one_dash_in_a_row": "tener sólo un guión consecutivo.",
- "end_with_a_letter_or_digit": "terminar con una legra o dígito.",
- "verified_exchange_no_memo": "Tienes que incluir un memo para la transferencia al exchange"
- },
- "settings_jsx": {
- "invalid_url": "URL inválida",
- "name_is_too_long": "El nombre es demasiado largo.",
- "name_must_not_begin_with": "El nombre no debe empezar con @",
- "about_is_too_long": "Sobre es demasiado largo",
- "location_is_too_long": "Localización es demasiado largo",
- "website_url_is_too_long": "La URL de la página web es muy larga",
- "public_profile_settings": "Herramientas para el perfil público",
- "private_post_display_settings": "Herramientas privadas para la visualización del post",
- "not_safe_for_work_nsfw_content": "(NSFW) contenido para adultos",
- "always_hide": "Ocultar siempre",
- "always_warn": "Advertir siempre",
- "always_show": "Mostrar siempre",
- "muted_users": "Usuarios silenciados",
- "update": "Actualizar",
- "profile_image_url": "Link para la foto de perfil",
- "cover_image_url": "Link para la imagen de fondo",
- "profile_name": "Nombre de visualización",
- "profile_about": "Sobre",
- "profile_location": "Localización",
- "profile_website": "Página Web"
- },
- "transfer_jsx": {
- "amount_is_in_form": "La cantidad está en el formato 99999.999",
- "insufficient_funds": "Saldo insuficiente",
- "use_only_3_digits_of_precison": "Usa solo 3 dígitos",
- "send_to_account": "Mandar a cuenta",
- "asset": "Activo",
- "this_memo_is_private": "Esta memo es privada",
- "this_memo_is_public": "Esta memo es pública",
- "convert_to_VESTING_TOKEN": "Convertir a %(VESTING_TOKEN)s",
- "balance_subject_to_3_day_withdraw_waiting_period": "El saldo está sujeto a 3 días de espera para la retirada",
- "move_funds_to_another_account": "Mover fondos a otra %(APP_NAME)scuenta.",
- "protect_funds_by_requiring_a_3_day_withdraw_waiting_period": "Protege los fondos al pedir la retirada con un periodo de 3 días de espera",
- "withdraw_funds_after_the_required_3_day_waiting_period": "Retirada de fondos después del periodo de 3 días de espera",
- "from": "De",
- "to": "Para",
- "asset_currently_collecting": "%(asset)s recolectando actualmente %(interest)s%% APR.",
- "beware_of_spam_and_phishing_links": "Beware of spam and phishing links in transfer memos. Do not open links from users you do not trust. Do not provide your private keys to any third party websites."
- },
- "userwallet_jsx": {
- "conversion_complete_tip": "Se completará el",
- "in_conversion": "%(amount)s en conversión",
- "transfer_to_savings": "Transferir a ahorros",
- "power_up": "Power up",
- "power_down": "Power down",
- "market": "Mercado",
- "convert_to_LIQUID_TOKEN": "Convertir a %(LIQUID_TOKEN)s",
- "withdraw_LIQUID_TOKEN": "Retirar %(LIQUID_TOKEN)s",
- "withdraw_DEBT_TOKENS": "Retirar %(DEBT_TOKENS)s",
- "tokens_worth_about_1_of_LIQUID_TICKER": "Los tokens valen alrededor de $1.00 de %(LIQUID_TICKER)s, ahora mismo recolectando %(sbdInterest)s%% APR.",
- "savings": "AHORROS",
- "estimated_account_value": "Valor de cuenta aproximado",
- "next_power_down_is_scheduled_to_happen": "El siguiente power down ocurrirá en ",
- "transfers_are_temporary_disabled": "Las transferencias están temporalmente inhabilitadas.",
- "history": "HISTORIA",
- "redeem_rewards": "Liquidar recompensas (Transferir al saldo)",
- "buy_steem_or_steem_power": "Compra STEEM o STEEM POWER."
- },
- "powerdown_jsx": {
- "power_down": "Power Down",
- "amount": "Cantidad",
- "already_power_down": "Estás haciendo un power down de %(AMOUNT)s%(LIQUID_TICKER)s (%(WITHDRAWN)s%(LIQUID_TICKER)shan sido pagados hasta ahora). Ten en cuenta que si cambias la cantidad de \"power down\" la fecha de pago se reinicializará.",
- "delegating": "Estás delegando %(AMOUNT)s%(LIQUID_TICKER)s. Esa cantidad está \"bloquedada\" y no podrás hacer \"power down\" con ella hasta que hayas cancelado la delegación y el periodo de pagos haya vencido.",
- "per_week": "Eso es %(AMOUNT)s%(LIQUID_TICKER)spor semana",
- "warning": "Dejar menos de %(AMOUNT)s%(VESTING_TOKEN)s en su cuenta no es recomendable y puede dejarla en un estado inutilizable.",
- "error": "Imposible hacer \"power down\" (ERROR: %(MESSAGE)s)"
- },
- "checkloginowner_jsx": {
- "your_password_permissions_were_reduced": "Sus permisos de identificacion han sido limitados.",
- "if_you_did_not_make_this_change": "Si no ha hecho el cambio por favor",
- "ownership_changed_on": "Pertenencia cambio el",
- "deadline_for_recovery_is": "La fecha límite para la recuperación es",
- "i_understand_dont_show_again": "Lo entiendo, no mostrarmelo de nuevo."
- }
}
diff --git a/src/app/locales/fr.json b/src/app/locales/fr.json
index 1c3d3f1ca54942ff0a892dddfb01e4f4a301b2a6..a2b6509dc9aa0dacfb8e8797fa1ef60a429cd85d 100644
--- a/src/app/locales/fr.json
+++ b/src/app/locales/fr.json
@@ -1,648 +1,793 @@
{
- "g": {
- "age": "ancienneté",
- "amount": "Montant",
- "and": "et",
- "are_you_sure": "Etes-vous sûr(e) ?",
- "ask": "Demande",
- "balance": "Solde",
- "balances": "Soldes",
- "bid": "Offre",
- "blog": "Blog",
- "browse": "Naviguer",
- "buy": "Acheter",
- "buy_or_sell": "Acheter ou vendre",
- "by": "par",
- "cancel": "Annuler",
- "change_password": "Changer le mot de passe",
- "choose_language": "Choisir la langue",
- "clear": "Effacer",
- "close": "Fermer",
- "collapse_or_expand": "Compacter / Etendre",
- "comments": "Commentaires",
- "confirm": "Confirmer",
- "convert": "Convertir",
- "date": "Date",
- "delete": "Supprimer",
- "dismiss": "Ignorer",
- "edit": "Editer",
- "email": "Email",
- "feed": "Flux",
- "follow": "S'abonner",
- "for": "pour",
- "from": "de",
- "go_back": "Retour",
- "hide": "Masquer",
- "in": "dans",
- "in_reply_to": "en réponse à",
- "insufficient_balance": "Solde insuffisant",
- "invalid_amount": "Montant invalide",
- "joined": "Inscrit en",
- "loading": "Chargement en cours",
- "login": "Se connecter",
- "logout": "Déconnexion",
- "memo": "Note",
- "mute": "Ignorer",
- "new": "nouveau",
- "newer": "Plus récent",
- "next": "Suivant",
- "no": "Non",
- "ok": "Ok",
- "older": "Plus ancien",
- "or": "ou",
- "order_placed": "Ordre effectué",
- "password": "Mot de passe",
- "payouts": "Gains",
- "permissions": "Permissions",
- "phishy_message": "Link expanded to plain text; beware of a potential phishing attempt",
- "post": "Poster",
- "post_as": "Poster en tant que",
- "posts": "Articles",
- "powered_up_100": "Converti en influence à 100%%",
- "preview": "Prévisualiser",
- "previous": "Précédent",
- "price": "Prix",
- "print": "Imprimer",
- "promote": "Promouvoir",
- "promoted": "promu",
- "re": "RE",
- "re_to": "RE :%(topic)s",
- "recent_password": "Mot de passe antérieur",
- "receive": "Recevoir",
- "remove": "Enlever",
- "remove_vote": "Enlever son vote",
- "replied_to": "répondu à %(account)s",
- "replies": "Réponses",
- "reply": "Répondre",
- "reply_count": {
- "zero": "pas de réponse",
- "one": "1 réponse",
- "other": "%(count)s réponses"
- },
- "reputation": "Réputation",
- "reveal_comment": "Révéler le commentaire",
- "request": "requête",
- "required": "Requis",
- "rewards": "Gains",
- "save": "Sauvegarder",
- "saved": "Sauvegardé",
- "search": "Rechercher",
- "sell": "Vendre",
- "settings": "Configuration",
- "share_this_post": "Partager cet article",
- "show": "Montrer",
- "sign_in": "S'inscrire",
- "sign_up": "S'inscrire",
- "since": "depuis",
- "submit": "Soumettre",
- "power_up": "Augmenter son influence",
- "submit_a_story": "Poster",
- "tag": "Mot clé",
- "to": "vers",
- "all_tags": "All tags",
- "transfer": "Transférer",
- "trending_topics": "Sujets en vogue",
- "type": "Genre",
- "unfollow": "Se désabonner",
- "unmute": "Ne plus ignorer",
- "unknown": "Inconnu",
- "upvote": "Voter pour",
- "upvote_post": "Voter pour l'article",
- "username": "Identifiant",
- "version": "Version",
- "vote": "Voter",
- "votes": "votes",
- "wallet": "Portefeuille",
- "warning": "alarme",
- "yes": "Oui",
- "posting": "de publication",
- "owner": "propriétaire",
- "active": "active",
- "account_not_found": "Compte inconnu",
- "this_is_wrong_password": "Mot de passe incorrect",
- "do_you_need_to": "Avez-vous besoin de",
- "account_name": "Nom du compte",
- "recover_your_account": "Récupérer son compte",
- "reset_usernames_password": "Réinitialiser le mot de passe de %(username)s",
- "this_will_update_usernames_authtype_key": "Ceci mettra a jour la clé %(authType)s de %(username)s",
- "passwords_do_not_match": "Mots de passe différents",
- "you_need_private_password_or_key_not_a_public_key": "La clé ou le mot de passe privé (et non public) est nécessaire ",
- "the_rules_of_APP_NAME": {
- "one": "La première règle de %(APP_NAME)s est de ne pas perdre son mot de passe.",
- "second": "La deuxième règle de %(APP_NAME)s est de ne pas perdre son mot de passe.",
- "third": "La troisième règle de %(APP_NAME)s est que nous ne pouvons réinitialiser votre mot de passe.",
- "fourth": "La quatrième règle est que si vous pouvez vous rappeler de votre mot de passe, il n'est pas assez sécuritaire.",
- "fifth": "La cinquième règle demande d'utiliser uniquement des mots de passe générés aléatoirement.",
- "sixth": "La sixième règle est de ne donner à personne son mot de passe.",
- "seventh": "La septième règle est de faire une sauvegarde de son mot de passe."
- },
- "recover_password": "Récupérer un compte",
- "current_password": "Mot de passe actuel",
- "generated_password": "Mot de passe généré",
- "backup_password_by_storing_it": "A sauvegarder en le copiant dans un fichier texte ou via un logiciel de gestion de mot de passe",
- "enter_account_show_password": "Entrer un identifiant valide pour afficher le mot de passe",
- "click_to_generate_password": "Cliquer ici pour générer un mot de passe",
- "re_enter_generate_password": "Recopier le mot de passe généré",
- "understand_that_APP_NAME_cannot_recover_password": "Je comprends que %(APP_NAME)s ne peut récupérer les mots de passe perdus",
- "i_saved_password": "J'ai sauvegardé mon mot de passe de façon sécuritaire",
- "update_password": "Mettre à jour le mot de passe",
- "confirm_password": "Confirmer le mot de passe",
- "account_updated": "Compte mis à jour",
- "password_must_be_characters_or_more": "Le mot de passe doit comporter au moins %(amount)s caractères supplémentaires",
- "need_password_or_key": "Il vous faut une clé ou un mot de passe privé (et non public)",
- "login_to_see_memo": "S'identifier pour voir le mémo",
- "new_password": "Nouveau mot de passe",
- "incorrect_password": "Mot de passe incorrect",
- "username_does_not_exist": "Cet identifiant n'existe pas",
- "account_name_should_start_with_a_letter": "L'identifiant doit commencer par une lettre.",
- "account_name_should_be_shorter": "L'identifiant doit être plus court.",
- "account_name_should_be_longer": "L'identifiant doit être plus long.",
- "account_name_should_have_only_letters_digits_or_dashes": "L'identifiant ne peut comporter que des lettres, des chiffres ou des traits d'union.",
- "cannot_increase_reward_of_post_within_the_last_minute_before_payout": "Les gains d'un article ne peuvent être accrus durant la dernière minute avant rétribution.",
- "vote_currently_exists_user_must_be_indicate_a_to_reject_witness": "un vote existe actuellement; l'utilisateur doit indiquer une raison pour rejeter le témoin",
- "only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes": "Un seul compte Steem est permis par adresse IP toutes les 10 minutes",
- "resteem_this_post": "Resteemer cet article",
- "reblog": "Resteem",
- "write_your_story": "Ecris ton histoire",
- "remember_voting_and_posting_key": "Se souvenir de la clé de publication et de vote",
- "auto_login_question_mark": "Identification automatique",
- "hide_private_key": "Masquer la clé privée",
- "show_private_key": "Révéler la clé privée",
- "login_to_show": "S'identifier pour révéler",
- "not_valid_email": "Adresse email invalide",
- "thank_you_for_being_an_early_visitor_to_APP_NAME": "Merci pour être l'un des premiers visiteurs de %(APP_NAME)s. Nous reviendrons vers vous aussi tôt que possible.",
- "author_rewards": "Gains éditoriaux",
- "curation_rewards": "Gains de curation",
- "sorry_your_reddit_account_doesnt_have_enough_karma": "Désolé, votre compte Reddit ne possède pas de Karma Reddit suffisant pour vous qualifier pour une inscription gratuite. Veuillez s'il-vous-plaît indiquer votre adresse email pour être placé(e) sur liste d'attente.",
- "register_with_facebook": "S'enregistrer par Facebook",
- "or_click_the_button_below_to_register_with_facebook": "Ou cliquer sur le bouton ci-dessous pour vous enregistrer par Facebook",
- "server_returned_error": "le serveur a renvoyé une erreur",
- "APP_NAME_support": "Support pour %(APP_NAME)s",
- "please_email_questions_to": "Veuillez s'il-vous-plaît envoyer vos questions par email à",
- "next_7_strings_single_block": {
- "authors_get_paid_when_people_like_you_upvote_their_post": "Les auteurs sont payés lorsque des personnes comme vous votent pour leur contenu",
- "if_you_enjoyed_what_you_read_earn_amount": "Si vous avez apprécié ce que vous avez lu ici, créez votre compte dès à présent et commencer par gagner immédiatement du STEEM",
- "free_steem": "STEEM GRATUIT!",
- "sign_up_earn_steem": "S'enregistrer pour gagner"
- },
- "next_3_strings_together": {
- "show_more": "Révéler plus",
- "show_less": "Révéler moins",
- "value_posts": "Articles de faible valeur"
- },
- "read_only_mode": "En raison d'une maintenance des serveurs, le site est en mode lecture seule. Nous sommes désolés pour le désagrément. ",
- "tags_and_topics": "Mots clés et sujets",
- "show_more_topics": "Révéler plus de sujets",
- "basic": "Basique",
- "advanced": "Avancé",
- "views": {
- "zero": "Pas de vue",
- "one": "%(count)s vue",
- "other": "%(count)s vues"
- },
- "responses": {
- "zero": "Pas de réponse",
- "one": "%(count)s réponse",
- "other": "%(count)s réponses"
- },
- "post_key_warning": {
- "confirm": "You are about to publish a STEEM private key or master password. You will probably lose control of the associated account and all its funds.",
- "warning": "Legitimate users, including employees of Steemit Inc., will never ask you for a private key or master password.",
- "checkbox": "I understand"
- }
- },
- "navigation": {
- "about": "A propos",
- "explore": "Explorer",
- "APP_NAME_whitepaper": "%(APP_NAME)s livre blanc",
- "buy_LIQUID_TOKEN": "Acheter %(LIQUID_TOKEN)s",
- "sell_LIQUID_TOKEN": "Vendre %(LIQUID_TOKEN)s",
- "currency_market": "Marché des devises",
- "stolen_account_recovery": "Récupération de comptes dérobés",
- "change_account_password": "Changement de mot de passe",
- "witnesses": "Témoins",
- "vote_for_witnesses": "Voter pour les témoins",
- "privacy_policy": "Politique de confidentialité",
- "terms_of_service": "Conditions d'utilisation",
- "sign_up": "Rejoindre",
- "learn_more": "En savoir plus",
- "welcome": "Bienvenue",
- "faq": "FAQ",
- "shop": "The Steemit Shop",
- "chat": "Salons de discussion Steemit",
- "app_center": "Centre d'applications Steemit",
- "api_docs": "Documentation API sur Steemit",
- "whitepaper": "Livre blanc sur le Steem",
- "bluepaper": "Steem Bluepaper",
- "intro_tagline": "Présentations sur la monnaie",
- "intro_paragraph": "Votre voix vaut quelque chose. Rejoignez la communauté qui vous rémunère pour vos articles et participez à la curation du contenu de qualité."
- },
- "main_menu": {
- "hot": "chaud",
- "trending": "en vogue"
- },
- "reply_editor": {
- "shorten_title": "Raccourcir le titre",
- "exceeds_maximum_length": "Dépassement de la taille maximale ( %(maxKb)s KB)",
- "including_the_category": "(incluant la catégorie '%(rootCategory)s')",
- "use_limited_amount_of_tags": "Vous avez un total de %(tagsLength)s mots clés %(includingCategory)s. Veuillez en utiliser seulement 5, autant pour l'article que pour le champ dédié aux mots clés.",
- "are_you_sure_you_want_to_clear_this_form": "Etes-vous sûr de vouloir effacer ce formulaire ?",
- "uploading": "Téléchargement en cours",
- "draft_saved": "Brouillon sauvegardé",
- "editor": "Editeur",
- "insert_images_by_dragging_dropping": "Insertion d'images par 'drag and drop'",
- "pasting_from_the_clipboard": "copie depuis le presse-papier,",
- "selecting_them": "les sélectionnant",
- "image_upload": "Téléchargement d'image",
- "power_up_100": "Conversion en influence à 100%%",
- "default_50_50": "Par défaut (50 %%/ 50%%)",
- "decline_payout": "Refuser les gains",
- "check_this_to_auto_upvote_your_post": "Cocher cette case pour auto-voter pour votre article",
- "markdown_styling_guide": "Guide stylistique pour le format Markdown",
- "or_by": "ou par",
- "title": "Titre",
- "update_post": "Mettre l'article à jour",
- "markdown_not_supported": "Le format Markdown n'est pas supporté ici"
- },
- "category_selector_jsx": {
- "tag_your_story": "Mots clés (jusqu'à 5 mots clés), le premier d'entre eux étant votre catégorie principale.",
- "select_a_tag": "Sélectionner un mot clé",
- "maximum_tag_length_is_24_characters": "La longueur d'un mot clé est d'au maximum 24 caractères",
- "use_limited_amount_of_categories": "Veuillez s'il-vous-plaît n'utiliser que %(amount)s catégories",
- "use_only_lowercase_letters": "Veuillez n'utiliser que des lettres minuscules",
- "use_one_dash": "Veuillez n'utiliser qu'un seul trait d'union",
- "use_spaces_to_separate_tags": "Veuillez utiliser des espaces pour séparer les mots clés",
- "use_only_allowed_characters": "Veuillez n'utilisez que des lettres minuscules, des chiffres et au plus un trait d'union",
- "must_start_with_a_letter": "Le premier caractère doit être une lettre",
- "must_end_with_a_letter_or_number": "Le dernier caractère doit être une lettre ou un chiffre"
- },
- "postfull_jsx": {
- "this_post_is_not_available_due_to_a_copyright_claim": "Cet article n'est pas disponible en raison d'une requête de droits d'auteur.",
- "share_on_facebook": "Partager sur Facebook",
- "share_on_twitter": "Partager sur Twitter",
- "share_on_linkedin": "Partager sur Linkedin",
- "recent_password": "Mot de passe antérieur",
- "in_week_convert_DEBT_TOKEN_to_LIQUID_TOKEN": "Dans 3.5 jours, conversion de %(amount)s %(DEBT_TOKEN)s en %(LIQUID_TOKEN)s",
- "view_the_full_context": "Voir le contexte complet",
- "view_the_direct_parent": "Voir le message précédent",
- "you_are_viewing_a_single_comments_thread_from": "Vous visualisez un commentaire unique de l'article"
- },
- "market_jsx": {
- "action": "Action",
- "date_created": "Date de création",
- "last_price": "Dernier cours",
- "24h_volume": "Volume des dernières 24h",
- "spread": "Ecart",
- "total": "Total",
- "available": "Disponible",
- "lowest_ask": "Demande au taux le plus bas",
- "highest_bid": "Offre au taux le plus haut",
- "buy_orders": "Ordres d'achat",
- "sell_orders": "Ordres de vente",
- "trade_history": "Historique des échanges",
- "open_orders": "Ordres ouverts",
- "sell_amount_for_atleast": "Vendre %(amount_to_sell)s pour au moins %(min_to_receive)s ( %(effectivePrice)s )",
- "buy_atleast_amount_for": "Acheter au moins %(min_to_receive)s pour %(amount_to_sell)s ( %(effectivePrice)s )",
- "price_warning_above": "Ce cours est bien au-delà des cours du marché actuels %(marketPrice)s, êtes-vous sûr (e) ?",
- "price_warning_below": "Ce cours est bien en-deça des cours du marché actuels %(marketPrice)s, êtes-vous sûr (e) ?",
- "order_cancel_confirm": "Annuler l'ordre %(order_id)s de %(user)s",
- "order_cancelled": "Ordre %(order_id)s annulé.",
- "higher": "Plus haut",
- "lower": "Plus bas",
- "total_DEBT_TOKEN_SHORT_CURRENCY_SIGN": "Total %(DEBT_TOKEN_SHORT)s (%(CURRENCY_SIGN)s)"
- },
- "recoveraccountstep1_jsx": {
- "begin_recovery": "Démarrer la récupération",
- "not_valid": "Invalide",
- "account_name_is_not_found": "Compte inexistant",
- "unable_to_recover_account_not_change_ownership_recently": "Nous sommes incapables de récupérer ce compte, car il n'a pas changé de propriétaire récemment.",
- "password_not_used_in_last_days": "Ce mot de passe n'a pas été utilisé durant les derniers 30 jours.",
- "request_already_submitted_contact_support": "Votre requête a déjà été soumise et nous nous en occupons. Veuillez s'il-vous-plaît contacter %(SUPPORT_EMAIL)s pour obtenir le statut de votre requête.",
- "recover_account_intro": "Il est possible que la clé propriétaire d'un Steemien soit compromise. Le processus de récupération de comptes dérobés est autorisé pour l'utilisateur de droit pendant 30 jours à partir du moment où le voleur a modifié la clé propriétaire. La récupération de comptes dérobés ne peut être utilisée sur %(APP_URL)s que si le propriétaire du compte a ajouté '%(APP_NAME)s'comme mandataire de confiance et accepté les conditions d'utilisation de %(APP_NAME)s.",
- "login_with_facebook_or_reddit_media_to_verify_identity": "Veuillez vous identifier via Facebook ou Reddit pour vérifier votre identité.",
- "login_with_social_media_to_verify_identity": "Veuillez vous identifier via %(provider)safin de vérifier votre identité",
- "enter_email_toverify_identity": "Nous devons vérifier votre identité. Veuillez s'il-vous-plaît entrer votre adresse email ci-dessous pour démarrer le processus.",
- "continue_with_email": "Continuer avec l'email.",
- "thanks_for_submitting_request_for_account_recovery": "Merci pour la soumission de votre requête concernant la récupération de votre compte %(APP_NAME)sen utilisant une authentification à multi-facteurs basée sur la blockchain. Nous vous répondrons aussi rapidement que possible. Cependant, il se pourrait que notre réponse prennent du temps en raison du gros volume d'emails à traiter. Veuillez vous préparer à vérifier votre identité.",
- "recovering_account": "Récupération du compte",
- "recover_account": "Récupérer le compte",
- "checking_account_owner": "Vérifier le propriétaire du compte",
- "sending_recovery_request": "Envoyer une requête de récupération",
- "cant_confirm_account_ownership": "Nous ne pouvons confirmer que vous êtes propriétaire de ce compte. Veuillez s'il-vous-plaît vérifier votre mot de passe.",
- "account_recovery_request_not_confirmed": "La requête de la récupération du compte n'est pas encore confirmée. Veuillez réessayer plus tard. Merci de votre patience."
- },
- "user_profile": {
- "unknown_account": "Compte inconnu",
- "user_hasnt_made_any_posts_yet": "Il semblerait que %(name)s n'ait pas encore publié d'article.",
- "user_hasnt_started_bloggin_yet": "Il semblerait que %(name)s n'ait pas encore commencer à blogger.",
- "user_hasnt_followed_anything_yet": "Il semblerait que %(name)s ne soit fan de personne. Dans le cas où %(name)s s'abonnerait au fil d'autres utilisateurs, son flux sera automatiquement rempli avec du nouveau contenu.",
- "user_hasnt_had_any_replies_yet": "%(name)s n'a pas encore reçu de réponse",
- "looks_like_you_havent_posted_anything_yet": "Looks like you haven't posted anything yet.",
- "create_a_post": "Create a Post",
- "explore_trending_articles": "Explore Trending Articles",
- "read_the_quick_start_guide": "Read The Quick Start Guide",
- "browse_the_faq": "Browse The FAQ",
- "followers": "Followers",
- "this_is_users_reputations_score_it_is_based_on_history_of_votes": "Ceci est le score de réputation de %(name)s. \n\nLe score de réputation est basé sur l'historique des votes reçus par l'utilisateur, et est utilisé pour masquer le contenu de basse qualité.",
- "follower_count": {
- "zero": "Pas de fans",
- "one": "1 fan",
- "other": "%(count)s fans"
- },
- "followed_count": {
- "zero": "N'est fan d'aucun utilisateur",
- "one": "fan d'1 personne",
- "other": "%(count)s fans"
- },
- "post_count": {
- "zero": "Pas d'article",
- "one": "1 article",
- "other": "%(count)s articles"
- }
- },
- "authorrewards_jsx": {
- "estimated_author_rewards_last_week": "Gains de publication estimés pour la semaine dernière",
- "author_rewards_history": "Historique des gains de publication"
- },
- "curationrewards_jsx": {
- "estimated_curation_rewards_last_week": "Gains de curation estimés pour la semaine dernière",
- "curation_rewards_history": "Historique des gains de curation"
- },
- "post_jsx": {
- "now_showing_comments_with_low_ratings": "Affichant à présent les commentaires de faible évaluation",
- "sort_order": "Classer les ordres",
- "comments_were_hidden_due_to_low_ratings": "Certains commentaires sont masqués en raison de leur faible évaluation"
- },
- "voting_jsx": {
- "flagging_post_can_remove_rewards_the_flag_should_be_used_for_the_following": "Signaler un article peut diminuer ses gains potentiels et rendre son contenu moins visible. Quelques raisons usuelles pour signaler un article :",
- "disagreement_on_rewards": "Désaccord sur les gains",
- "fraud_or_plagiarism": "Fraude ou plagiarisme",
- "hate_speech_or_internet_trolling": "Discours haineux ou troll",
- "intentional_miss_categorized_content_or_spam": "Contenu catégorisé incorrectement de façon intentionnelle ou spam",
- "pending_payout": "%(value)s$ de gains en suspens",
- "payout_declined": "Gains refusés",
- "max_accepted_payout": "%(value)s$ de gains maximum acceptés",
- "promotion_cost": "Cout de la promotion: %(value)s$",
- "past_payouts": "Gains antérieurs: %(value)s$",
- "past_payouts_author": "- Auteur: %(value)s$",
- "past_payouts_curators": "Curateurs: %(value)s$",
- "we_will_reset_curation_rewards_for_this_post": "cela annulera vos potentiels gains de curation pour cet article",
- "removing_your_vote": "Enlever votre vote",
- "changing_to_an_upvote": "Modifier pour un vote positif",
- "changing_to_a_downvote": "Modifier pour un vote négatif",
- "confirm_flag": "Confirmer la signalisation",
- "and_more": "et %(count)s en plus",
- "votes_plural": {
- "one": "%(count)s vote",
- "other": "%(count)s votes"
- }
- },
- "witnesses_jsx": {
- "witness_thread": "article introductif pour le témoin",
- "top_witnesses": "Votes pour les témoins",
- "you_have_votes_remaining": {
- "zero": "Il ne vous reste plus de vote disponible",
- "one": "Il vous reste 1 vote disponible",
- "other": "Il vous reste %(count)s votes disponibles"
- },
- "you_can_vote_for_maximum_of_witnesses": "Vous pouvez voter pour un maximum de 30 témoins",
- "witness": "Témoin",
- "information": "Information",
- "if_you_want_to_vote_outside_of_top_enter_account_name": "Si vous voulez voter pour un témoin en dehors du top 50, veuille entrer le nom du compte concerné ci-dessous afin de voter pour lui",
- "set_witness_proxy": "Vous pouvez aussi donner une procuration à quelqu'un qui votera pour les témoins en votre nom. Cela annulera votre choix de témoins actuels.",
- "witness_set": "Vous avez donné une procuration pour le vote des témoins. Si vous voulez réactiver le vote manuel, veuillez annuler votre procuration.",
- "witness_proxy_current": "Vous avez donné une procuration à",
- "witness_proxy_set": "Donner une procuration",
- "witness_proxy_clear": "Annuler la procuration",
- "proxy_update_error": "Votre procuration n'a pas été mise à jour"
- },
- "votesandcomments_jsx": {
- "no_responses_yet_click_to_respond": "Pas encore de réponse. Cliquez ici pour répondre.",
- "response_count_tooltip": {
- "zero": "Pas de réponse. Cliquez ici pour répondre.",
- "one": "1 réponse. Cliquez ici pour répondre.",
- "other": "%(count)s réponses. Cliquez ici pour répondre. "
- },
- "vote_count": {
- "zero": "Pas de vote",
- "one": "1 vote",
- "other": "%(count)svotes"
+ "g": {
+ "age": "ancienneté",
+ "amount": "Montant",
+ "and": "et",
+ "are_you_sure": "Etes-vous sûr(e) ?",
+ "ask": "Demande",
+ "balance": "Solde",
+ "balances": "Soldes",
+ "bid": "Offre",
+ "blog": "Blog",
+ "browse": "Naviguer",
+ "buy": "Acheter",
+ "buy_or_sell": "Acheter ou vendre",
+ "by": "par",
+ "cancel": "Annuler",
+ "change_password": "Changer le mot de passe",
+ "choose_language": "Choisir la langue",
+ "clear": "Effacer",
+ "close": "Fermer",
+ "collapse_or_expand": "Compacter / Etendre",
+ "comments": "Commentaires",
+ "confirm": "Confirmer",
+ "convert": "Convertir",
+ "date": "Date",
+ "delete": "Supprimer",
+ "dismiss": "Ignorer",
+ "edit": "Editer",
+ "email": "Email",
+ "feed": "Flux",
+ "follow": "S'abonner",
+ "for": "pour",
+ "from": "de",
+ "go_back": "Retour",
+ "hide": "Masquer",
+ "in": "dans",
+ "in_reply_to": "en réponse à",
+ "insufficient_balance": "Solde insuffisant",
+ "invalid_amount": "Montant invalide",
+ "joined": "Inscrit en",
+ "loading": "Chargement en cours",
+ "login": "Se connecter",
+ "logout": "Déconnexion",
+ "memo": "Note",
+ "mute": "Ignorer",
+ "new": "nouveau",
+ "newer": "Plus récent",
+ "next": "Suivant",
+ "no": "Non",
+ "ok": "Ok",
+ "older": "Plus ancien",
+ "or": "ou",
+ "order_placed": "Ordre effectué",
+ "password": "Mot de passe",
+ "payouts": "Gains",
+ "permissions": "Permissions",
+ "phishy_message":
+ "Link expanded to plain text; beware of a potential phishing attempt",
+ "post": "Poster",
+ "post_as": "Poster en tant que",
+ "posts": "Articles",
+ "powered_up_100": "Converti en influence à 100%%",
+ "preview": "Prévisualiser",
+ "previous": "Précédent",
+ "price": "Prix",
+ "print": "Imprimer",
+ "promote": "Promouvoir",
+ "promoted": "promu",
+ "re": "RE",
+ "re_to": "RE :%(topic)s",
+ "recent_password": "Mot de passe antérieur",
+ "receive": "Recevoir",
+ "remove": "Enlever",
+ "remove_vote": "Enlever son vote",
+ "replied_to": "répondu à %(account)s",
+ "replies": "Réponses",
+ "reply": "Répondre",
+ "reply_count": {
+ "zero": "pas de réponse",
+ "one": "1 réponse",
+ "other": "%(count)s réponses"
+ },
+ "reputation": "Réputation",
+ "reveal_comment": "Révéler le commentaire",
+ "request": "requête",
+ "required": "Requis",
+ "rewards": "Gains",
+ "save": "Sauvegarder",
+ "saved": "Sauvegardé",
+ "search": "Rechercher",
+ "sell": "Vendre",
+ "settings": "Configuration",
+ "share_this_post": "Partager cet article",
+ "show": "Montrer",
+ "sign_in": "S'inscrire",
+ "sign_up": "S'inscrire",
+ "since": "depuis",
+ "submit": "Soumettre",
+ "power_up": "Augmenter son influence",
+ "submit_a_story": "Poster",
+ "tag": "Mot clé",
+ "to": "vers",
+ "all_tags": "All tags",
+ "transfer": "Transférer",
+ "trending_topics": "Sujets en vogue",
+ "type": "Genre",
+ "unfollow": "Se désabonner",
+ "unmute": "Ne plus ignorer",
+ "unknown": "Inconnu",
+ "upvote": "Voter pour",
+ "upvote_post": "Voter pour l'article",
+ "username": "Identifiant",
+ "version": "Version",
+ "vote": "Voter",
+ "votes": "votes",
+ "wallet": "Portefeuille",
+ "warning": "alarme",
+ "yes": "Oui",
+ "posting": "de publication",
+ "owner": "propriétaire",
+ "active": "active",
+ "account_not_found": "Compte inconnu",
+ "this_is_wrong_password": "Mot de passe incorrect",
+ "do_you_need_to": "Avez-vous besoin de",
+ "account_name": "Nom du compte",
+ "recover_your_account": "Récupérer son compte",
+ "reset_usernames_password":
+ "Réinitialiser le mot de passe de %(username)s",
+ "this_will_update_usernames_authtype_key":
+ "Ceci mettra a jour la clé %(authType)s de %(username)s",
+ "passwords_do_not_match": "Mots de passe différents",
+ "you_need_private_password_or_key_not_a_public_key":
+ "La clé ou le mot de passe privé (et non public) est nécessaire ",
+ "the_rules_of_APP_NAME": {
+ "one":
+ "La première règle de %(APP_NAME)s est de ne pas perdre son mot de passe.",
+ "second":
+ "La deuxième règle de %(APP_NAME)s est de ne pas perdre son mot de passe.",
+ "third":
+ "La troisième règle de %(APP_NAME)s est que nous ne pouvons réinitialiser votre mot de passe.",
+ "fourth":
+ "La quatrième règle est que si vous pouvez vous rappeler de votre mot de passe, il n'est pas assez sécuritaire.",
+ "fifth":
+ "La cinquième règle demande d'utiliser uniquement des mots de passe générés aléatoirement.",
+ "sixth":
+ "La sixième règle est de ne donner à personne son mot de passe.",
+ "seventh":
+ "La septième règle est de faire une sauvegarde de son mot de passe."
+ },
+ "recover_password": "Récupérer un compte",
+ "current_password": "Mot de passe actuel",
+ "generated_password": "Mot de passe généré",
+ "backup_password_by_storing_it":
+ "A sauvegarder en le copiant dans un fichier texte ou via un logiciel de gestion de mot de passe",
+ "enter_account_show_password":
+ "Entrer un identifiant valide pour afficher le mot de passe",
+ "click_to_generate_password":
+ "Cliquer ici pour générer un mot de passe",
+ "re_enter_generate_password": "Recopier le mot de passe généré",
+ "understand_that_APP_NAME_cannot_recover_password":
+ "Je comprends que %(APP_NAME)s ne peut récupérer les mots de passe perdus",
+ "i_saved_password":
+ "J'ai sauvegardé mon mot de passe de façon sécuritaire",
+ "update_password": "Mettre à jour le mot de passe",
+ "confirm_password": "Confirmer le mot de passe",
+ "account_updated": "Compte mis à jour",
+ "password_must_be_characters_or_more":
+ "Le mot de passe doit comporter au moins %(amount)s caractères supplémentaires",
+ "need_password_or_key":
+ "Il vous faut une clé ou un mot de passe privé (et non public)",
+ "login_to_see_memo": "S'identifier pour voir le mémo",
+ "new_password": "Nouveau mot de passe",
+ "incorrect_password": "Mot de passe incorrect",
+ "username_does_not_exist": "Cet identifiant n'existe pas",
+ "account_name_should_start_with_a_letter":
+ "L'identifiant doit commencer par une lettre.",
+ "account_name_should_be_shorter": "L'identifiant doit être plus court.",
+ "account_name_should_be_longer": "L'identifiant doit être plus long.",
+ "account_name_should_have_only_letters_digits_or_dashes":
+ "L'identifiant ne peut comporter que des lettres, des chiffres, des points ou des traits d'union.",
+ "cannot_increase_reward_of_post_within_the_last_minute_before_payout":
+ "Les gains d'un article ne peuvent être accrus durant la dernière minute avant rétribution.",
+ "vote_currently_exists_user_must_be_indicate_a_to_reject_witness":
+ "un vote existe actuellement; l'utilisateur doit indiquer une raison pour rejeter le témoin",
+ "only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes":
+ "Un seul compte Steem est permis par adresse IP toutes les 10 minutes",
+ "resteem_this_post": "Resteemer cet article",
+ "reblog": "Resteem",
+ "write_your_story": "Ecris ton histoire",
+ "remember_voting_and_posting_key":
+ "Se souvenir de la clé de publication et de vote",
+ "auto_login_question_mark": "Identification automatique",
+ "hide_private_key": "Masquer la clé privée",
+ "show_private_key": "Révéler la clé privée",
+ "login_to_show": "S'identifier pour révéler",
+ "not_valid_email": "Adresse email invalide",
+ "thank_you_for_being_an_early_visitor_to_APP_NAME":
+ "Merci pour être l'un des premiers visiteurs de %(APP_NAME)s. Nous reviendrons vers vous aussi tôt que possible.",
+ "author_rewards": "Gains éditoriaux",
+ "curation_rewards": "Gains de curation",
+ "sorry_your_reddit_account_doesnt_have_enough_karma":
+ "Désolé, votre compte Reddit ne possède pas de Karma Reddit suffisant pour vous qualifier pour une inscription gratuite. Veuillez s'il-vous-plaît indiquer votre adresse email pour être placé(e) sur liste d'attente.",
+ "register_with_facebook": "S'enregistrer par Facebook",
+ "or_click_the_button_below_to_register_with_facebook":
+ "Ou cliquer sur le bouton ci-dessous pour vous enregistrer par Facebook",
+ "server_returned_error": "le serveur a renvoyé une erreur",
+ "APP_NAME_support": "Support pour %(APP_NAME)s",
+ "please_email_questions_to":
+ "Veuillez s'il-vous-plaît envoyer vos questions par email à",
+ "next_7_strings_single_block": {
+ "authors_get_paid_when_people_like_you_upvote_their_post":
+ "Les auteurs sont payés lorsque des personnes comme vous votent pour leur contenu",
+ "if_you_enjoyed_what_you_read_earn_amount":
+ "Si vous avez apprécié ce que vous avez lu ici, créez votre compte dès à présent et commencer par gagner immédiatement du STEEM",
+ "free_steem": "STEEM GRATUIT!",
+ "sign_up_earn_steem": "S'enregistrer pour gagner"
+ },
+ "next_3_strings_together": {
+ "show_more": "Révéler plus",
+ "show_less": "Révéler moins",
+ "value_posts": "Articles de faible valeur"
+ },
+ "read_only_mode":
+ "En raison d'une maintenance des serveurs, le site est en mode lecture seule. Nous sommes désolés pour le désagrément. ",
+ "tags_and_topics": "Mots clés et sujets",
+ "show_more_topics": "Révéler plus de sujets",
+ "basic": "Basique",
+ "advanced": "Avancé",
+ "views": {
+ "zero": "Pas de vue",
+ "one": "%(count)s vue",
+ "other": "%(count)s vues"
+ },
+ "responses": {
+ "zero": "Pas de réponse",
+ "one": "%(count)s réponse",
+ "other": "%(count)s réponses"
+ },
+ "post_key_warning": {
+ "confirm":
+ "You are about to publish a STEEM private key or master password. You will probably lose control of the associated account and all its funds.",
+ "warning":
+ "Legitimate users, including employees of Steemit Inc., will never ask you for a private key or master password.",
+ "checkbox": "I understand"
+ }
+ },
+ "navigation": {
+ "about": "A propos",
+ "explore": "Explorer",
+ "APP_NAME_whitepaper": "%(APP_NAME)s livre blanc",
+ "buy_LIQUID_TOKEN": "Acheter %(LIQUID_TOKEN)s",
+ "sell_LIQUID_TOKEN": "Vendre %(LIQUID_TOKEN)s",
+ "currency_market": "Marché des devises",
+ "stolen_account_recovery": "Récupération de comptes dérobés",
+ "change_account_password": "Changement de mot de passe",
+ "witnesses": "Témoins",
+ "vote_for_witnesses": "Voter pour les témoins",
+ "privacy_policy": "Politique de confidentialité",
+ "terms_of_service": "Conditions d'utilisation",
+ "sign_up": "Rejoindre",
+ "learn_more": "En savoir plus",
+ "welcome": "Bienvenue",
+ "faq": "FAQ",
+ "shop": "The Steemit Shop",
+ "chat": "Salons de discussion Steemit",
+ "app_center": "Centre d'applications Steemit",
+ "api_docs": "Documentation API sur Steemit",
+ "whitepaper": "Livre blanc sur le Steem",
+ "bluepaper": "Steem Bluepaper",
+ "smt_whitepaper": "Livre blanc sur le SMT",
+ "intro_tagline": "Présentations sur la monnaie",
+ "intro_paragraph":
+ "Votre voix vaut quelque chose. Rejoignez la communauté qui vous rémunère pour vos articles et participez à la curation du contenu de qualité."
+ },
+ "main_menu": {
+ "hot": "chaud",
+ "trending": "en vogue"
+ },
+ "reply_editor": {
+ "shorten_title": "Raccourcir le titre",
+ "exceeds_maximum_length":
+ "Dépassement de la taille maximale ( %(maxKb)s KB)",
+ "including_the_category": "(incluant la catégorie '%(rootCategory)s')",
+ "use_limited_amount_of_tags":
+ "Vous avez un total de %(tagsLength)s mots clés %(includingCategory)s. Veuillez en utiliser seulement 5, autant pour l'article que pour le champ dédié aux mots clés.",
+ "are_you_sure_you_want_to_clear_this_form":
+ "Etes-vous sûr de vouloir effacer ce formulaire ?",
+ "uploading": "Téléchargement en cours",
+ "draft_saved": "Brouillon sauvegardé",
+ "editor": "Editeur",
+ "insert_images_by_dragging_dropping":
+ "Insertion d'images par 'drag and drop'",
+ "pasting_from_the_clipboard": "copie depuis le presse-papier,",
+ "selecting_them": "les sélectionnant",
+ "image_upload": "Téléchargement d'image",
+ "power_up_100": "Conversion en influence à 100%%",
+ "default_50_50": "Par défaut (50 %%/ 50%%)",
+ "decline_payout": "Refuser les gains",
+ "check_this_to_auto_upvote_your_post":
+ "Cocher cette case pour auto-voter pour votre article",
+ "markdown_styling_guide": "Guide stylistique pour le format Markdown",
+ "or_by": "ou par",
+ "title": "Titre",
+ "update_post": "Mettre l'article à jour",
+ "markdown_not_supported": "Le format Markdown n'est pas supporté ici"
+ },
+ "category_selector_jsx": {
+ "tag_your_story":
+ "Mots clés (jusqu'à 5 mots clés), le premier d'entre eux étant votre catégorie principale.",
+ "select_a_tag": "Sélectionner un mot clé",
+ "maximum_tag_length_is_24_characters":
+ "La longueur d'un mot clé est d'au maximum 24 caractères",
+ "use_limited_amount_of_categories":
+ "Veuillez s'il-vous-plaît n'utiliser que %(amount)s catégories",
+ "use_only_lowercase_letters":
+ "Veuillez n'utiliser que des lettres minuscules",
+ "use_one_dash": "Veuillez n'utiliser qu'un seul trait d'union",
+ "use_spaces_to_separate_tags":
+ "Veuillez utiliser des espaces pour séparer les mots clés",
+ "use_only_allowed_characters":
+ "Veuillez n'utilisez que des lettres minuscules, des chiffres et au plus un trait d'union",
+ "must_start_with_a_letter": "Le premier caractère doit être une lettre",
+ "must_end_with_a_letter_or_number":
+ "Le dernier caractère doit être une lettre ou un chiffre"
+ },
+ "postfull_jsx": {
+ "this_post_is_not_available_due_to_a_copyright_claim":
+ "Cet article n'est pas disponible en raison d'une requête de droits d'auteur.",
+ "share_on_facebook": "Partager sur Facebook",
+ "share_on_twitter": "Partager sur Twitter",
+ "share_on_linkedin": "Partager sur Linkedin",
+ "recent_password": "Mot de passe antérieur",
+ "in_week_convert_DEBT_TOKEN_to_LIQUID_TOKEN":
+ "Dans 3.5 jours, conversion de %(amount)s %(DEBT_TOKEN)s en %(LIQUID_TOKEN)s",
+ "view_the_full_context": "Voir le contexte complet",
+ "view_the_direct_parent": "Voir le message précédent",
+ "you_are_viewing_a_single_comments_thread_from":
+ "Vous visualisez un commentaire unique de l'article"
+ },
+ "market_jsx": {
+ "action": "Action",
+ "date_created": "Date de création",
+ "last_price": "Dernier cours",
+ "24h_volume": "Volume des dernières 24h",
+ "spread": "Ecart",
+ "total": "Total",
+ "available": "Disponible",
+ "lowest_ask": "Demande au taux le plus bas",
+ "highest_bid": "Offre au taux le plus haut",
+ "buy_orders": "Ordres d'achat",
+ "sell_orders": "Ordres de vente",
+ "trade_history": "Historique des échanges",
+ "open_orders": "Ordres ouverts",
+ "sell_amount_for_atleast":
+ "Vendre %(amount_to_sell)s pour au moins %(min_to_receive)s ( %(effectivePrice)s )",
+ "buy_atleast_amount_for":
+ "Acheter au moins %(min_to_receive)s pour %(amount_to_sell)s ( %(effectivePrice)s )",
+ "price_warning_above":
+ "Ce cours est bien au-delà des cours du marché actuels %(marketPrice)s, êtes-vous sûr (e) ?",
+ "price_warning_below":
+ "Ce cours est bien en-deça des cours du marché actuels %(marketPrice)s, êtes-vous sûr (e) ?",
+ "order_cancel_confirm": "Annuler l'ordre %(order_id)s de %(user)s",
+ "order_cancelled": "Ordre %(order_id)s annulé.",
+ "higher": "Plus haut",
+ "lower": "Plus bas",
+ "total_DEBT_TOKEN_SHORT_CURRENCY_SIGN":
+ "Total %(DEBT_TOKEN_SHORT)s (%(CURRENCY_SIGN)s)"
+ },
+ "recoveraccountstep1_jsx": {
+ "begin_recovery": "Démarrer la récupération",
+ "not_valid": "Invalide",
+ "account_name_is_not_found": "Compte inexistant",
+ "unable_to_recover_account_not_change_ownership_recently":
+ "Nous sommes incapables de récupérer ce compte, car il n'a pas changé de propriétaire récemment.",
+ "password_not_used_in_last_days":
+ "Ce mot de passe n'a pas été utilisé durant les derniers 30 jours.",
+ "request_already_submitted_contact_support":
+ "Votre requête a déjà été soumise et nous nous en occupons. Veuillez s'il-vous-plaît contacter %(SUPPORT_EMAIL)s pour obtenir le statut de votre requête.",
+ "recover_account_intro":
+ "Il est possible que la clé propriétaire d'un Steemien soit compromise. Le processus de récupération de comptes dérobés est autorisé pour l'utilisateur de droit pendant 30 jours à partir du moment où le voleur a modifié la clé propriétaire. La récupération de comptes dérobés ne peut être utilisée sur %(APP_URL)s que si le propriétaire du compte a ajouté '%(APP_NAME)s'comme mandataire de confiance et accepté les conditions d'utilisation de %(APP_NAME)s.",
+ "login_with_facebook_or_reddit_media_to_verify_identity":
+ "Veuillez vous identifier via Facebook ou Reddit pour vérifier votre identité.",
+ "login_with_social_media_to_verify_identity":
+ "Veuillez vous identifier via %(provider)safin de vérifier votre identité",
+ "enter_email_toverify_identity":
+ "Nous devons vérifier votre identité. Veuillez s'il-vous-plaît entrer votre adresse email ci-dessous pour démarrer le processus.",
+ "continue_with_email": "Continuer avec l'email.",
+ "thanks_for_submitting_request_for_account_recovery":
+ "Merci pour la soumission de votre requête concernant la récupération de votre compte %(APP_NAME)sen utilisant une authentification à multi-facteurs basée sur la blockchain. Nous vous répondrons aussi rapidement que possible. Cependant, il se pourrait que notre réponse prennent du temps en raison du gros volume d'emails à traiter. Veuillez vous préparer à vérifier votre identité.",
+ "recovering_account": "Récupération du compte",
+ "recover_account": "Récupérer le compte",
+ "checking_account_owner": "Vérifier le propriétaire du compte",
+ "sending_recovery_request": "Envoyer une requête de récupération",
+ "cant_confirm_account_ownership":
+ "Nous ne pouvons confirmer que vous êtes propriétaire de ce compte. Veuillez s'il-vous-plaît vérifier votre mot de passe.",
+ "account_recovery_request_not_confirmed":
+ "La requête de la récupération du compte n'est pas encore confirmée. Veuillez réessayer plus tard. Merci de votre patience."
+ },
+ "user_profile": {
+ "unknown_account": "Compte inconnu",
+ "user_hasnt_made_any_posts_yet":
+ "Il semblerait que %(name)s n'ait pas encore publié d'article.",
+ "user_hasnt_started_bloggin_yet":
+ "Il semblerait que %(name)s n'ait pas encore commencer à blogger.",
+ "user_hasnt_followed_anything_yet":
+ "Il semblerait que %(name)s ne soit fan de personne. Dans le cas où %(name)s s'abonnerait au fil d'autres utilisateurs, son flux sera automatiquement rempli avec du nouveau contenu.",
+ "user_hasnt_had_any_replies_yet":
+ "%(name)s n'a pas encore reçu de réponse",
+ "looks_like_you_havent_posted_anything_yet":
+ "Looks like you haven't posted anything yet.",
+ "create_a_post": "Create a Post",
+ "explore_trending_articles": "Explore Trending Articles",
+ "read_the_quick_start_guide": "Read The Quick Start Guide",
+ "browse_the_faq": "Browse The FAQ",
+ "followers": "Followers",
+ "this_is_users_reputations_score_it_is_based_on_history_of_votes":
+ "Ceci est le score de réputation de %(name)s. \n\nLe score de réputation est basé sur l'historique des votes reçus par l'utilisateur, et est utilisé pour masquer le contenu de basse qualité.",
+ "follower_count": {
+ "zero": "Pas de fans",
+ "one": "1 fan",
+ "other": "%(count)s fans"
+ },
+ "followed_count": {
+ "zero": "N'est fan d'aucun utilisateur",
+ "one": "fan d'1 personne",
+ "other": "%(count)s fans"
+ },
+ "post_count": {
+ "zero": "Pas d'article",
+ "one": "1 article",
+ "other": "%(count)s articles"
+ }
+ },
+ "authorrewards_jsx": {
+ "estimated_author_rewards_last_week":
+ "Gains de publication estimés pour la semaine dernière",
+ "author_rewards_history": "Historique des gains de publication"
+ },
+ "curationrewards_jsx": {
+ "estimated_curation_rewards_last_week":
+ "Gains de curation estimés pour la semaine dernière",
+ "curation_rewards_history": "Historique des gains de curation"
+ },
+ "post_jsx": {
+ "now_showing_comments_with_low_ratings":
+ "Affichant à présent les commentaires de faible évaluation",
+ "sort_order": "Classer les ordres",
+ "comments_were_hidden_due_to_low_ratings":
+ "Certains commentaires sont masqués en raison de leur faible évaluation"
+ },
+ "voting_jsx": {
+ "flagging_post_can_remove_rewards_the_flag_should_be_used_for_the_following":
+ "Signaler un article peut diminuer ses gains potentiels et rendre son contenu moins visible. Quelques raisons usuelles pour signaler un article :",
+ "disagreement_on_rewards": "Désaccord sur les gains",
+ "fraud_or_plagiarism": "Fraude ou plagiarisme",
+ "hate_speech_or_internet_trolling": "Discours haineux ou troll",
+ "intentional_miss_categorized_content_or_spam":
+ "Contenu catégorisé incorrectement de façon intentionnelle ou spam",
+ "pending_payout": "%(value)s$ de gains en suspens",
+ "payout_declined": "Gains refusés",
+ "max_accepted_payout": "%(value)s$ de gains maximum acceptés",
+ "promotion_cost": "Cout de la promotion: %(value)s$",
+ "past_payouts": "Gains antérieurs: %(value)s$",
+ "past_payouts_author": "- Auteur: %(value)s$",
+ "past_payouts_curators": "Curateurs: %(value)s$",
+ "we_will_reset_curation_rewards_for_this_post":
+ "cela annulera vos potentiels gains de curation pour cet article",
+ "removing_your_vote": "Enlever votre vote",
+ "changing_to_an_upvote": "Modifier pour un vote positif",
+ "changing_to_a_downvote": "Modifier pour un vote négatif",
+ "confirm_flag": "Confirmer la signalisation",
+ "and_more": "et %(count)s en plus",
+ "votes_plural": {
+ "one": "%(count)s vote",
+ "other": "%(count)s votes"
+ }
+ },
+ "witnesses_jsx": {
+ "witness_thread": "article introductif pour le témoin",
+ "top_witnesses": "Votes pour les témoins",
+ "you_have_votes_remaining": {
+ "zero": "Il ne vous reste plus de vote disponible",
+ "one": "Il vous reste 1 vote disponible",
+ "other": "Il vous reste %(count)s votes disponibles"
+ },
+ "you_can_vote_for_maximum_of_witnesses":
+ "Vous pouvez voter pour un maximum de 30 témoins",
+ "witness": "Témoin",
+ "information": "Information",
+ "if_you_want_to_vote_outside_of_top_enter_account_name":
+ "Si vous voulez voter pour un témoin en dehors du top 50, veuille entrer le nom du compte concerné ci-dessous afin de voter pour lui",
+ "set_witness_proxy":
+ "Vous pouvez aussi donner une procuration à quelqu'un qui votera pour les témoins en votre nom. Cela annulera votre choix de témoins actuels.",
+ "witness_set":
+ "Vous avez donné une procuration pour le vote des témoins. Si vous voulez réactiver le vote manuel, veuillez annuler votre procuration.",
+ "witness_proxy_current": "Vous avez donné une procuration à",
+ "witness_proxy_set": "Donner une procuration",
+ "witness_proxy_clear": "Annuler la procuration",
+ "proxy_update_error": "Votre procuration n'a pas été mise à jour"
+ },
+ "votesandcomments_jsx": {
+ "no_responses_yet_click_to_respond":
+ "Pas encore de réponse. Cliquez ici pour répondre.",
+ "response_count_tooltip": {
+ "zero": "Pas de réponse. Cliquez ici pour répondre.",
+ "one": "1 réponse. Cliquez ici pour répondre.",
+ "other": "%(count)s réponses. Cliquez ici pour répondre. "
+ },
+ "vote_count": {
+ "zero": "Pas de vote",
+ "one": "1 vote",
+ "other": "%(count)svotes"
+ }
+ },
+ "userkeys_jsx": {
+ "public": "Public",
+ "private": "Privé",
+ "public_something_key": "Clé publique %(key)s",
+ "private_something_key": "Clé privée %(key)s",
+ "posting_key_is_required_it_should_be_different":
+ "Le clé de publication est utilisée pour publier et voter. Elle devrait être différente des clés active et propriétaire.",
+ "the_active_key_is_used_to_make_transfers_and_place_orders":
+ "La clé active est utilisée pour effectuer des transferts et des placer des ordres sur le marché interne.",
+ "the_owner_key_is_required_to_change_other_keys":
+ "La clé propriétaire est la clé principale du compte et est requise pour changer les autres clés.",
+ "the_private_key_or_password_should_be_kept_offline":
+ "La clé privée, ou le mot de passe pour la clé propriétaire, devrait être gardée hors ligne autant que possible.",
+ "the_memo_key_is_used_to_create_and_read_memos":
+ "La clé pour les notes est utilisée pour créer et lire des notes."
+ },
+ "suggestpassword_jsx": {
+ "APP_NAME_cannot_recover_passwords_keep_this_page_in_a_secure_location":
+ "%(APP_NAME)s ne peut pas récupérer de mots de passe. Veuille garder une trace de cette page en lieu sûr, comme un coffre fort ininflammable et sécuritaire.",
+ "APP_NAME_password_backup":
+ "Sauvegarde de mot de passe pour %(APP_NAME)s",
+ "APP_NAME_password_backup_required":
+ "Sauvegarde de mot de passe pour %(APP_NAME)s (requis)",
+ "after_printing_write_down_your_user_name":
+ "Après impression, veuillez indiquer votre identifiant"
+ },
+ "converttosteem_jsx": {
+ "your_existing_DEBT_TOKEN_are_liquid_and_transferable":
+ "Vos %(DEBT_TOKEN)s existants sont en liquide et donc transférable. Vous pouvez par exemple ėchanger %(DEBT_TOKEN)s directement sur ce site via le lien %(link)s, ou les transférer vers un marché externe.",
+ "this_is_a_price_feed_conversion":
+ "Il s'agit d'une conversion au taux du marché. Le délais de 3.5 jours est nécessaire afin d'éviter les abus de ceux qui tenterait de parier sur les modifications à court terme du taux du marché moyen.",
+ "convert_to_LIQUID_TOKEN": "Convertir en %(LIQUID_TOKEN)s",
+ "DEBT_TOKEN_will_be_unavailable":
+ "Cette action aura lieu dans 3.5 jours et ne peut être annulée. Ces %(DEBT_TOKEN)s deviendront immédiatement non disponibles."
+ },
+ "tips_js": {
+ "liquid_token":
+ "Des jetons négociables peuvent être transférés n'importe où à tout moment. %(LIQUID_TOKEN)s peuvent être convertis en %(VESTING_TOKEN)s lors d'un processus appelé conversion en influence, ou power up.",
+ "influence_token":
+ "Jetons d'influence qui vous donnent plus de contrôle sur les gains potentiels des articles et vous permettent d'augmenter vos gains de curation",
+ "estimated_value":
+ "La valeur estimée est basée sur la valeur moyenne de %(LIQUID_TOKEN)s en dollars américains.",
+ "non_transferable":
+ "%(VESTING_TOKEN)s est non transférable et demande 3 mois (13 paiements) pour être convertis en %(LIQUID_TOKEN)s. ",
+ "converted_VESTING_TOKEN_can_be_sent_to_yourself_but_can_not_transfer_again":
+ "Les %(VESTING_TOKEN)s convertis peuvent être envoyés soit à vous, soit à quelqu'un d'autre, mais ne peuvent pas être transférés à nouveau sans être convertis en %(LIQUID_TOKEN)s.",
+ "part_of_your_steem_power_is_currently_delegated":
+ "Une partie de votre influence, ou STEEM POWER, est actuellement déléguée. La délégation est un don pour augmenter l'influence ou pour encourager les nouveaux utilisateurs à effectuer des actions sur Steemit. Le montant délégué peut varier."
+ },
+ "promote_post_jsx": {
+ "promote_post": "Promouvoir un article",
+ "spend_your_DEBT_TOKEN_to_advertise_this_post":
+ "Dépenser vos %(DEBT_TOKEN)s pour afficher cet article dans la section contenant les articles promus. ",
+ "you_successfully_promoted_this_post":
+ "Vous avez promotionné cet article avec succès",
+ "this_post_was_hidden_due_to_low_ratings":
+ "Cet article est masqué en raison d'une faible évaluation."
+ },
+ "about_jsx": {
+ "about_app": "A propos de %(APP_NAME)s",
+ "about_app_details":
+ "%(APP_NAME)s est une plateforme de réseau social où les utilisateurs sont payés pour créer et effecter la curation du contenu. Elle influence un système de points digitaux, appelé Steem, qui ont une valeur réelle en fonction des prix du marché et des liquidités disponibles.",
+ "learn_more_at_app_url": "Plus d'informations à %(APP_URL)s",
+ "resources": "Ressources"
+ },
+ "markdownviewer_jsx": {
+ "images_were_hidden_due_to_low_ratings":
+ "Les images sont masqués en raison d'une faible évaluation."
+ },
+ "postsummary_jsx": {
+ "resteemed": "resteemé",
+ "resteemed_by": "Resteemé par",
+ "reveal_it": "Révélez-le",
+ "adjust_your": "Ajustez vos",
+ "display_preferences": "préférences visuelles",
+ "create_an_account": "créer un compte",
+ "to_save_your_preferences": "Pour enregistrer vos préférences"
+ },
+ "posts_index": {
+ "empty_feed_1":
+ "Il semblerait que vous ne vous êtes abonné(e) à aucun fil pour le moment",
+ "empty_feed_2":
+ "Si vous vous êtes récemment abonné(e) au fil de nouveaux utilisateurs, votre flux personnel sera automatiquement rempli lorsque du nouveau contenu apparaîtra",
+ "empty_feed_3": "Explorer les articles en vogue",
+ "empty_feed_4": "Lire le guide de prise en main rapide",
+ "empty_feed_5": "Parcourir la FAQ"
+ },
+ "transferhistoryrow_jsx": {
+ "to_savings": "vers l'épargne",
+ "from_savings": "depuis l'épargne",
+ "cancel_transfer_from_savings": "Annuler le transfert vers l'épargne",
+ "stop_power_down":
+ "Arrêter la récupération de l'influence, ou le power down",
+ "start_power_down_of":
+ "Démarrer la récupération de l'influence, ou le power down",
+ "receive_interest_of": "Recevoir les intérêts de"
+ },
+ "savingswithdrawhistory_jsx": {
+ "cancel_this_withdraw_request":
+ "Voulez-vous annuler cette demande de retrait ?",
+ "pending_savings_withdrawals": "RETRAITS D'EPARGNE EN SUSPENS",
+ "withdraw": "Retirer %(amount)s",
+ "to": "vers %(to)s",
+ "from_to": "de %(from)s vers %(to)s"
+ },
+ "explorepost_jsx": {
+ "copied": "Copié!",
+ "copy": "COPIER",
+ "alternative_sources": "Références alternatives"
+ },
+ "header_jsx": {
+ "home": "répertoire personnel",
+ "create_a_post": "Créer un article",
+ "change_account_password": "Changer le mot de passe du compte",
+ "create_account": "Créer un compte",
+ "stolen_account_recovery": "Récupération des comptes dérobés",
+ "people_following": "Personnes fans de",
+ "people_followed_by": "Personnes suivies par",
+ "curation_rewards_by": "Gains de curation de",
+ "author_rewards_by": "Gains de publication de",
+ "replies_to": "Réponses à",
+ "comments_by": "Commentaires de"
+ },
+ "loginform_jsx": {
+ "you_need_a_private_password_or_key":
+ "Il vous faut un mot de passe ou une clé privé (pas une clé publique)",
+ "cryptography_test_failed": "Le test de cryptographie a échoué",
+ "unable_to_log_you_in":
+ "Nous sommes incapables de vous identifier avec ce navigateur.",
+ "the_latest_versions_of": "Les dernières versions de",
+ "are_well_tested_and_known_to_work_with":
+ "sont bien testées et connues pour fonctionner avec %(APP_URL)s.",
+ "due_to_server_maintenance":
+ "En raison de la maintenance des serveurs, nous opérons en mode 'lecture seule'. Nous nous excusons des désagréments. ",
+ "login_to_vote": "S'identifier pour voter",
+ "login_to_post": "S'identifier pour publier",
+ "login_to_comment": "S'identifier pour commenter",
+ "posting": "de publication",
+ "active_or_owner": "Active ou propriétaire",
+ "this_password_is_bound_to_your_account_owner_key":
+ "Ce mot de passe est lié à votre clé propriétaire et ne peut pas être utilisé pour vous identifier sur ce site.",
+ "however_you_can_use_it_to": "Cependant, vous pouvez l'utiliser pour ",
+ "update_your_password": "Mettre à jour votre mot de passe",
+ "to_obtain_a_more_secure_set_of_keys":
+ "Pour obtenir un jeu de clés plus sûr.",
+ "this_password_is_bound_to_your_account_active_key":
+ "Ce mot de passe est lié à la clé active de votre compte et ne peut pas être utilisé pour vous connecter à cette page.",
+ "you_may_use_this_active_key_on_other_more":
+ "Vous pouvez utiliser cette clé active sur d'autres pages plus sécurisées comme les pages 'Portefeuille' ou 'Marché'.",
+ "you_account_has_been_successfully_created":
+ "Votre compte a été créé avec succès!",
+ "you_account_has_been_successfully_recovered":
+ "Votre compte a été récupéré avec succès!",
+ "password_update_succes":
+ "Le mot de passe pour%(accountName)sa été mis à jour avec succès.",
+ "password_info":
+ "Ce mot de passe ou clé privée est incorrect. Il y a probablement une erreur d'écriture ou d'entrée des données. Indication : un mot de passe ou une clé privée générée par Steemit ne contiendra jamais aucun 0 (zéro), O (o majuscule), I (i majuscule) ou l (l minuscule).",
+ "enter_your_username": "Entrez votre nom d'utilisateur",
+ "password_or_wif": "Mot de passe ou WIF",
+ "this_operation_requires_your_key_or_master_password":
+ "Cette opération nécessite votre clé %(authType)s ou votre mot de passe principal.",
+ "keep_me_logged_in": "Gardez-moi connecté",
+ "amazing_community": "communauté extraordinaire",
+ "to_comment_and_reward_others":
+ " pour commenter et récompenser les autres.",
+ "sign_up_get_steem": "Sign up. Get STEEM",
+ "signup_button": "Sign up now to earn ",
+ "signup_button_emphasis": "FREE STEEM!",
+ "returning_users": "Utilisateurs de retour :",
+ "join_our": "Rejoignez notre"
+ },
+ "chainvalidation_js": {
+ "account_name_should": "Le nom du compte doit ",
+ "not_be_empty": "ne peut pas être vide.",
+ "be_longer": "être plus long.",
+ "be_shorter": "être plus court.",
+ "each_account_segment_should": "Chaque segment de compte devrait",
+ "start_with_a_letter": "commencer par une lettre.",
+ "have_only_letters_digits_or_dashes":
+ "ne comporter que des lettres, des chiffres ou des traits d'union.",
+ "have_only_one_dash_in_a_row": "n'avoir qu'un seul trait d'union.",
+ "end_with_a_letter_or_digit": "terminer par une lettre ou un chiffre.",
+ "verified_exchange_no_memo":
+ "Vous devez inclure un mémo pour votre transfert vers un marché d'échanges."
+ },
+ "settings_jsx": {
+ "invalid_url": "L'URL est invalide",
+ "name_is_too_long": "Le nom est trop long",
+ "name_must_not_begin_with": "Le nom ne doit pas commencer avec un @",
+ "about_is_too_long": "Le \"A propos\" est trop long",
+ "location_is_too_long": "Le lieu est trop long",
+ "website_url_is_too_long": "L'URL du site web est trop longue",
+ "public_profile_settings": "Paramètres du profil public",
+ "preferences": "Paramètres de l'affichage des messages privés",
+ "not_safe_for_work_nsfw_content":
+ "Peu approprié pour le travail (NSFW)",
+ "always_hide": "Toujours masquer",
+ "always_warn": "Toujours avertir",
+ "always_show": "Toujours montrer",
+ "muted_users": "Utilisateurs ignorés",
+ "update": "Mise à jour",
+ "profile_image_url": "URL de la photo de profil",
+ "cover_image_url": "URL de l'image de couverture",
+ "profile_name": "Nom à afficher",
+ "profile_about": "A propos",
+ "profile_location": "Lieu",
+ "profile_website": "Site internet"
+ },
+ "transfer_jsx": {
+ "amount_is_in_form": "Montant dans le format 99999.999",
+ "insufficient_funds": "Fonds insuffisants",
+ "use_only_3_digits_of_precison":
+ "Utiliser au maximum 3 décimales pour la précision",
+ "send_to_account": "Envoyer au compte",
+ "asset": "Actif",
+ "this_memo_is_private": "Ce mémo est privé",
+ "this_memo_is_public": "Ce mémo est public",
+ "convert_to_VESTING_TOKEN": "Convertir en %(VESTING_TOKEN)s",
+ "balance_subject_to_3_day_withdraw_waiting_period":
+ "Le solde dépend de la période de 3 jours d'attente requise pour les retraits",
+ "move_funds_to_another_account":
+ "Transférer des fonds vers un autre compte %(APP_NAME)s ",
+ "protect_funds_by_requiring_a_3_day_withdraw_waiting_period":
+ "Protéger les fonds en imposant une période de latence de 3 jours pour les retraits.",
+ "withdraw_funds_after_the_required_3_day_waiting_period":
+ "Retirer les fonds après la période de 3 jours de latence requise",
+ "from": "De",
+ "to": "A",
+ "asset_currently_collecting":
+ "%(asset)s collectant actuellement %(interest)s %% d'APR.",
+ "beware_of_spam_and_phishing_links":
+ "Beware of spam and phishing links in transfer memos. Do not open links from users you do not trust. Do not provide your private keys to any third party websites."
+ },
+ "userwallet_jsx": {
+ "conversion_complete_tip": "S'achèvera le",
+ "in_conversion": "%(amount)s en conversion",
+ "transfer_to_savings": "Transfert vers l'épargne",
+ "power_up": "Augmenter son influence",
+ "power_down": "Diminuer son influence",
+ "market": "Marché",
+ "convert_to_LIQUID_TOKEN": "Convertir en %(LIQUID_TOKEN)s",
+ "withdraw_LIQUID_TOKEN": "Retirer %(LIQUID_TOKEN)s",
+ "withdraw_DEBT_TOKENS": "Retirer %(DEBT_TOKENS)s",
+ "tokens_worth_about_1_of_LIQUID_TICKER":
+ "Des jetons d'environ 1.00$ de %(LIQUID_TICKER)s, actuellement donnant lieu à %(sbdInterest)s %% d'APR.",
+ "savings": "EPARGNE",
+ "estimated_account_value": "Valeur estimée du compte",
+ "next_power_down_is_scheduled_to_happen":
+ "Le prochain retrait d'influence, ou power down, est prévu dans ",
+ "transfers_are_temporary_disabled":
+ "Les transferts sont temporairement désactivés.",
+ "history": "HISTORIQUE",
+ "redeem_rewards": "Réclamer les gains (transférer vers le solde)",
+ "buy_steem_or_steem_power": "Acheter du STEEM ou du STEEM POWER"
+ },
+ "powerdown_jsx": {
+ "power_down": "Diminuer son influence",
+ "amount": "Montant",
+ "already_power_down":
+ "Vous êtes actuellement en train de retirer %(AMOUNT)s %(LIQUID_TICKER)s d'influence (%(WITHDRAWN)s %(LIQUID_TICKER)s déjà payé). Veuillez noter que si le montant retiré est modifié, le compteur pour le prochain retrait sera remis à zéro également.",
+ "delegating":
+ "Vous déléguez actuellement %(AMOUNT)s %(LIQUID_TICKER)s. Ce montant est bloqué et est indisponible pour tout retrait d'influence, ou power down, tant que la délégation n'est pas annulée et qu'une période complète de gains soit passée.",
+ "per_week": "C'est environ %(AMOUNT)s%(LIQUID_TICKER)s par semaine.",
+ "warning":
+ "Laisser moins de%(AMOUNT)s%(VESTING_TOKEN)s sur votre compte n'est pas recommandé et peut rendre votre compte inutilisable.",
+ "error":
+ "Impossible d'effectuer un retrait d'influence (ERREUR : %(MESSAGE)s)"
+ },
+ "checkloginowner_jsx": {
+ "your_password_permissions_were_reduced":
+ "Les permissions de votre mot de passe ont été réduites",
+ "if_you_did_not_make_this_change":
+ "Si vous n'avez pas fait ce changement, veuillez s'il-vous-plaît",
+ "ownership_changed_on": "Changement de propriétaire à compter du ",
+ "deadline_for_recovery_is": "La date limite de récupération est",
+ "i_understand_dont_show_again":
+ "J'ai compris, ne me le montrez plus jamais"
}
- },
- "userkeys_jsx": {
- "public": "Public",
- "private": "Privé",
- "public_something_key": "Clé publique %(key)s",
- "private_something_key": "Clé privée %(key)s",
- "posting_key_is_required_it_should_be_different": "Le clé de publication est utilisée pour publier et voter. Elle devrait être différente des clés active et propriétaire.",
- "the_active_key_is_used_to_make_transfers_and_place_orders": "La clé active est utilisée pour effectuer des transferts et des placer des ordres sur le marché interne.",
- "the_owner_key_is_required_to_change_other_keys": "La clé propriétaire est la clé principale du compte et est requise pour changer les autres clés.",
- "the_private_key_or_password_should_be_kept_offline": "La clé privée, ou le mot de passe pour la clé propriétaire, devrait être gardée hors ligne autant que possible.",
- "the_memo_key_is_used_to_create_and_read_memos": "La clé pour les notes est utilisée pour créer et lire des notes."
- },
- "suggestpassword_jsx": {
- "APP_NAME_cannot_recover_passwords_keep_this_page_in_a_secure_location": "%(APP_NAME)s ne peut pas récupérer de mots de passe. Veuille garder une trace de cette page en lieu sûr, comme un coffre fort ininflammable et sécuritaire.",
- "APP_NAME_password_backup": "Sauvegarde de mot de passe pour %(APP_NAME)s",
- "APP_NAME_password_backup_required": "Sauvegarde de mot de passe pour %(APP_NAME)s (requis)",
- "after_printing_write_down_your_user_name": "Après impression, veuillez indiquer votre identifiant"
- },
- "converttosteem_jsx": {
- "your_existing_DEBT_TOKEN_are_liquid_and_transferable": "Vos %(DEBT_TOKEN)s existants sont en liquide et donc transférable. Vous pouvez par exemple ėchanger %(DEBT_TOKEN)s directement sur ce site via le lien %(link)s, ou les transférer vers un marché externe.",
- "this_is_a_price_feed_conversion": "Il s'agit d'une conversion au taux du marché. Le délais de 3.5 jours est nécessaire afin d'éviter les abus de ceux qui tenterait de parier sur les modifications à court terme du taux du marché moyen.",
- "convert_to_LIQUID_TOKEN": "Convertir en %(LIQUID_TOKEN)s",
- "DEBT_TOKEN_will_be_unavailable": "Cette action aura lieu dans 3.5 jours et ne peut être annulée. Ces %(DEBT_TOKEN)s deviendront immédiatement non disponibles."
- },
- "tips_js": {
- "liquid_token": "Des jetons négociables peuvent être transférés n'importe où à tout moment. %(LIQUID_TOKEN)s peuvent être convertis en %(VESTING_TOKEN)s lors d'un processus appelé conversion en influence, ou power up.",
- "influence_token": "Jetons d'influence qui vous donnent plus de contrôle sur les gains potentiels des articles et vous permettent d'augmenter vos gains de curation",
- "estimated_value": "La valeur estimée est basée sur la valeur moyenne de %(LIQUID_TOKEN)s en dollars américains.",
- "non_transferable": "%(VESTING_TOKEN)s est non transférable et demande 3 mois (13 paiements) pour être convertis en %(LIQUID_TOKEN)s. ",
- "converted_VESTING_TOKEN_can_be_sent_to_yourself_but_can_not_transfer_again": "Les %(VESTING_TOKEN)s convertis peuvent être envoyés soit à vous, soit à quelqu'un d'autre, mais ne peuvent pas être transférés à nouveau sans être convertis en %(LIQUID_TOKEN)s.",
- "part_of_your_steem_power_is_currently_delegated": "Une partie de votre influence, ou STEEM POWER, est actuellement déléguée. La délégation est un don pour augmenter l'influence ou pour encourager les nouveaux utilisateurs à effectuer des actions sur Steemit. Le montant délégué peut varier."
- },
- "promote_post_jsx": {
- "promote_post": "Promouvoir un article",
- "spend_your_DEBT_TOKEN_to_advertise_this_post": "Dépenser vos %(DEBT_TOKEN)s pour afficher cet article dans la section contenant les articles promus. ",
- "you_successfully_promoted_this_post": "Vous avez promotionné cet article avec succès",
- "this_post_was_hidden_due_to_low_ratings": "Cet article est masqué en raison d'une faible évaluation."
- },
- "about_jsx": {
- "about_app": "A propos de %(APP_NAME)s",
- "about_app_details": "%(APP_NAME)s est une plateforme de réseau social où les utilisateurs sont payés pour créer et effecter la curation du contenu. Elle influence un système de points digitaux, appelé Steem, qui ont une valeur réelle en fonction des prix du marché et des liquidités disponibles.",
- "learn_more_at_app_url": "Plus d'informations à %(APP_URL)s",
- "resources": "Ressources"
- },
- "markdownviewer_jsx": {
- "images_were_hidden_due_to_low_ratings": "Les images sont masqués en raison d'une faible évaluation."
- },
- "postsummary_jsx": {
- "resteemed": "resteemé",
- "resteemed_by": "Resteemé par",
- "reveal_it": "Révélez-le",
- "adjust_your": "Ajustez vos",
- "display_preferences": "préférences visuelles",
- "create_an_account": "créer un compte",
- "to_save_your_preferences": "Pour enregistrer vos préférences"
- },
- "posts_index": {
- "empty_feed_1": "Il semblerait que vous ne vous êtes abonné(e) à aucun fil pour le moment",
- "empty_feed_2": "Si vous vous êtes récemment abonné(e) au fil de nouveaux utilisateurs, votre flux personnel sera automatiquement rempli lorsque du nouveau contenu apparaîtra",
- "empty_feed_3": "Explorer les articles en vogue",
- "empty_feed_4": "Lire le guide de prise en main rapide",
- "empty_feed_5": "Parcourir la FAQ"
- },
- "transferhistoryrow_jsx": {
- "to_savings": "vers l'épargne",
- "from_savings": "depuis l'épargne",
- "cancel_transfer_from_savings": "Annuler le transfert vers l'épargne",
- "stop_power_down": "Arrêter la récupération de l'influence, ou le power down",
- "start_power_down_of": "Démarrer la récupération de l'influence, ou le power down",
- "receive_interest_of": "Recevoir les intérêts de"
- },
- "savingswithdrawhistory_jsx": {
- "cancel_this_withdraw_request": "Voulez-vous annuler cette demande de retrait ?",
- "pending_savings_withdrawals": "RETRAITS D'EPARGNE EN SUSPENS",
- "withdraw": "Retirer %(amount)s",
- "to": "vers %(to)s",
- "from_to": "de %(from)s vers %(to)s"
- },
- "explorepost_jsx": {
- "copied": "Copié!",
- "copy": "COPIER",
- "alternative_sources": "Références alternatives"
- },
- "header_jsx": {
- "home": "répertoire personnel",
- "create_a_post": "Créer un article",
- "change_account_password": "Changer le mot de passe du compte",
- "create_account": "Créer un compte",
- "stolen_account_recovery": "Récupération des comptes dérobés",
- "people_following": "Personnes fans de",
- "people_followed_by": "Personnes suivies par",
- "curation_rewards_by": "Gains de curation de",
- "author_rewards_by": "Gains de publication de",
- "replies_to": "Réponses à",
- "comments_by": "Commentaires de"
- },
- "loginform_jsx": {
- "you_need_a_private_password_or_key": "Il vous faut un mot de passe ou une clé privé (pas une clé publique)",
- "cryptography_test_failed": "Le test de cryptographie a échoué",
- "unable_to_log_you_in": "Nous sommes incapables de vous identifier avec ce navigateur.",
- "the_latest_versions_of": "Les dernières versions de",
- "are_well_tested_and_known_to_work_with": "sont bien testées et connues pour fonctionner avec %(APP_URL)s.",
- "due_to_server_maintenance": "En raison de la maintenance des serveurs, nous opérons en mode 'lecture seule'. Nous nous excusons des désagréments. ",
- "login_to_vote": "S'identifier pour voter",
- "login_to_post": "S'identifier pour publier",
- "login_to_comment": "S'identifier pour commenter",
- "posting": "de publication",
- "active_or_owner": "Active ou propriétaire",
- "this_password_is_bound_to_your_account_owner_key": "Ce mot de passe est lié à votre clé propriétaire et ne peut pas être utilisé pour vous identifier sur ce site.",
- "however_you_can_use_it_to": "Cependant, vous pouvez l'utiliser pour ",
- "update_your_password": "Mettre à jour votre mot de passe",
- "to_obtain_a_more_secure_set_of_keys": "Pour obtenir un jeu de clés plus sûr.",
- "this_password_is_bound_to_your_account_active_key": "Ce mot de passe est lié à la clé active de votre compte et ne peut pas être utilisé pour vous connecter à cette page.",
- "you_may_use_this_active_key_on_other_more": "Vous pouvez utiliser cette clé active sur d'autres pages plus sécurisées comme les pages 'Portefeuille' ou 'Marché'.",
- "you_account_has_been_successfully_created": "Votre compte a été créé avec succès!",
- "you_account_has_been_successfully_recovered": "Votre compte a été récupéré avec succès!",
- "password_update_succes": "Le mot de passe pour%(accountName)sa été mis à jour avec succès.",
- "password_info": "Ce mot de passe ou clé privée est incorrect. Il y a probablement une erreur d'écriture ou d'entrée des données. Indication : un mot de passe ou une clé privée générée par Steemit ne contiendra jamais aucun 0 (zéro), O (o majuscule), I (i majuscule) ou l (l minuscule).",
- "enter_your_username": "Entrez votre nom d'utilisateur",
- "password_or_wif": "Mot de passe ou WIF",
- "this_operation_requires_your_key_or_master_password": "Cette opération nécessite votre clé %(authType)s ou votre mot de passe principal.",
- "keep_me_logged_in": "Gardez-moi connecté",
- "amazing_community": "communauté extraordinaire",
- "to_comment_and_reward_others": " pour commenter et récompenser les autres.",
- "sign_up_get_steem": "Sign up. Get STEEM",
- "signup_button": "Sign up now to earn ",
- "signup_button_emphasis": "FREE STEEM!",
- "returning_users": "Utilisateurs de retour :",
- "join_our": "Rejoignez notre"
- },
- "chainvalidation_js": {
- "account_name_should": "Le nom du compte doit ",
- "not_be_empty": "ne peut pas être vide.",
- "be_longer": "être plus long.",
- "be_shorter": "être plus court.",
- "each_account_segment_should": "Chaque segment de compte devrait",
- "start_with_a_letter": "commencer par une lettre.",
- "have_only_letters_digits_or_dashes": "ne comporter que des lettres, des chiffres ou des traits d'union.",
- "have_only_one_dash_in_a_row": "n'avoir qu'un seul trait d'union.",
- "end_with_a_letter_or_digit": "terminer par une lettre ou un chiffre.",
- "verified_exchange_no_memo": "Vous devez inclure un mémo pour votre transfert vers un marché d'échanges."
- },
- "settings_jsx": {
- "invalid_url": "L'URL est invalide",
- "name_is_too_long": "Le nom est trop long",
- "name_must_not_begin_with": "Le nom ne doit pas commencer avec un @",
- "about_is_too_long": "Le \"A propos\" est trop long",
- "location_is_too_long": "Le lieu est trop long",
- "website_url_is_too_long": "L'URL du site web est trop longue",
- "public_profile_settings": "Paramètres du profil public",
- "private_post_display_settings": "Paramètres de l'affichage des messages privés",
- "not_safe_for_work_nsfw_content": "Peu approprié pour le travail (NSFW)",
- "always_hide": "Toujours masquer",
- "always_warn": "Toujours avertir",
- "always_show": "Toujours montrer",
- "muted_users": "Utilisateurs ignorés",
- "update": "Mise à jour",
- "profile_image_url": "URL de la photo de profil",
- "cover_image_url": "URL de l'image de couverture",
- "profile_name": "Nom à afficher",
- "profile_about": "A propos",
- "profile_location": "Lieu",
- "profile_website": "Site internet"
- },
- "transfer_jsx": {
- "amount_is_in_form": "Montant dans le format 99999.999",
- "insufficient_funds": "Fonds insuffisants",
- "use_only_3_digits_of_precison": "Utiliser au maximum 3 décimales pour la précision",
- "send_to_account": "Envoyer au compte",
- "asset": "Actif",
- "this_memo_is_private": "Ce mémo est privé",
- "this_memo_is_public": "Ce mémo est public",
- "convert_to_VESTING_TOKEN": "Convertir en %(VESTING_TOKEN)s",
- "balance_subject_to_3_day_withdraw_waiting_period": "Le solde dépend de la période de 3 jours d'attente requise pour les retraits",
- "move_funds_to_another_account": "Transférer des fonds vers un autre compte %(APP_NAME)s ",
- "protect_funds_by_requiring_a_3_day_withdraw_waiting_period": "Protéger les fonds en imposant une période de latence de 3 jours pour les retraits.",
- "withdraw_funds_after_the_required_3_day_waiting_period": "Retirer les fonds après la période de 3 jours de latence requise",
- "from": "De",
- "to": "A",
- "asset_currently_collecting": "%(asset)s collectant actuellement %(interest)s %% d'APR.",
- "beware_of_spam_and_phishing_links": "Beware of spam and phishing links in transfer memos. Do not open links from users you do not trust. Do not provide your private keys to any third party websites."
- },
- "userwallet_jsx": {
- "conversion_complete_tip": "S'achèvera le",
- "in_conversion": "%(amount)s en conversion",
- "transfer_to_savings": "Transfert vers l'épargne",
- "power_up": "Augmenter son influence",
- "power_down": "Diminuer son influence",
- "market": "Marché",
- "convert_to_LIQUID_TOKEN": "Convertir en %(LIQUID_TOKEN)s",
- "withdraw_LIQUID_TOKEN": "Retirer %(LIQUID_TOKEN)s",
- "withdraw_DEBT_TOKENS": "Retirer %(DEBT_TOKENS)s",
- "tokens_worth_about_1_of_LIQUID_TICKER": "Des jetons d'environ 1.00$ de %(LIQUID_TICKER)s, actuellement donnant lieu à %(sbdInterest)s %% d'APR.",
- "savings": "EPARGNE",
- "estimated_account_value": "Valeur estimée du compte",
- "next_power_down_is_scheduled_to_happen": "Le prochain retrait d'influence, ou power down, est prévu dans ",
- "transfers_are_temporary_disabled": "Les transferts sont temporairement désactivés.",
- "history": "HISTORIQUE",
- "redeem_rewards": "Réclamer les gains (transférer vers le solde)",
- "buy_steem_or_steem_power": "Acheter du STEEM ou du STEEM POWER"
- },
- "powerdown_jsx": {
- "power_down": "Diminuer son influence",
- "amount": "Montant",
- "already_power_down": "Vous êtes actuellement en train de retirer %(AMOUNT)s %(LIQUID_TICKER)s d'influence (%(WITHDRAWN)s %(LIQUID_TICKER)s déjà payé). Veuillez noter que si le montant retiré est modifié, le compteur pour le prochain retrait sera remis à zéro également.",
- "delegating": "Vous déléguez actuellement %(AMOUNT)s %(LIQUID_TICKER)s. Ce montant est bloqué et est indisponible pour tout retrait d'influence, ou power down, tant que la délégation n'est pas annulée et qu'une période complète de gains soit passée.",
- "per_week": "C'est environ %(AMOUNT)s%(LIQUID_TICKER)s par semaine.",
- "warning": "Laisser moins de%(AMOUNT)s%(VESTING_TOKEN)s sur votre compte n'est pas recommandé et peut rendre votre compte inutilisable.",
- "error": "Impossible d'effectuer un retrait d'influence (ERREUR : %(MESSAGE)s)"
- },
- "checkloginowner_jsx": {
- "your_password_permissions_were_reduced": "Les permissions de votre mot de passe ont été réduites",
- "if_you_did_not_make_this_change": "Si vous n'avez pas fait ce changement, veuillez s'il-vous-plaît",
- "ownership_changed_on": "Changement de propriétaire à compter du ",
- "deadline_for_recovery_is": "La date limite de récupération est",
- "i_understand_dont_show_again": "J'ai compris, ne me le montrez plus jamais"
- }
}
diff --git a/src/app/locales/it.json b/src/app/locales/it.json
index 74464332cb003dd92f41830837add9873cc2cea6..0c69e04f5fda67cde46ce1353b6cd5738e4fd0ba 100644
--- a/src/app/locales/it.json
+++ b/src/app/locales/it.json
@@ -1,648 +1,782 @@
{
- "g": {
- "age": "età",
- "amount": "Quantità",
- "and": "e",
- "are_you_sure": "Sei sicuro?",
- "ask": "Ask",
- "balance": "Saldo",
- "balances": "Saldi",
- "bid": "Bid",
- "blog": "Blog",
- "browse": "Naviga",
- "buy": "Acquista",
- "buy_or_sell": "Acquista o vendi",
- "by": "da",
- "cancel": "Cancella",
- "change_password": "Cambia Password",
- "choose_language": "Scegli la lingua",
- "clear": "Pulisci",
- "close": "Chiudi",
- "collapse_or_expand": "Riduci/Espandi",
- "comments": "Commenti",
- "confirm": "Conferma",
- "convert": "Converti",
- "date": "Data",
- "delete": "Elimina",
- "dismiss": "Abbandona",
- "edit": "Modifica",
- "email": "Email",
- "feed": "Feed",
- "follow": "Segui",
- "for": "per",
- "from": "da",
- "go_back": "Indietro",
- "hide": "Nascondi",
- "in": "in",
- "in_reply_to": "in risposta a",
- "insufficient_balance": "Credito insufficiente",
- "invalid_amount": "Importo errato",
- "joined": "Connesso",
- "loading": "Caricamento",
- "login": "Login",
- "logout": "Logout",
- "memo": "Memo",
- "mute": "Silenzia",
- "new": "Nuovo",
- "newer": "Più recente",
- "next": "Prossimo",
- "no": "No",
- "ok": "Ok",
- "older": "Meno recente",
- "or": "o",
- "order_placed": "Ordine piazzato",
- "password": "Password",
- "payouts": "Pagamenti",
- "permissions": "Permessi",
- "phishy_message": "Link expanded to plain text; beware of a potential phishing attempt",
- "post": "Post",
- "post_as": "Pubblica come",
- "posts": "Posts",
- "powered_up_100": "Powered Up 100%%",
- "preview": "Anteprima",
- "previous": "Precedente",
- "price": "Prezzo",
- "print": "Stampa",
- "promote": "Promuovi",
- "promoted": "promosso",
- "re": "RE",
- "re_to": "RE: %(topic)s",
- "recent_password": "Password Recente",
- "receive": "Ricevi",
- "remove": "Rimuovi",
- "remove_vote": "Rimuovi il voto",
- "replied_to": "risposto a %(account)s",
- "replies": "Risponde",
- "reply": "Risposta",
- "reply_count": {
- "zero": "Nessuna risposta",
- "one": "1 risposta",
- "other": "%(count)s risposte"
- },
- "reputation": "Reputazione",
- "reveal_comment": "Mostra Commento",
- "request": "richiesta",
- "required": "Richiesto",
- "rewards": "Ricompense",
- "save": "Salva",
- "saved": "Salvato",
- "search": "Cerca",
- "sell": "Vendi",
- "settings": "Impostazioni",
- "share_this_post": "Condividi questo post",
- "show": "Mostra",
- "sign_in": "Accedi",
- "sign_up": "Registrati",
- "since": "da",
- "submit": "Sottoscrivi",
- "power_up": "Power Up",
- "submit_a_story": "Post",
- "tag": "Tag",
- "to": "a",
- "all_tags": "All tags",
- "transfer": "Trasferisci",
- "trending_topics": "Trending Topics",
- "type": "Scrivi",
- "unfollow": "Non seguire più",
- "unmute": "Unmute",
- "unknown": "Sconosciuto",
- "upvote": "Upvote",
- "upvote_post": "Upvote post",
- "username": "Username",
- "version": "Versione",
- "vote": "Vota",
- "votes": "voti",
- "wallet": "Wallet",
- "warning": "avviso",
- "yes": "Sì",
- "posting": "Postare",
- "owner": "Proprietario",
- "active": "Attivo",
- "account_not_found": "Account non trovato",
- "this_is_wrong_password": "Password errata",
- "do_you_need_to": "Hai bisogno di",
- "account_name": "Nome Account",
- "recover_your_account": "recupera il tuo account",
- "reset_usernames_password": "Resetta la password di %(username)s",
- "this_will_update_usernames_authtype_key": "Questo aggiornerà la %(authType)s key di %(username)s ",
- "passwords_do_not_match": "Le password non corrispondono",
- "you_need_private_password_or_key_not_a_public_key": "Hai bisogno di una password privata o di una chiave (non di una chiave pubblica)",
- "the_rules_of_APP_NAME": {
- "one": "La prima regola di %(APP_NAME)sè: Non perdere la tua password.",
- "second": "La seconda regola di %(APP_NAME)s è: Non perdere la tua password.",
- "third": "La terza regola di %(APP_NAME)s è: Non possiamo recuperare la tua password.",
- "fourth": "La quarta regola è: Se puoi ricordare la password, non è sicura.",
- "fifth": "La quinta regola è: Usa solo password generate in modo casuale.",
- "sixth": "La sesta regola è: Non dire a nessuno la tua password.",
- "seventh": "La settima regola è: Salva sempre la tua password."
- },
- "recover_password": "Recupera Account",
- "current_password": "Password attuale",
- "generated_password": "Password generata",
- "backup_password_by_storing_it": "Effettua il backup copiando la password in un file di testo o in un gestore di password. ",
- "enter_account_show_password": "Inserisci un nome account valido per visualizzare la password",
- "click_to_generate_password": "Clicca per generare una password",
- "re_enter_generate_password": "Inserisci di nuovo la Password Generata",
- "understand_that_APP_NAME_cannot_recover_password": "Ho capito che %(APP_NAME)s non può recuperare le password perse",
- "i_saved_password": "Ho salvato in modo sicuro la mia password generata automaticamente",
- "update_password": "Aggiorna la password",
- "confirm_password": "Conferma la password",
- "account_updated": "Account aggiornato",
- "password_must_be_characters_or_more": "La password deve essere lunga %(amount)s caratteri o più",
- "need_password_or_key": "Hai bisogno di una password o di una chiave privata (non una chiave pubblica)",
- "login_to_see_memo": "Esegui il login per visualizzare la memo",
- "new_password": "Nuova password",
- "incorrect_password": "Password errata",
- "username_does_not_exist": "Il nome utente non esiste",
- "account_name_should_start_with_a_letter": "Il nome dell'account deve iniziare con una lettera.",
- "account_name_should_be_shorter": "Il nome dell'account deve essere più corto.",
- "account_name_should_be_longer": "Il nome dell'account deve essere più lungo.",
- "account_name_should_have_only_letters_digits_or_dashes": "Il nome account deve essere composto solo da lettere, cifre e trattini.",
- "cannot_increase_reward_of_post_within_the_last_minute_before_payout": "Non è possibile aumentare le ricompense del post durante l'ultimo minuto prima del pagamento",
- "vote_currently_exists_user_must_be_indicate_a_to_reject_witness": "Attualmente il voto esiste, l'utente deve indicare la volonta di rigettare il witness ",
- "only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes": "è possibile utilizzare un solo Steem account per indirizzo IP ogni 10 minuti",
- "resteem_this_post": "Fai il resteem di questo post",
- "reblog": "Resteem",
- "write_your_story": "Scrivi la tua storia",
- "remember_voting_and_posting_key": "Ricorda la chiave di voto e di pubblicazione",
- "auto_login_question_mark": "Accesso automatico?",
- "hide_private_key": "Nascondi la chiave privata",
- "show_private_key": "Mostra la chiave privata",
- "login_to_show": "Esegui il login per mostrare",
- "not_valid_email": "Email non valida",
- "thank_you_for_being_an_early_visitor_to_APP_NAME": "Ti ringraziamo per essere uno dei primi visitatori di %(APP_NAME)s. Sarai ricontattato il prima possibile. ",
- "author_rewards": "Ricompense da autore",
- "curation_rewards": "Ricompense da curatore",
- "sorry_your_reddit_account_doesnt_have_enough_karma": "Purtroppo il tuo account Reddit non possiede abbastanza Reddit Karma per essere usato per la registrazione gratuita. Aggiungi per favore la tua email per ottenere un posto in lista d'attesa.",
- "register_with_facebook": "Registrati con Facebook",
- "or_click_the_button_below_to_register_with_facebook": "O premi il pulsante sottostante per registrarti con Facebook",
- "server_returned_error": "Errore del server",
- "APP_NAME_support": "Supporto %(APP_NAME)s",
- "please_email_questions_to": "Per piacere invia le tue domande tramite email a",
- "next_7_strings_single_block": {
- "authors_get_paid_when_people_like_you_upvote_their_post": "Gli autori ricevono un compenso quando gli utenti come te votano il loro post. ",
- "if_you_enjoyed_what_you_read_earn_amount": "Se ti piace quello che hai letto, crea il tuo account oggi e inizia ricevendo STEEM GRATIS!",
- "free_steem": "STEEM GRATIS!",
- "sign_up_earn_steem": "Registrati adesso per guadagnare"
- },
- "next_3_strings_together": {
- "show_more": "Mostra di più",
- "show_less": "Mostra di meno",
- "value_posts": "post di basso valore"
- },
- "read_only_mode": "Server in manutenzione, modalità sola lettura attiva. Ci scusiamo per l'inconveniente.",
- "tags_and_topics": "Tag e argomenti",
- "show_more_topics": "Vedi più argomenti",
- "basic": "Base",
- "advanced": "Avanzato",
- "views": {
- "zero": "Nessuna Visualizzazione",
- "one": "%(count)s Visualizzazione",
- "other": "%(count)s Visualizzazioni"
- },
- "responses": {
- "zero": "Nessuna Risposta",
- "one": "%(count)s Risposta",
- "other": "%(count)s Risposte"
- },
- "post_key_warning": {
- "confirm": "You are about to publish a STEEM private key or master password. You will probably lose control of the associated account and all its funds.",
- "warning": "Legitimate users, including employees of Steemit Inc., will never ask you for a private key or master password.",
- "checkbox": "I understand"
- }
- },
- "navigation": {
- "about": "Circa",
- "explore": "Esplora",
- "APP_NAME_whitepaper": "%(APP_NAME)s Whitepaper",
- "buy_LIQUID_TOKEN": "Compra %(LIQUID_TOKEN)s",
- "sell_LIQUID_TOKEN": "Vendi %(LIQUID_TOKEN)s",
- "currency_market": "Mercato della valuta",
- "stolen_account_recovery": "Recupero degli Account Rubati",
- "change_account_password": "Cambia la password dell'account",
- "witnesses": "Witness",
- "vote_for_witnesses": "Vota per i Witness",
- "privacy_policy": "Privacy Policy",
- "terms_of_service": "Condizioni di servizio",
- "sign_up": "Entra",
- "learn_more": "Scopri di più",
- "welcome": "Benvenuto",
- "faq": "FAQ",
- "shop": "The Steemit Shop",
- "chat": "Steemit Chat",
- "app_center": "Steemit App Center",
- "api_docs": "Steemit API Docs",
- "bluepaper": "Steem Bluepaper",
- "whitepaper": "Steem Whitepaper",
- "intro_tagline": "Il denaro parla",
- "intro_paragraph": "La tua voce vale qualcosa. Entra nella comunità che ti pagare per pubblicare e curare contenuti di alta qualità."
- },
- "main_menu": {
- "hot": "hot",
- "trending": "trending"
- },
- "reply_editor": {
- "shorten_title": "Titolo breve",
- "exceeds_maximum_length": "Supera la grandezza massima (%(maxKb)sKB)",
- "including_the_category": " (inclusa la categoria '%(rootCategory)s')",
- "use_limited_amount_of_tags": "Hai %(tagsLength)s tag in totale %(includingCategory)s. Usane solo 5 nel tuo post e nella linea delle categorie.",
- "are_you_sure_you_want_to_clear_this_form": "Sicuro di voler cancellare questo form?",
- "uploading": "Caricamento",
- "draft_saved": "Bozza salvata",
- "editor": "Editor",
- "insert_images_by_dragging_dropping": "Per inserire le immagini, trascinale qui",
- "pasting_from_the_clipboard": "incollando dagli appunti,",
- "selecting_them": "selezionandole. ",
- "image_upload": "Carica immagine",
- "power_up_100": "Power Up 100%%",
- "default_50_50": "Default (50%% / 50%%)",
- "decline_payout": "Rinuncia al pagamento",
- "check_this_to_auto_upvote_your_post": "Clicca qui per effettuare l'upvote automatico del tuo post",
- "markdown_styling_guide": "Guida di stile Markdown",
- "or_by": "o da",
- "title": "Titolo",
- "update_post": "Aggiorna il Post",
- "markdown_not_supported": "Il Markdown non è supportato qui"
- },
- "category_selector_jsx": {
- "tag_your_story": "Tag (massimo 5). Il primo tag è la categoria principale. ",
- "select_a_tag": "Seleziona un tag",
- "maximum_tag_length_is_24_characters": "La lunghezza massima di un tag è 24 caratteri",
- "use_limited_amount_of_categories": "Utilizzare solo %(amount)s categorie",
- "use_only_lowercase_letters": "Usa solo caratteri minuscoli",
- "use_one_dash": "Usa solo un trattino",
- "use_spaces_to_separate_tags": "Usa gli spazi per separare i tag",
- "use_only_allowed_characters": "Usa solo lettere minuscole, cifre e un trattino",
- "must_start_with_a_letter": "Deve iniziare con una lettera",
- "must_end_with_a_letter_or_number": "Deve terminare con una lettera o un numero"
- },
- "postfull_jsx": {
- "this_post_is_not_available_due_to_a_copyright_claim": "Questo post non è disponibile per violazione del copyright.",
- "share_on_facebook": "Condividi su Facebook",
- "share_on_twitter": "Condividi su Twitter",
- "share_on_linkedin": "Condividi su Linkedin",
- "recent_password": "Password recente",
- "in_week_convert_DEBT_TOKEN_to_LIQUID_TOKEN": "In 3,5 giorni, converti %(amount)s%(DEBT_TOKEN)s in %(LIQUID_TOKEN)s",
- "view_the_full_context": "Vedi il contesto completo",
- "view_the_direct_parent": "Visualizza il collegamento diretto",
- "you_are_viewing_a_single_comments_thread_from": "Stai visualizzando il commento singolo di un thread di "
- },
- "market_jsx": {
- "action": "Azione",
- "date_created": "Data creazione",
- "last_price": "Ultimo prezzo",
- "24h_volume": "Volume nelle 24 ore",
- "spread": "Spread",
- "total": "Totale",
- "available": "Disponibile",
- "lowest_ask": "Prezzo di vendità più basso",
- "highest_bid": "Prezzo di acquisto più alto",
- "buy_orders": "Ordini d'acquisto",
- "sell_orders": "Ordini di vendita",
- "trade_history": "Cronologia delle Transazioni",
- "open_orders": "Ordini Aperti",
- "sell_amount_for_atleast": "Vendi %(amount_to_sell)s per almeno %(min_to_receive)s (%(effectivePrice)s)",
- "buy_atleast_amount_for": "Compra ad almeno %(min_to_receive)s per %(amount_to_sell)s (%(effectivePrice)s)",
- "price_warning_above": "Questo prezzo è ben al di sopra del prezzo di mercato corrente di %(marketPrice)s, sei sicuro?",
- "price_warning_below": "Questo prezzo è ben al di sotto del prezzo di mercato corrente di %(marketPrice)s, sei sicuro?",
- "order_cancel_confirm": "Cancella l'ordine %(order_id)s per %(user)s?",
- "order_cancelled": "Ordine %(order_id)s cancellato",
- "higher": "Più alto",
- "lower": "Più basso",
- "total_DEBT_TOKEN_SHORT_CURRENCY_SIGN": "Totale %(DEBT_TOKEN_SHORT)s (%(CURRENCY_SIGN)s)"
- },
- "recoveraccountstep1_jsx": {
- "begin_recovery": "Inizia il Ripristino",
- "not_valid": "Non valido",
- "account_name_is_not_found": "Nome account non trovato",
- "unable_to_recover_account_not_change_ownership_recently": "Non possiamo recuperare questo account, non ha cambiato proprietario di recente. ",
- "password_not_used_in_last_days": "Questa password non viene usata per questo account da 30 giorni. ",
- "request_already_submitted_contact_support": "La tua richiesta è stata già inviata e la stiamo lavorando. Puoi contattare %(SUPPORT_EMAIL)sper verificare lo stato della tua richiesta.",
- "recover_account_intro": "Può succedere che ogni tanto la chiave personale di un membro di Steemit possa essere compromessa. La funzione \"Recupera account rubato\" dà 30 giorni al legittimo proprietario dell'account per recuperarlo dal momento in cui il ladro cambia la chiave personale. \"Recupera account rubato\" può essere usato solo su %(APP_URL)s se il proprietario dell'account ha precedentemente inserito %(APP_NAME)s come account fidato e accettato i Termini di Servizio di %(APP_NAME)s.",
- "login_with_facebook_or_reddit_media_to_verify_identity": "Effettua il login con Facebook o Reddit per verificare la tua identità ",
- "login_with_social_media_to_verify_identity": "Effettua il login con %(provider)s per verificare la tua identità",
- "enter_email_toverify_identity": "Abbiamo bisogno di verificare la tua identità. Inserisci di seguito il tuo indirizzo email per iniziare la verifica. ",
- "continue_with_email": "Continua con l'email",
- "thanks_for_submitting_request_for_account_recovery": "Grazie per aver immesso la tua richiesta per Ripristinare il tuo Account usando l'autenticazione multi fattoriale basata sulla blockchain di %(APP_NAME)s. Ti risponderemo il prima possibile, comunque considera che potrebbero esserci ritardi nella risposta a causa del grade volume di email. Preparati a verificare la tua identità.",
- "recovering_account": "Stiamo recuperando l'account",
- "recover_account": "Recupero Account",
- "checking_account_owner": "Stiamo controllando il proprietario dell'account",
- "sending_recovery_request": "Invia richiesta di recupero ",
- "cant_confirm_account_ownership": "Non siamo riusciti a confermare la proprietà dell'account. Controlla la password.",
- "account_recovery_request_not_confirmed": "La richiesta di recupero account non è ancora stata confermata. Per favore, ritorna tra un po'. Grazie per la pazienza! "
- },
- "user_profile": {
- "unknown_account": "Account sconosciuto",
- "user_hasnt_made_any_posts_yet": "Sembra che %(name)snon abbia ancora pubblicato nessun post! ",
- "user_hasnt_started_bloggin_yet": "Sembra che %(name)s non abbia ancora iniziato a scrivere!",
- "user_hasnt_followed_anything_yet": "Sembra che %(name)snon stia seguendo ancora nessuno! Se %(name)sha aggiunto di recente nuovi utenti da seguire, il feed personalizzato si riempirà di contenuti non appena ce ne saranno di nuovi. ",
- "user_hasnt_had_any_replies_yet": "%(name)s hasn't had any replies yet",
- "looks_like_you_havent_posted_anything_yet": "Looks like you haven't posted anything yet.",
- "create_a_post": "Create a Post",
- "explore_trending_articles": "Explore Trending Articles",
- "read_the_quick_start_guide": "Read The Quick Start Guide",
- "browse_the_faq": "Browse The FAQ",
- "followers": "Followers",
- "this_is_users_reputations_score_it_is_based_on_history_of_votes": "Questo è il livello di reputazione di %(name)s. \n\nIl livello di reputazione si basa sulla storia dei voti ricevuti dall'account e viene utilizzato per nascondere contenuti di scarsa qualità. ",
- "follower_count": {
- "zero": "Nessun follower",
- "one": "1 follower",
- "other": "%(count)s follower"
- },
- "followed_count": {
- "zero": "Non segue nessuno",
- "one": "1 following",
- "other": "%(count)s following"
- },
- "post_count": {
- "zero": "Nessun post",
- "one": "1 post",
- "other": "%(count)s post"
- }
- },
- "authorrewards_jsx": {
- "estimated_author_rewards_last_week": "Ricompense per l'autore stimate durante l'ultima settimana",
- "author_rewards_history": "Cronologia di Ricompense dell'autore"
- },
- "curationrewards_jsx": {
- "estimated_curation_rewards_last_week": "Ricompense da curatore stimate nell'ultima settimana",
- "curation_rewards_history": "Cronologia ricompense da curatore"
- },
- "post_jsx": {
- "now_showing_comments_with_low_ratings": "Commenti con voti bassi rivelati",
- "sort_order": "Ordinamento",
- "comments_were_hidden_due_to_low_ratings": "Commenti nascosti a causa del basso rating"
- },
- "voting_jsx": {
- "flagging_post_can_remove_rewards_the_flag_should_be_used_for_the_following": "Flaggare un post può rimuovere le ricompense e rendere questo materiale meno visibile. Alcune ragioni comuni per effettuare un flag sono",
- "disagreement_on_rewards": "Disaccordo sulle ricompense",
- "fraud_or_plagiarism": "Frode o Plagio",
- "hate_speech_or_internet_trolling": "Incitamento all'odio o Trolling",
- "intentional_miss_categorized_content_or_spam": "Contenuto volutamente categorizzato impropriamente o spam",
- "pending_payout": "Pagamento in attesa $%(value)s",
- "payout_declined": "Pagamento Rifiutato",
- "max_accepted_payout": "Il pagamento massimo accettato è di %(value)s $",
- "promotion_cost": "Costo della Promozione $%(value)s",
- "past_payouts": "Pagamenti precedenti di %(value)s $",
- "past_payouts_author": "- Autore %(value)s $",
- "past_payouts_curators": "- Curatori %(value)s $",
- "we_will_reset_curation_rewards_for_this_post": "sarà effettuato il reset delle ricompense del curatore in questo post. ",
- "removing_your_vote": "Rimuovi il tuo voto",
- "changing_to_an_upvote": "Cambia in un upvote",
- "changing_to_a_downvote": "Cambia in un downvote",
- "confirm_flag": "Conferma il flag",
- "and_more": "e %(count)s in più",
- "votes_plural": {
- "one": "%(count)s voto",
- "other": "%(count)s voti"
- }
- },
- "witnesses_jsx": {
- "witness_thread": "witness thread",
- "top_witnesses": "Voto Witness ",
- "you_have_votes_remaining": {
- "zero": "Non hai voti residui",
- "one": "Ti resta 1 voto",
- "other": "Hai %(count)svoti residui"
- },
- "you_can_vote_for_maximum_of_witnesses": "Puoi votare un massimo di 30 witness",
- "witness": "Witness",
- "information": "Informazioni",
- "if_you_want_to_vote_outside_of_top_enter_account_name": "Se desideri votare un witness al di fuori della top 50, inserisci di seguito il nome account per effettuare il voto. ",
- "set_witness_proxy": "Puoi anche scegliere un proxy che voterà i witnesses per te. Questo resetterà la tua attuale selezione di testimoni.",
- "witness_set": "Hai settato un proxy di voto. Se volessi riabilitare il voto manuale, cancella il tuo proxy.",
- "witness_proxy_current": "Il tuo attuale proxy è:",
- "witness_proxy_set": "Setta il proxy",
- "witness_proxy_clear": "Cancella il proxy",
- "proxy_update_error": "Il tuo proxy non è aggiornato"
- },
- "votesandcomments_jsx": {
- "no_responses_yet_click_to_respond": "Non c'è ancora nessuna risposta. Clicca per rispondere.",
- "response_count_tooltip": {
- "zero": "Nessun commento. Clicca per commentare.",
- "one": "1 commento. Clicca per commentare.",
- "other": "%(count)s commenti. Clicca per commentare."
- },
- "vote_count": {
- "zero": "Nessun voto",
- "one": "1 voto",
- "other": "%(count)s voti"
+ "g": {
+ "age": "età",
+ "amount": "Quantità",
+ "and": "e",
+ "are_you_sure": "Sei sicuro?",
+ "ask": "Ask",
+ "balance": "Saldo",
+ "balances": "Saldi",
+ "bid": "Bid",
+ "blog": "Blog",
+ "browse": "Naviga",
+ "buy": "Acquista",
+ "buy_or_sell": "Acquista o vendi",
+ "by": "da",
+ "cancel": "Cancella",
+ "change_password": "Cambia Password",
+ "choose_language": "Scegli la lingua",
+ "clear": "Pulisci",
+ "close": "Chiudi",
+ "collapse_or_expand": "Riduci/Espandi",
+ "comments": "Commenti",
+ "confirm": "Conferma",
+ "convert": "Converti",
+ "date": "Data",
+ "delete": "Elimina",
+ "dismiss": "Abbandona",
+ "edit": "Modifica",
+ "email": "Email",
+ "feed": "Feed",
+ "follow": "Segui",
+ "for": "per",
+ "from": "da",
+ "go_back": "Indietro",
+ "hide": "Nascondi",
+ "in": "in",
+ "in_reply_to": "in risposta a",
+ "insufficient_balance": "Credito insufficiente",
+ "invalid_amount": "Importo errato",
+ "joined": "Connesso",
+ "loading": "Caricamento",
+ "login": "Login",
+ "logout": "Logout",
+ "memo": "Memo",
+ "mute": "Silenzia",
+ "new": "Nuovo",
+ "newer": "Più recente",
+ "next": "Prossimo",
+ "no": "No",
+ "ok": "Ok",
+ "older": "Meno recente",
+ "or": "o",
+ "order_placed": "Ordine piazzato",
+ "password": "Password",
+ "payouts": "Pagamenti",
+ "permissions": "Permessi",
+ "phishy_message":
+ "Link expanded to plain text; beware of a potential phishing attempt",
+ "post": "Post",
+ "post_as": "Pubblica come",
+ "posts": "Posts",
+ "powered_up_100": "Powered Up 100%%",
+ "preview": "Anteprima",
+ "previous": "Precedente",
+ "price": "Prezzo",
+ "print": "Stampa",
+ "promote": "Promuovi",
+ "promoted": "promosso",
+ "re": "RE",
+ "re_to": "RE: %(topic)s",
+ "recent_password": "Password Recente",
+ "receive": "Ricevi",
+ "remove": "Rimuovi",
+ "remove_vote": "Rimuovi il voto",
+ "replied_to": "risposto a %(account)s",
+ "replies": "Risponde",
+ "reply": "Risposta",
+ "reply_count": {
+ "zero": "Nessuna risposta",
+ "one": "1 risposta",
+ "other": "%(count)s risposte"
+ },
+ "reputation": "Reputazione",
+ "reveal_comment": "Mostra Commento",
+ "request": "richiesta",
+ "required": "Richiesto",
+ "rewards": "Ricompense",
+ "save": "Salva",
+ "saved": "Salvato",
+ "search": "Cerca",
+ "sell": "Vendi",
+ "settings": "Impostazioni",
+ "share_this_post": "Condividi questo post",
+ "show": "Mostra",
+ "sign_in": "Accedi",
+ "sign_up": "Registrati",
+ "since": "da",
+ "submit": "Sottoscrivi",
+ "power_up": "Power Up",
+ "submit_a_story": "Post",
+ "tag": "Tag",
+ "to": "a",
+ "all_tags": "All tags",
+ "transfer": "Trasferisci",
+ "trending_topics": "Trending Topics",
+ "type": "Scrivi",
+ "unfollow": "Non seguire più",
+ "unmute": "Unmute",
+ "unknown": "Sconosciuto",
+ "upvote": "Upvote",
+ "upvote_post": "Upvote post",
+ "username": "Username",
+ "version": "Versione",
+ "vote": "Vota",
+ "votes": "voti",
+ "wallet": "Wallet",
+ "warning": "avviso",
+ "yes": "Sì",
+ "posting": "Postare",
+ "owner": "Proprietario",
+ "active": "Attivo",
+ "account_not_found": "Account non trovato",
+ "this_is_wrong_password": "Password errata",
+ "do_you_need_to": "Hai bisogno di",
+ "account_name": "Nome Account",
+ "recover_your_account": "recupera il tuo account",
+ "reset_usernames_password": "Resetta la password di %(username)s",
+ "this_will_update_usernames_authtype_key":
+ "Questo aggiornerà la %(authType)s key di %(username)s ",
+ "passwords_do_not_match": "Le password non corrispondono",
+ "you_need_private_password_or_key_not_a_public_key":
+ "Hai bisogno di una password privata o di una chiave (non di una chiave pubblica)",
+ "the_rules_of_APP_NAME": {
+ "one":
+ "La prima regola di %(APP_NAME)sè: Non perdere la tua password.",
+ "second":
+ "La seconda regola di %(APP_NAME)s è: Non perdere la tua password.",
+ "third":
+ "La terza regola di %(APP_NAME)s è: Non possiamo recuperare la tua password.",
+ "fourth":
+ "La quarta regola è: Se puoi ricordare la password, non è sicura.",
+ "fifth":
+ "La quinta regola è: Usa solo password generate in modo casuale.",
+ "sixth": "La sesta regola è: Non dire a nessuno la tua password.",
+ "seventh": "La settima regola è: Salva sempre la tua password."
+ },
+ "recover_password": "Recupera Account",
+ "current_password": "Password attuale",
+ "generated_password": "Password generata",
+ "backup_password_by_storing_it":
+ "Effettua il backup copiando la password in un file di testo o in un gestore di password. ",
+ "enter_account_show_password":
+ "Inserisci un nome account valido per visualizzare la password",
+ "click_to_generate_password": "Clicca per generare una password",
+ "re_enter_generate_password": "Inserisci di nuovo la Password Generata",
+ "understand_that_APP_NAME_cannot_recover_password":
+ "Ho capito che %(APP_NAME)s non può recuperare le password perse",
+ "i_saved_password":
+ "Ho salvato in modo sicuro la mia password generata automaticamente",
+ "update_password": "Aggiorna la password",
+ "confirm_password": "Conferma la password",
+ "account_updated": "Account aggiornato",
+ "password_must_be_characters_or_more":
+ "La password deve essere lunga %(amount)s caratteri o più",
+ "need_password_or_key":
+ "Hai bisogno di una password o di una chiave privata (non una chiave pubblica)",
+ "login_to_see_memo": "Esegui il login per visualizzare la memo",
+ "new_password": "Nuova password",
+ "incorrect_password": "Password errata",
+ "username_does_not_exist": "Il nome utente non esiste",
+ "account_name_should_start_with_a_letter":
+ "Il nome dell'account deve iniziare con una lettera.",
+ "account_name_should_be_shorter":
+ "Il nome dell'account deve essere più corto.",
+ "account_name_should_be_longer":
+ "Il nome dell'account deve essere più lungo.",
+ "account_name_should_have_only_letters_digits_or_dashes":
+ "Il nome account deve essere composto solo da lettere, cifre, punti o trattini.",
+ "cannot_increase_reward_of_post_within_the_last_minute_before_payout":
+ "Non è possibile aumentare le ricompense del post durante l'ultimo minuto prima del pagamento",
+ "vote_currently_exists_user_must_be_indicate_a_to_reject_witness":
+ "Attualmente il voto esiste, l'utente deve indicare la volonta di rigettare il witness ",
+ "only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes":
+ "è possibile utilizzare un solo Steem account per indirizzo IP ogni 10 minuti",
+ "resteem_this_post": "Fai il resteem di questo post",
+ "reblog": "Resteem",
+ "write_your_story": "Scrivi la tua storia",
+ "remember_voting_and_posting_key":
+ "Ricorda la chiave di voto e di pubblicazione",
+ "auto_login_question_mark": "Accesso automatico?",
+ "hide_private_key": "Nascondi la chiave privata",
+ "show_private_key": "Mostra la chiave privata",
+ "login_to_show": "Esegui il login per mostrare",
+ "not_valid_email": "Email non valida",
+ "thank_you_for_being_an_early_visitor_to_APP_NAME":
+ "Ti ringraziamo per essere uno dei primi visitatori di %(APP_NAME)s. Sarai ricontattato il prima possibile. ",
+ "author_rewards": "Ricompense da autore",
+ "curation_rewards": "Ricompense da curatore",
+ "sorry_your_reddit_account_doesnt_have_enough_karma":
+ "Purtroppo il tuo account Reddit non possiede abbastanza Reddit Karma per essere usato per la registrazione gratuita. Aggiungi per favore la tua email per ottenere un posto in lista d'attesa.",
+ "register_with_facebook": "Registrati con Facebook",
+ "or_click_the_button_below_to_register_with_facebook":
+ "O premi il pulsante sottostante per registrarti con Facebook",
+ "server_returned_error": "Errore del server",
+ "APP_NAME_support": "Supporto %(APP_NAME)s",
+ "please_email_questions_to":
+ "Per piacere invia le tue domande tramite email a",
+ "next_7_strings_single_block": {
+ "authors_get_paid_when_people_like_you_upvote_their_post":
+ "Gli autori ricevono un compenso quando gli utenti come te votano il loro post. ",
+ "if_you_enjoyed_what_you_read_earn_amount":
+ "Se ti piace quello che hai letto, crea il tuo account oggi e inizia ricevendo STEEM GRATIS!",
+ "free_steem": "STEEM GRATIS!",
+ "sign_up_earn_steem": "Registrati adesso per guadagnare"
+ },
+ "next_3_strings_together": {
+ "show_more": "Mostra di più",
+ "show_less": "Mostra di meno",
+ "value_posts": "post di basso valore"
+ },
+ "read_only_mode":
+ "Server in manutenzione, modalità sola lettura attiva. Ci scusiamo per l'inconveniente.",
+ "tags_and_topics": "Tag e argomenti",
+ "show_more_topics": "Vedi più argomenti",
+ "basic": "Base",
+ "advanced": "Avanzato",
+ "views": {
+ "zero": "Nessuna Visualizzazione",
+ "one": "%(count)s Visualizzazione",
+ "other": "%(count)s Visualizzazioni"
+ },
+ "responses": {
+ "zero": "Nessuna Risposta",
+ "one": "%(count)s Risposta",
+ "other": "%(count)s Risposte"
+ },
+ "post_key_warning": {
+ "confirm":
+ "You are about to publish a STEEM private key or master password. You will probably lose control of the associated account and all its funds.",
+ "warning":
+ "Legitimate users, including employees of Steemit Inc., will never ask you for a private key or master password.",
+ "checkbox": "I understand"
+ }
+ },
+ "navigation": {
+ "about": "Circa",
+ "explore": "Esplora",
+ "APP_NAME_whitepaper": "%(APP_NAME)s Whitepaper",
+ "buy_LIQUID_TOKEN": "Compra %(LIQUID_TOKEN)s",
+ "sell_LIQUID_TOKEN": "Vendi %(LIQUID_TOKEN)s",
+ "currency_market": "Mercato della valuta",
+ "stolen_account_recovery": "Recupero degli Account Rubati",
+ "change_account_password": "Cambia la password dell'account",
+ "witnesses": "Witness",
+ "vote_for_witnesses": "Vota per i Witness",
+ "privacy_policy": "Privacy Policy",
+ "terms_of_service": "Condizioni di servizio",
+ "sign_up": "Entra",
+ "learn_more": "Scopri di più",
+ "welcome": "Benvenuto",
+ "faq": "FAQ",
+ "shop": "The Steemit Shop",
+ "chat": "Steem Chat",
+ "app_center": "Steemit App Center",
+ "api_docs": "Steemit API Docs",
+ "bluepaper": "Steem Bluepaper",
+ "smt_whitepaper": "SMT Whitepaper",
+ "whitepaper": "Steem Whitepaper",
+ "intro_tagline": "Il denaro parla",
+ "intro_paragraph":
+ "La tua voce vale qualcosa. Entra nella comunità che ti pagare per pubblicare e curare contenuti di alta qualità."
+ },
+ "main_menu": {
+ "hot": "hot",
+ "trending": "trending"
+ },
+ "reply_editor": {
+ "shorten_title": "Titolo breve",
+ "exceeds_maximum_length": "Supera la grandezza massima (%(maxKb)sKB)",
+ "including_the_category": " (inclusa la categoria '%(rootCategory)s')",
+ "use_limited_amount_of_tags":
+ "Hai %(tagsLength)s tag in totale %(includingCategory)s. Usane solo 5 nel tuo post e nella linea delle categorie.",
+ "are_you_sure_you_want_to_clear_this_form":
+ "Sicuro di voler cancellare questo form?",
+ "uploading": "Caricamento",
+ "draft_saved": "Bozza salvata",
+ "editor": "Editor",
+ "insert_images_by_dragging_dropping":
+ "Per inserire le immagini, trascinale qui",
+ "pasting_from_the_clipboard": "incollando dagli appunti,",
+ "selecting_them": "selezionandole. ",
+ "image_upload": "Carica immagine",
+ "power_up_100": "Power Up 100%%",
+ "default_50_50": "Default (50%% / 50%%)",
+ "decline_payout": "Rinuncia al pagamento",
+ "check_this_to_auto_upvote_your_post":
+ "Clicca qui per effettuare l'upvote automatico del tuo post",
+ "markdown_styling_guide": "Guida di stile Markdown",
+ "or_by": "o da",
+ "title": "Titolo",
+ "update_post": "Aggiorna il Post",
+ "markdown_not_supported": "Il Markdown non è supportato qui"
+ },
+ "category_selector_jsx": {
+ "tag_your_story":
+ "Tag (massimo 5). Il primo tag è la categoria principale. ",
+ "select_a_tag": "Seleziona un tag",
+ "maximum_tag_length_is_24_characters":
+ "La lunghezza massima di un tag è 24 caratteri",
+ "use_limited_amount_of_categories":
+ "Utilizzare solo %(amount)s categorie",
+ "use_only_lowercase_letters": "Usa solo caratteri minuscoli",
+ "use_one_dash": "Usa solo un trattino",
+ "use_spaces_to_separate_tags": "Usa gli spazi per separare i tag",
+ "use_only_allowed_characters":
+ "Usa solo lettere minuscole, cifre e un trattino",
+ "must_start_with_a_letter": "Deve iniziare con una lettera",
+ "must_end_with_a_letter_or_number":
+ "Deve terminare con una lettera o un numero"
+ },
+ "postfull_jsx": {
+ "this_post_is_not_available_due_to_a_copyright_claim":
+ "Questo post non è disponibile per violazione del copyright.",
+ "share_on_facebook": "Condividi su Facebook",
+ "share_on_twitter": "Condividi su Twitter",
+ "share_on_linkedin": "Condividi su Linkedin",
+ "recent_password": "Password recente",
+ "in_week_convert_DEBT_TOKEN_to_LIQUID_TOKEN":
+ "In 3,5 giorni, converti %(amount)s%(DEBT_TOKEN)s in %(LIQUID_TOKEN)s",
+ "view_the_full_context": "Vedi il contesto completo",
+ "view_the_direct_parent": "Visualizza il collegamento diretto",
+ "you_are_viewing_a_single_comments_thread_from":
+ "Stai visualizzando il commento singolo di un thread di "
+ },
+ "market_jsx": {
+ "action": "Azione",
+ "date_created": "Data creazione",
+ "last_price": "Ultimo prezzo",
+ "24h_volume": "Volume nelle 24 ore",
+ "spread": "Spread",
+ "total": "Totale",
+ "available": "Disponibile",
+ "lowest_ask": "Prezzo di vendità più basso",
+ "highest_bid": "Prezzo di acquisto più alto",
+ "buy_orders": "Ordini d'acquisto",
+ "sell_orders": "Ordini di vendita",
+ "trade_history": "Cronologia delle Transazioni",
+ "open_orders": "Ordini Aperti",
+ "sell_amount_for_atleast":
+ "Vendi %(amount_to_sell)s per almeno %(min_to_receive)s (%(effectivePrice)s)",
+ "buy_atleast_amount_for":
+ "Compra ad almeno %(min_to_receive)s per %(amount_to_sell)s (%(effectivePrice)s)",
+ "price_warning_above":
+ "Questo prezzo è ben al di sopra del prezzo di mercato corrente di %(marketPrice)s, sei sicuro?",
+ "price_warning_below":
+ "Questo prezzo è ben al di sotto del prezzo di mercato corrente di %(marketPrice)s, sei sicuro?",
+ "order_cancel_confirm": "Cancella l'ordine %(order_id)s per %(user)s?",
+ "order_cancelled": "Ordine %(order_id)s cancellato",
+ "higher": "Più alto",
+ "lower": "Più basso",
+ "total_DEBT_TOKEN_SHORT_CURRENCY_SIGN":
+ "Totale %(DEBT_TOKEN_SHORT)s (%(CURRENCY_SIGN)s)"
+ },
+ "recoveraccountstep1_jsx": {
+ "begin_recovery": "Inizia il Ripristino",
+ "not_valid": "Non valido",
+ "account_name_is_not_found": "Nome account non trovato",
+ "unable_to_recover_account_not_change_ownership_recently":
+ "Non possiamo recuperare questo account, non ha cambiato proprietario di recente. ",
+ "password_not_used_in_last_days":
+ "Questa password non viene usata per questo account da 30 giorni. ",
+ "request_already_submitted_contact_support":
+ "La tua richiesta è stata già inviata e la stiamo lavorando. Puoi contattare %(SUPPORT_EMAIL)sper verificare lo stato della tua richiesta.",
+ "recover_account_intro":
+ "Può succedere che ogni tanto la chiave personale di un membro di Steemit possa essere compromessa. La funzione \"Recupera account rubato\" dà 30 giorni al legittimo proprietario dell'account per recuperarlo dal momento in cui il ladro cambia la chiave personale. \"Recupera account rubato\" può essere usato solo su %(APP_URL)s se il proprietario dell'account ha precedentemente inserito %(APP_NAME)s come account fidato e accettato i Termini di Servizio di %(APP_NAME)s.",
+ "login_with_facebook_or_reddit_media_to_verify_identity":
+ "Effettua il login con Facebook o Reddit per verificare la tua identità ",
+ "login_with_social_media_to_verify_identity":
+ "Effettua il login con %(provider)s per verificare la tua identità",
+ "enter_email_toverify_identity":
+ "Abbiamo bisogno di verificare la tua identità. Inserisci di seguito il tuo indirizzo email per iniziare la verifica. ",
+ "continue_with_email": "Continua con l'email",
+ "thanks_for_submitting_request_for_account_recovery":
+ "Grazie per aver immesso la tua richiesta per Ripristinare il tuo Account usando l'autenticazione multi fattoriale basata sulla blockchain di %(APP_NAME)s. Ti risponderemo il prima possibile, comunque considera che potrebbero esserci ritardi nella risposta a causa del grade volume di email. Preparati a verificare la tua identità.",
+ "recovering_account": "Stiamo recuperando l'account",
+ "recover_account": "Recupero Account",
+ "checking_account_owner":
+ "Stiamo controllando il proprietario dell'account",
+ "sending_recovery_request": "Invia richiesta di recupero ",
+ "cant_confirm_account_ownership":
+ "Non siamo riusciti a confermare la proprietà dell'account. Controlla la password.",
+ "account_recovery_request_not_confirmed":
+ "La richiesta di recupero account non è ancora stata confermata. Per favore, ritorna tra un po'. Grazie per la pazienza! "
+ },
+ "user_profile": {
+ "unknown_account": "Account sconosciuto",
+ "user_hasnt_made_any_posts_yet":
+ "Sembra che %(name)snon abbia ancora pubblicato nessun post! ",
+ "user_hasnt_started_bloggin_yet":
+ "Sembra che %(name)s non abbia ancora iniziato a scrivere!",
+ "user_hasnt_followed_anything_yet":
+ "Sembra che %(name)snon stia seguendo ancora nessuno! Se %(name)sha aggiunto di recente nuovi utenti da seguire, il feed personalizzato si riempirà di contenuti non appena ce ne saranno di nuovi. ",
+ "user_hasnt_had_any_replies_yet": "%(name)s hasn't had any replies yet",
+ "looks_like_you_havent_posted_anything_yet":
+ "Looks like you haven't posted anything yet.",
+ "create_a_post": "Create a Post",
+ "explore_trending_articles": "Explore Trending Articles",
+ "read_the_quick_start_guide": "Read The Quick Start Guide",
+ "browse_the_faq": "Browse The FAQ",
+ "followers": "Followers",
+ "this_is_users_reputations_score_it_is_based_on_history_of_votes":
+ "Questo è il livello di reputazione di %(name)s. \n\nIl livello di reputazione si basa sulla storia dei voti ricevuti dall'account e viene utilizzato per nascondere contenuti di scarsa qualità. ",
+ "follower_count": {
+ "zero": "Nessun follower",
+ "one": "1 follower",
+ "other": "%(count)s follower"
+ },
+ "followed_count": {
+ "zero": "Non segue nessuno",
+ "one": "1 following",
+ "other": "%(count)s following"
+ },
+ "post_count": {
+ "zero": "Nessun post",
+ "one": "1 post",
+ "other": "%(count)s post"
+ }
+ },
+ "authorrewards_jsx": {
+ "estimated_author_rewards_last_week":
+ "Ricompense per l'autore stimate durante l'ultima settimana",
+ "author_rewards_history": "Cronologia di Ricompense dell'autore"
+ },
+ "curationrewards_jsx": {
+ "estimated_curation_rewards_last_week":
+ "Ricompense da curatore stimate nell'ultima settimana",
+ "curation_rewards_history": "Cronologia ricompense da curatore"
+ },
+ "post_jsx": {
+ "now_showing_comments_with_low_ratings":
+ "Commenti con voti bassi rivelati",
+ "sort_order": "Ordinamento",
+ "comments_were_hidden_due_to_low_ratings":
+ "Commenti nascosti a causa del basso rating"
+ },
+ "voting_jsx": {
+ "flagging_post_can_remove_rewards_the_flag_should_be_used_for_the_following":
+ "Flaggare un post può rimuovere le ricompense e rendere questo materiale meno visibile. Alcune ragioni comuni per effettuare un flag sono",
+ "disagreement_on_rewards": "Disaccordo sulle ricompense",
+ "fraud_or_plagiarism": "Frode o Plagio",
+ "hate_speech_or_internet_trolling": "Incitamento all'odio o Trolling",
+ "intentional_miss_categorized_content_or_spam":
+ "Contenuto volutamente categorizzato impropriamente o spam",
+ "pending_payout": "Pagamento in attesa $%(value)s",
+ "payout_declined": "Pagamento Rifiutato",
+ "max_accepted_payout":
+ "Il pagamento massimo accettato è di %(value)s $",
+ "promotion_cost": "Costo della Promozione $%(value)s",
+ "past_payouts": "Pagamenti precedenti di %(value)s $",
+ "past_payouts_author": "- Autore %(value)s $",
+ "past_payouts_curators": "- Curatori %(value)s $",
+ "we_will_reset_curation_rewards_for_this_post":
+ "sarà effettuato il reset delle ricompense del curatore in questo post. ",
+ "removing_your_vote": "Rimuovi il tuo voto",
+ "changing_to_an_upvote": "Cambia in un upvote",
+ "changing_to_a_downvote": "Cambia in un downvote",
+ "confirm_flag": "Conferma il flag",
+ "and_more": "e %(count)s in più",
+ "votes_plural": {
+ "one": "%(count)s voto",
+ "other": "%(count)s voti"
+ }
+ },
+ "witnesses_jsx": {
+ "witness_thread": "witness thread",
+ "top_witnesses": "Voto Witness ",
+ "you_have_votes_remaining": {
+ "zero": "Non hai voti residui",
+ "one": "Ti resta 1 voto",
+ "other": "Hai %(count)svoti residui"
+ },
+ "you_can_vote_for_maximum_of_witnesses":
+ "Puoi votare un massimo di 30 witness",
+ "witness": "Witness",
+ "information": "Informazioni",
+ "if_you_want_to_vote_outside_of_top_enter_account_name":
+ "Se desideri votare un witness al di fuori della top 50, inserisci di seguito il nome account per effettuare il voto. ",
+ "set_witness_proxy":
+ "Puoi anche scegliere un proxy che voterà i witnesses per te. Questo resetterà la tua attuale selezione di testimoni.",
+ "witness_set":
+ "Hai settato un proxy di voto. Se volessi riabilitare il voto manuale, cancella il tuo proxy.",
+ "witness_proxy_current": "Il tuo attuale proxy è:",
+ "witness_proxy_set": "Setta il proxy",
+ "witness_proxy_clear": "Cancella il proxy",
+ "proxy_update_error": "Il tuo proxy non è aggiornato"
+ },
+ "votesandcomments_jsx": {
+ "no_responses_yet_click_to_respond":
+ "Non c'è ancora nessuna risposta. Clicca per rispondere.",
+ "response_count_tooltip": {
+ "zero": "Nessun commento. Clicca per commentare.",
+ "one": "1 commento. Clicca per commentare.",
+ "other": "%(count)s commenti. Clicca per commentare."
+ },
+ "vote_count": {
+ "zero": "Nessun voto",
+ "one": "1 voto",
+ "other": "%(count)s voti"
+ }
+ },
+ "userkeys_jsx": {
+ "public": "Pubblico",
+ "private": "Privato",
+ "public_something_key": "%(key)sChiave Pubblica",
+ "private_something_key": "%(key)sChiave Privata",
+ "posting_key_is_required_it_should_be_different":
+ "La chiave di pubblicazione si usa per pubblicare e votare. Dovrebbe essere diversa dalla chiave attiva e dalla chiave proprietaria. ",
+ "the_active_key_is_used_to_make_transfers_and_place_orders":
+ "La chiave attiva si usa per effettuare trasferimenti e per piazzare ordini nel market interno. ",
+ "the_owner_key_is_required_to_change_other_keys":
+ "La chiave proprietaria è la chiave principale dell'account e serve a cambiare le altre chiavi. ",
+ "the_private_key_or_password_should_be_kept_offline":
+ "Raccomandiamo di conservare offline la chiave privata e la password della chiave proprietaria. ",
+ "the_memo_key_is_used_to_create_and_read_memos":
+ "La chiave memo si usa per creare e leggere i memo. "
+ },
+ "suggestpassword_jsx": {
+ "APP_NAME_cannot_recover_passwords_keep_this_page_in_a_secure_location":
+ "%(APP_NAME)snon può recuperare la password. Conserva questa pagina in un luogo sicuro, come ad esempio una cassaforte o una cassetta di sicurezza. ",
+ "APP_NAME_password_backup": "Password Backup di %(APP_NAME)s",
+ "APP_NAME_password_backup_required":
+ "Password Backup di %(APP_NAME)s (richiesto)",
+ "after_printing_write_down_your_user_name":
+ "Dopo la stampa, scrivi il tuo nome utente. "
+ },
+ "converttosteem_jsx": {
+ "your_existing_DEBT_TOKEN_are_liquid_and_transferable":
+ "I tuoi %(DEBT_TOKEN)s sono liquidi e trasferibili. Invece se desiderassi scambiare %(DEBT_TOKEN)s direttamente in questo sito su %(link)s o trasferirli su un mercato esterno.",
+ "this_is_a_price_feed_conversion":
+ "Questa è una conversione di prezzo. L'attesa di 3,5 giorni è necessaria per evitare di abusare della media dei prezzi.",
+ "convert_to_LIQUID_TOKEN": "Converti in %(LIQUID_TOKEN)s",
+ "DEBT_TOKEN_will_be_unavailable":
+ "Questa azione avverrà tra 3,5 giorni da adesso e non può essere cancellata. Questi%(DEBT_TOKEN)s diverranno subito indisponibili"
+ },
+ "tips_js": {
+ "liquid_token":
+ "Token scambiabili che possono essere trasferiti ovunque in qualsiasi momento. %(LIQUID_TOKEN)s possono essere convertiti in %(VESTING_TOKEN)s con un processo chiamato powering up.",
+ "influence_token":
+ "Token che ti danno più controllo sui pagamenti dei post e ti consentono di guadagnare sulle ricompense da curatore.",
+ "estimated_value":
+ "Il valore stimato si basa sul valore medio di %(LIQUID_TOKEN)s in dollari US. ",
+ "non_transferable":
+ "%(VESTING_TOKEN)s non è trasferibile e richiede 3 mesi, (13 pagamenti) per riconvertirli in %(LIQUID_TOKEN)s.",
+ "converted_VESTING_TOKEN_can_be_sent_to_yourself_but_can_not_transfer_again":
+ "I %(VESTING_TOKEN)s convertiti possono essere spediti a te stesso o a qualcun altro ma non possono non ritrasferirli senza essere convertirli di nuovo in %(LIQUID_TOKEN)s.",
+ "part_of_your_steem_power_is_currently_delegated":
+ "Parte del tuo STEEM POWER ti è attualmente delegato. La delegazione è donata per l'influenza o per aiutare i nuovi utenti ad eseguire le azioni su steemit. Il quantitativo delegato può fluttuare."
+ },
+ "promote_post_jsx": {
+ "promote_post": "Promuovi post",
+ "spend_your_DEBT_TOKEN_to_advertise_this_post":
+ "Spendi %(DEBT_TOKEN)s per pubblicizzare questo post nella sezione dei contenuti promossi.",
+ "you_successfully_promoted_this_post":
+ "Hai promosso questo post con successo",
+ "this_post_was_hidden_due_to_low_ratings":
+ "Questo post è stato nascosto a causa della bassa reputazione"
+ },
+ "about_jsx": {
+ "about_app": "About %(APP_NAME)s",
+ "about_app_details":
+ "%(APP_NAME)s è una piattaforma di social media dove tutti vengono ricompensati per la creazione e la cura di contenuti. Utilizza un complesso sistema a punti digitali, chiamato Steem che possiede un valore effettivo per le ricompense digitali attraverso la scoperta dei prezzi di mercato e la liquidità. ",
+ "learn_more_at_app_url": "Scopri di più %(APP_URL)s",
+ "resources": "Risorse"
+ },
+ "markdownviewer_jsx": {
+ "images_were_hidden_due_to_low_ratings":
+ "Le immagini sono state nascoste a causa della bassa reputazione."
+ },
+ "postsummary_jsx": {
+ "resteemed": "condiviso",
+ "resteemed_by": "Condiviso da",
+ "reveal_it": "mostra",
+ "adjust_your": "sistema il tuo",
+ "display_preferences": "mostrare le tue preferenze",
+ "create_an_account": "creare un accout",
+ "to_save_your_preferences": "per salvare le tue preferenze"
+ },
+ "posts_index": {
+ "empty_feed_1": "Sembra che tu non stia ancora seguendo nessuno. ",
+ "empty_feed_2":
+ "Se hai da poco aggiunto nuovi utenti da seguire, quando ci saranno nuovi contenuti disponibili li vedrai nel tuo feed personalizzato.",
+ "empty_feed_3": "Esplora gli Articoli in Trending",
+ "empty_feed_4": "Leggi la Guida di Avvio Rapido",
+ "empty_feed_5": "Leggi le FAQ"
+ },
+ "transferhistoryrow_jsx": {
+ "to_savings": "ai risparmi",
+ "from_savings": "dai risparmi",
+ "cancel_transfer_from_savings":
+ "Cancella il trasferimento dai risparmi",
+ "stop_power_down": "Interrompi il Power Down",
+ "start_power_down_of": "Avvia il Power Down di",
+ "receive_interest_of": "Ricevi l'interesse di"
+ },
+ "savingswithdrawhistory_jsx": {
+ "cancel_this_withdraw_request":
+ "Cancellare questa richiesta di prelevamento?",
+ "pending_savings_withdrawals": "PRELIEVI DEI RISPARMI IN SOSPESO",
+ "withdraw": "Ritira %(amount)s",
+ "to": "a %(to)s",
+ "from_to": "da %(from)s a %(to)s"
+ },
+ "explorepost_jsx": {
+ "copied": "Copiato!",
+ "copy": "Copia",
+ "alternative_sources": "Fonti alternative"
+ },
+ "header_jsx": {
+ "home": "Home",
+ "create_a_post": "Crea un post",
+ "change_account_password": "Cambia la password dell'account",
+ "create_account": "Crea un account",
+ "stolen_account_recovery": "Recupero account rubato",
+ "people_following": "Persone che seguono",
+ "people_followed_by": "Persone seguite da ",
+ "curation_rewards_by": "Ricompense da curatore da",
+ "author_rewards_by": "Ricompense da autore da",
+ "replies_to": "Risposte a ",
+ "comments_by": "Commenti di"
+ },
+ "loginform_jsx": {
+ "you_need_a_private_password_or_key":
+ "Hai bisogno di una password privata o di una chiave (non di una chiave pubblica)",
+ "cryptography_test_failed": "Test di crittofrafia fallito",
+ "unable_to_log_you_in":
+ "Non è possibile effettuare il log in con questo browser.",
+ "the_latest_versions_of": "Le ultime versioni di ",
+ "are_well_tested_and_known_to_work_with":
+ "sono testate e conosciute per funzionare con %(APP_URL)s.",
+ "due_to_server_maintenance":
+ "A causa della manutenzione del server siamo in modalità sola lettura. Ci dispiace per l'inconveniente.",
+ "login_to_vote": "Effettua il login per votare ",
+ "login_to_post": "Effettua il login per postare",
+ "login_to_comment": "Effettua il login per commentare",
+ "posting": "Post",
+ "active_or_owner": "Attivo o proprietario",
+ "this_password_is_bound_to_your_account_owner_key":
+ "Questa password è collegata alla chiave proprietaria del tuo account e non può essere usata per effettuare il login su questo sito. ",
+ "however_you_can_use_it_to": "Nonostante questo, puoi usarla per",
+ "update_your_password": "aggiornare la tua password",
+ "to_obtain_a_more_secure_set_of_keys":
+ "per ottenere un set di chiavi più sicuro. ",
+ "this_password_is_bound_to_your_account_active_key":
+ "Questa password è collegata alla chiave attiva del tuo account e non può essere usata per effettuare il login su questa pagina. ",
+ "you_may_use_this_active_key_on_other_more":
+ "Puoi usare la chiave attiva su altre pagine di sicurezza come le pagine Wallet o Market. ",
+ "you_account_has_been_successfully_created":
+ "Il tuo account è stato creato con successo! ",
+ "you_account_has_been_successfully_recovered":
+ "Il tuo account è stato ripristinato con successo!",
+ "password_update_succes":
+ "La password dell'account %(accountName)s è stata aggiornata con successo",
+ "password_info":
+ "La password o la chiave privata è stata inserita erroneamente. C'è probabilmente un errore di battitura o un inserimento di dati errato. Suggerimento: Una password o una chiave privata generata da Steemit non conterrà mai i caratteri 0 (zero), O (o maiuscola), I (i maiuscola) e l (l minuscola).",
+ "enter_your_username": "Inserisci il tuo username",
+ "password_or_wif": "Password o WIF",
+ "this_operation_requires_your_key_or_master_password":
+ "Per eseguire l'operazione è necessaria la propria chiave %(authType)so Master password. ",
+ "keep_me_logged_in": "Voglio restare connesso",
+ "amazing_community": "una comunità incredibile",
+ "to_comment_and_reward_others": "per commentare e premiare gli altri. ",
+ "sign_up_get_steem": "Sign up. Get STEEM",
+ "signup_button": "Sign up now to earn ",
+ "signup_button_emphasis": "FREE STEEM!",
+ "returning_users": "Utenti di ritorno:",
+ "join_our": "Unisciti al nostro"
+ },
+ "chainvalidation_js": {
+ "account_name_should": "Il nome account",
+ "not_be_empty": "non deve essere vuoto.",
+ "be_longer": "essere più lungo.",
+ "be_shorter": "essere più corto.",
+ "each_account_segment_should": "Ogni segmento dell'account dovrebbe",
+ "start_with_a_letter": "iniziare con una lettera.",
+ "have_only_letters_digits_or_dashes":
+ "avere solo lettere, cifre o trattini.",
+ "have_only_one_dash_in_a_row": "avere solo un trattino per riga. ",
+ "end_with_a_letter_or_digit": "terminare con una lettera o una cifra.",
+ "verified_exchange_no_memo":
+ "Devi includere una memo per il trasferimento."
+ },
+ "settings_jsx": {
+ "invalid_url": "URL invalido",
+ "name_is_too_long": "Nome troppo lungo",
+ "name_must_not_begin_with": "Il nome non deve iniziare con @",
+ "about_is_too_long": "About troppo lungo ",
+ "location_is_too_long": "Luogo è troppo lungo",
+ "website_url_is_too_long": "L'url del sito è troppo lunga ",
+ "public_profile_settings": "Impostazioni profilo pubblico",
+ "preferences": "Impostazioni di Visualizzazione del Post Privato",
+ "not_safe_for_work_nsfw_content":
+ "Contenuto inappropriato da visualizzare da un luogo di lavoro (NSFW)",
+ "always_hide": "Nascondi sempre",
+ "always_warn": "Avverti sempre",
+ "always_show": "Mostra sempre",
+ "muted_users": "Utenti mutati",
+ "update": "Aggiornamento",
+ "profile_image_url": "Url immagine profilo",
+ "cover_image_url": "Url immagine di copertina",
+ "profile_name": "Mostra nome",
+ "profile_about": "About",
+ "profile_location": "Località",
+ "profile_website": "Sito"
+ },
+ "transfer_jsx": {
+ "amount_is_in_form": "La quantita deve essere della forma 99999.999",
+ "insufficient_funds": "Fondi insufficienti",
+ "use_only_3_digits_of_precison": "Usare solo 3 cifre di precisione",
+ "send_to_account": "Invia a un account",
+ "asset": "Asset",
+ "this_memo_is_private": "Questo memo è privato",
+ "this_memo_is_public": "Questo memo è pubblico",
+ "convert_to_VESTING_TOKEN": "Converti in %(VESTING_TOKEN)s",
+ "balance_subject_to_3_day_withdraw_waiting_period":
+ "Saldo soggetto a 3 giorni di attesa per il prelievo.",
+ "move_funds_to_another_account":
+ "Sposta i fondi verso un altro account %(APP_NAME)s",
+ "protect_funds_by_requiring_a_3_day_withdraw_waiting_period":
+ "Proteggi i fondi richiedendo un periodo di attesa di 3 giorni.",
+ "withdraw_funds_after_the_required_3_day_waiting_period":
+ "Preleva fondi dopo il periodo di attesa necessario di 3 giorni.",
+ "from": "Da",
+ "to": "A",
+ "asset_currently_collecting":
+ "%(asset)s attualmente percepiscono %(interest)s%% ISC.",
+ "beware_of_spam_and_phishing_links":
+ "Beware of spam and phishing links in transfer memos. Do not open links from users you do not trust. Do not provide your private keys to any third party websites."
+ },
+ "userwallet_jsx": {
+ "conversion_complete_tip": "Si completerà su",
+ "in_conversion": "%(amount)s in conversione",
+ "transfer_to_savings": "Sposta nei Risparmi",
+ "power_up": "Power Up",
+ "power_down": "Power Down",
+ "market": "Market",
+ "convert_to_LIQUID_TOKEN": "Converti in %(LIQUID_TOKEN)s",
+ "withdraw_LIQUID_TOKEN": "Preleva %(LIQUID_TOKEN)s",
+ "withdraw_DEBT_TOKENS": "Preleva %(DEBT_TOKENS)s",
+ "tokens_worth_about_1_of_LIQUID_TICKER":
+ "I token valgono circa $1.00 di %(LIQUID_TICKER)s, attualmente percepiscono %(sbdInterest)s%% ISC.",
+ "savings": "RISPARMI",
+ "estimated_account_value": "Valore stimato dell'account",
+ "next_power_down_is_scheduled_to_happen":
+ "Il prossimo power downo è programmato per avvenire",
+ "transfers_are_temporary_disabled":
+ "I trasferimenti sono temporaneamente disabilitati.",
+ "history": "CRONOLOGIA",
+ "redeem_rewards": "Riscuoti le ricompense (Trasferisci sul conto)",
+ "buy_steem_or_steem_power": "Compra STEEM o STEEM POWER"
+ },
+ "powerdown_jsx": {
+ "power_down": "Power Down",
+ "amount": "Somma",
+ "already_power_down":
+ "Stai già effettuando il powering down %(AMOUNT)s %(LIQUID_TICKER)s (%(WITHDRAWN)s %(LIQUID_TICKER)s pagati sin ora). Ricorda che se cambi l'ammontare del power down il pagamento programmato verrà resettato.",
+ "delegating":
+ "Stai delegando %(AMOUNT)s %(LIQUID_TICKER)s. Questa somma sarà bloccata e non disponibile per il power down sino a quando la delega non sarà rimossa e non sia passato un intero intervallo di ricompensa.",
+ "per_week": "È ~%(AMOUNT)s %(LIQUID_TICKER)s a settimana.",
+ "warning":
+ "Lasciare meno di %(AMOUNT)s %(VESTING_TOKEN)s sul tuo account è sconsigliato e potrebbe renderlo inutilizzabile.",
+ "error": "Impossibile effettuare il power down (ERROR: %(MESSAGE)s)"
+ },
+ "checkloginowner_jsx": {
+ "your_password_permissions_were_reduced":
+ "I tuoi permessi delle password sono stati ridotti",
+ "if_you_did_not_make_this_change":
+ "Se non hai fatto questo cambio per favore",
+ "ownership_changed_on": "Proprietà Cambiata Su",
+ "deadline_for_recovery_is": "Il termine per il ripristino è",
+ "i_understand_dont_show_again": "Ho capito, non mostrare nuovamente"
}
- },
- "userkeys_jsx": {
- "public": "Pubblico",
- "private": "Privato",
- "public_something_key": "%(key)sChiave Pubblica",
- "private_something_key": "%(key)sChiave Privata",
- "posting_key_is_required_it_should_be_different": "La chiave di pubblicazione si usa per pubblicare e votare. Dovrebbe essere diversa dalla chiave attiva e dalla chiave proprietaria. ",
- "the_active_key_is_used_to_make_transfers_and_place_orders": "La chiave attiva si usa per effettuare trasferimenti e per piazzare ordini nel market interno. ",
- "the_owner_key_is_required_to_change_other_keys": "La chiave proprietaria è la chiave principale dell'account e serve a cambiare le altre chiavi. ",
- "the_private_key_or_password_should_be_kept_offline": "Raccomandiamo di conservare offline la chiave privata e la password della chiave proprietaria. ",
- "the_memo_key_is_used_to_create_and_read_memos": "La chiave memo si usa per creare e leggere i memo. "
- },
- "suggestpassword_jsx": {
- "APP_NAME_cannot_recover_passwords_keep_this_page_in_a_secure_location": "%(APP_NAME)snon può recuperare la password. Conserva questa pagina in un luogo sicuro, come ad esempio una cassaforte o una cassetta di sicurezza. ",
- "APP_NAME_password_backup": "Password Backup di %(APP_NAME)s",
- "APP_NAME_password_backup_required": "Password Backup di %(APP_NAME)s (richiesto)",
- "after_printing_write_down_your_user_name": "Dopo la stampa, scrivi il tuo nome utente. "
- },
- "converttosteem_jsx": {
- "your_existing_DEBT_TOKEN_are_liquid_and_transferable": "I tuoi %(DEBT_TOKEN)s sono liquidi e trasferibili. Invece se desiderassi scambiare %(DEBT_TOKEN)s direttamente in questo sito su %(link)s o trasferirli su un mercato esterno.",
- "this_is_a_price_feed_conversion": "Questa è una conversione di prezzo. L'attesa di 3,5 giorni è necessaria per evitare di abusare della media dei prezzi.",
- "convert_to_LIQUID_TOKEN": "Converti in %(LIQUID_TOKEN)s",
- "DEBT_TOKEN_will_be_unavailable": "Questa azione avverrà tra 3,5 giorni da adesso e non può essere cancellata. Questi%(DEBT_TOKEN)s diverranno subito indisponibili"
- },
- "tips_js": {
- "liquid_token": "Token scambiabili che possono essere trasferiti ovunque in qualsiasi momento. %(LIQUID_TOKEN)s possono essere convertiti in %(VESTING_TOKEN)s con un processo chiamato powering up.",
- "influence_token": "Token che ti danno più controllo sui pagamenti dei post e ti consentono di guadagnare sulle ricompense da curatore.",
- "estimated_value": "Il valore stimato si basa sul valore medio di %(LIQUID_TOKEN)s in dollari US. ",
- "non_transferable": "%(VESTING_TOKEN)s non è trasferibile e richiede 3 mesi, (13 pagamenti) per riconvertirli in %(LIQUID_TOKEN)s.",
- "converted_VESTING_TOKEN_can_be_sent_to_yourself_but_can_not_transfer_again": "I %(VESTING_TOKEN)s convertiti possono essere spediti a te stesso o a qualcun altro ma non possono non ritrasferirli senza essere convertirli di nuovo in %(LIQUID_TOKEN)s.",
- "part_of_your_steem_power_is_currently_delegated": "Parte del tuo STEEM POWER ti è attualmente delegato. La delegazione è donata per l'influenza o per aiutare i nuovi utenti ad eseguire le azioni su steemit. Il quantitativo delegato può fluttuare."
- },
- "promote_post_jsx": {
- "promote_post": "Promuovi post",
- "spend_your_DEBT_TOKEN_to_advertise_this_post": "Spendi %(DEBT_TOKEN)s per pubblicizzare questo post nella sezione dei contenuti promossi.",
- "you_successfully_promoted_this_post": "Hai promosso questo post con successo",
- "this_post_was_hidden_due_to_low_ratings": "Questo post è stato nascosto a causa della bassa reputazione"
- },
- "about_jsx": {
- "about_app": "About %(APP_NAME)s",
- "about_app_details": "%(APP_NAME)s è una piattaforma di social media dove tutti vengono ricompensati per la creazione e la cura di contenuti. Utilizza un complesso sistema a punti digitali, chiamato Steem che possiede un valore effettivo per le ricompense digitali attraverso la scoperta dei prezzi di mercato e la liquidità. ",
- "learn_more_at_app_url": "Scopri di più %(APP_URL)s",
- "resources": "Risorse"
- },
- "markdownviewer_jsx": {
- "images_were_hidden_due_to_low_ratings": "Le immagini sono state nascoste a causa della bassa reputazione."
- },
- "postsummary_jsx": {
- "resteemed": "condiviso",
- "resteemed_by": "Condiviso da",
- "reveal_it": "mostra",
- "adjust_your": "sistema il tuo",
- "display_preferences": "mostrare le tue preferenze",
- "create_an_account": "creare un accout",
- "to_save_your_preferences": "per salvare le tue preferenze"
- },
- "posts_index": {
- "empty_feed_1": "Sembra che tu non stia ancora seguendo nessuno. ",
- "empty_feed_2": "Se hai da poco aggiunto nuovi utenti da seguire, quando ci saranno nuovi contenuti disponibili li vedrai nel tuo feed personalizzato.",
- "empty_feed_3": "Esplora gli Articoli in Trending",
- "empty_feed_4": "Leggi la Guida di Avvio Rapido",
- "empty_feed_5": "Leggi le FAQ"
- },
- "transferhistoryrow_jsx": {
- "to_savings": "ai risparmi",
- "from_savings": "dai risparmi",
- "cancel_transfer_from_savings": "Cancella il trasferimento dai risparmi",
- "stop_power_down": "Interrompi il Power Down",
- "start_power_down_of": "Avvia il Power Down di",
- "receive_interest_of": "Ricevi l'interesse di"
- },
- "savingswithdrawhistory_jsx": {
- "cancel_this_withdraw_request": "Cancellare questa richiesta di prelevamento?",
- "pending_savings_withdrawals": "PRELIEVI DEI RISPARMI IN SOSPESO",
- "withdraw": "Ritira %(amount)s",
- "to": "a %(to)s",
- "from_to": "da %(from)s a %(to)s"
- },
- "explorepost_jsx": {
- "copied": "Copiato!",
- "copy": "Copia",
- "alternative_sources": "Fonti alternative"
- },
- "header_jsx": {
- "home": "Home",
- "create_a_post": "Crea un post",
- "change_account_password": "Cambia la password dell'account",
- "create_account": "Crea un account",
- "stolen_account_recovery": "Recupero account rubato",
- "people_following": "Persone che seguono",
- "people_followed_by": "Persone seguite da ",
- "curation_rewards_by": "Ricompense da curatore da",
- "author_rewards_by": "Ricompense da autore da",
- "replies_to": "Risposte a ",
- "comments_by": "Commenti di"
- },
- "loginform_jsx": {
- "you_need_a_private_password_or_key": "Hai bisogno di una password privata o di una chiave (non di una chiave pubblica)",
- "cryptography_test_failed": "Test di crittofrafia fallito",
- "unable_to_log_you_in": "Non è possibile effettuare il log in con questo browser.",
- "the_latest_versions_of": "Le ultime versioni di ",
- "are_well_tested_and_known_to_work_with": "sono testate e conosciute per funzionare con %(APP_URL)s.",
- "due_to_server_maintenance": "A causa della manutenzione del server siamo in modalità sola lettura. Ci dispiace per l'inconveniente.",
- "login_to_vote": "Effettua il login per votare ",
- "login_to_post": "Effettua il login per postare",
- "login_to_comment": "Effettua il login per commentare",
- "posting": "Post",
- "active_or_owner": "Attivo o proprietario",
- "this_password_is_bound_to_your_account_owner_key": "Questa password è collegata alla chiave proprietaria del tuo account e non può essere usata per effettuare il login su questo sito. ",
- "however_you_can_use_it_to": "Nonostante questo, puoi usarla per",
- "update_your_password": "aggiornare la tua password",
- "to_obtain_a_more_secure_set_of_keys": "per ottenere un set di chiavi più sicuro. ",
- "this_password_is_bound_to_your_account_active_key": "Questa password è collegata alla chiave attiva del tuo account e non può essere usata per effettuare il login su questa pagina. ",
- "you_may_use_this_active_key_on_other_more": "Puoi usare la chiave attiva su altre pagine di sicurezza come le pagine Wallet o Market. ",
- "you_account_has_been_successfully_created": "Il tuo account è stato creato con successo! ",
- "you_account_has_been_successfully_recovered": "Il tuo account è stato ripristinato con successo!",
- "password_update_succes": "La password dell'account %(accountName)s è stata aggiornata con successo",
- "password_info": "La password o la chiave privata è stata inserita erroneamente. C'è probabilmente un errore di battitura o un inserimento di dati errato. Suggerimento: Una password o una chiave privata generata da Steemit non conterrà mai i caratteri 0 (zero), O (o maiuscola), I (i maiuscola) e l (l minuscola).",
- "enter_your_username": "Inserisci il tuo username",
- "password_or_wif": "Password o WIF",
- "this_operation_requires_your_key_or_master_password": "Per eseguire l'operazione è necessaria la propria chiave %(authType)so Master password. ",
- "keep_me_logged_in": "Voglio restare connesso",
- "amazing_community": "una comunità incredibile",
- "to_comment_and_reward_others": "per commentare e premiare gli altri. ",
- "sign_up_get_steem": "Sign up. Get STEEM",
- "signup_button": "Sign up now to earn ",
- "signup_button_emphasis": "FREE STEEM!",
- "returning_users": "Utenti di ritorno:",
- "join_our": "Unisciti al nostro"
- },
- "chainvalidation_js": {
- "account_name_should": "Il nome account",
- "not_be_empty": "non deve essere vuoto.",
- "be_longer": "essere più lungo.",
- "be_shorter": "essere più corto.",
- "each_account_segment_should": "Ogni segmento dell'account dovrebbe",
- "start_with_a_letter": "iniziare con una lettera.",
- "have_only_letters_digits_or_dashes": "avere solo lettere, cifre o trattini.",
- "have_only_one_dash_in_a_row": "avere solo un trattino per riga. ",
- "end_with_a_letter_or_digit": "terminare con una lettera o una cifra.",
- "verified_exchange_no_memo": "Devi includere una memo per il trasferimento."
- },
- "settings_jsx": {
- "invalid_url": "URL invalido",
- "name_is_too_long": "Nome troppo lungo",
- "name_must_not_begin_with": "Il nome non deve iniziare con @",
- "about_is_too_long": "About troppo lungo ",
- "location_is_too_long": "Luogo è troppo lungo",
- "website_url_is_too_long": "L'url del sito è troppo lunga ",
- "public_profile_settings": "Impostazioni profilo pubblico",
- "private_post_display_settings": "Impostazioni di Visualizzazione del Post Privato",
- "not_safe_for_work_nsfw_content": "Contenuto inappropriato da visualizzare da un luogo di lavoro (NSFW)",
- "always_hide": "Nascondi sempre",
- "always_warn": "Avverti sempre",
- "always_show": "Mostra sempre",
- "muted_users": "Utenti mutati",
- "update": "Aggiornamento",
- "profile_image_url": "Url immagine profilo",
- "cover_image_url": "Url immagine di copertina",
- "profile_name": "Mostra nome",
- "profile_about": "About",
- "profile_location": "Località",
- "profile_website": "Sito"
- },
- "transfer_jsx": {
- "amount_is_in_form": "La quantita deve essere della forma 99999.999",
- "insufficient_funds": "Fondi insufficienti",
- "use_only_3_digits_of_precison": "Usare solo 3 cifre di precisione",
- "send_to_account": "Invia a un account",
- "asset": "Asset",
- "this_memo_is_private": "Questo memo è privato",
- "this_memo_is_public": "Questo memo è pubblico",
- "convert_to_VESTING_TOKEN": "Converti in %(VESTING_TOKEN)s",
- "balance_subject_to_3_day_withdraw_waiting_period": "Saldo soggetto a 3 giorni di attesa per il prelievo.",
- "move_funds_to_another_account": "Sposta i fondi verso un altro account %(APP_NAME)s",
- "protect_funds_by_requiring_a_3_day_withdraw_waiting_period": "Proteggi i fondi richiedendo un periodo di attesa di 3 giorni.",
- "withdraw_funds_after_the_required_3_day_waiting_period": "Preleva fondi dopo il periodo di attesa necessario di 3 giorni.",
- "from": "Da",
- "to": "A",
- "asset_currently_collecting": "%(asset)s attualmente percepiscono %(interest)s%% ISC.",
- "beware_of_spam_and_phishing_links": "Beware of spam and phishing links in transfer memos. Do not open links from users you do not trust. Do not provide your private keys to any third party websites."
- },
- "userwallet_jsx": {
- "conversion_complete_tip": "Si completerà su",
- "in_conversion": "%(amount)s in conversione",
- "transfer_to_savings": "Sposta nei Risparmi",
- "power_up": "Power Up",
- "power_down": "Power Down",
- "market": "Market",
- "convert_to_LIQUID_TOKEN": "Converti in %(LIQUID_TOKEN)s",
- "withdraw_LIQUID_TOKEN": "Preleva %(LIQUID_TOKEN)s",
- "withdraw_DEBT_TOKENS": "Preleva %(DEBT_TOKENS)s",
- "tokens_worth_about_1_of_LIQUID_TICKER": "I token valgono circa $1.00 di %(LIQUID_TICKER)s, attualmente percepiscono %(sbdInterest)s%% ISC.",
- "savings": "RISPARMI",
- "estimated_account_value": "Valore stimato dell'account",
- "next_power_down_is_scheduled_to_happen": "Il prossimo power downo è programmato per avvenire",
- "transfers_are_temporary_disabled": "I trasferimenti sono temporaneamente disabilitati.",
- "history": "CRONOLOGIA",
- "redeem_rewards": "Riscuoti le ricompense (Trasferisci sul conto)",
- "buy_steem_or_steem_power": "Compra STEEM o STEEM POWER"
- },
- "powerdown_jsx": {
- "power_down": "Power Down",
- "amount": "Somma",
- "already_power_down": "Stai già effettuando il powering down %(AMOUNT)s %(LIQUID_TICKER)s (%(WITHDRAWN)s %(LIQUID_TICKER)s pagati sin ora). Ricorda che se cambi l'ammontare del power down il pagamento programmato verrà resettato.",
- "delegating": "Stai delegando %(AMOUNT)s %(LIQUID_TICKER)s. Questa somma sarà bloccata e non disponibile per il power down sino a quando la delega non sarà rimossa e non sia passato un intero intervallo di ricompensa.",
- "per_week": "È ~%(AMOUNT)s %(LIQUID_TICKER)s a settimana.",
- "warning": "Lasciare meno di %(AMOUNT)s %(VESTING_TOKEN)s sul tuo account è sconsigliato e potrebbe renderlo inutilizzabile.",
- "error": "Impossibile effettuare il power down (ERROR: %(MESSAGE)s)"
- },
- "checkloginowner_jsx": {
- "your_password_permissions_were_reduced": "I tuoi permessi delle password sono stati ridotti",
- "if_you_did_not_make_this_change": "Se non hai fatto questo cambio per favore",
- "ownership_changed_on": "Proprietà Cambiata Su",
- "deadline_for_recovery_is": "Il termine per il ripristino è",
- "i_understand_dont_show_again": "Ho capito, non mostrare nuovamente"
- }
}
diff --git a/src/app/locales/ko.json b/src/app/locales/ko.json
new file mode 100644
index 0000000000000000000000000000000000000000..15022f09edf918329a3eedb3643e68b412bbf9fb
--- /dev/null
+++ b/src/app/locales/ko.json
@@ -0,0 +1,771 @@
+{
+ "g": {
+ "age": "시간",
+ "amount": "양",
+ "and": "and",
+ "are_you_sure": "Are you sure?",
+ "ask": "Ask",
+ "balance": "잔고",
+ "balances": "잔고",
+ "bid": "Bid",
+ "blog": "블로그",
+ "browse": "Browse",
+ "buy": "구매",
+ "buy_or_sell": "구입/판매",
+ "by": "by",
+ "cancel": "취소",
+ "change_password": "비밀번호 변경",
+ "choose_language": "언어 선택",
+ "clear": "지우기",
+ "close": "닫기",
+ "collapse_or_expand": "닫기/펼치기",
+ "comments": "작성한 댓글",
+ "confirm": "확인",
+ "convert": "변환하기",
+ "date": "날짜",
+ "delete": "삭제",
+ "dismiss": "확인",
+ "edit": "수정",
+ "email": "Email",
+ "feed": "피드",
+ "follow": "팔로우",
+ "for": " for ",
+ "from": " from ",
+ "go_back": "Back",
+ "hide": "숨기기",
+ "in": "in",
+ "in_reply_to": "in reply to",
+ "insufficient_balance": "잔고 부족",
+ "invalid_amount": "잘못된 금액",
+ "joined": "가입일",
+ "loading": "로딩중..",
+ "login": "로그인",
+ "logout": "로그아웃",
+ "memo": "메모",
+ "mute": "차단",
+ "myblog": "내 블로그",
+ "mycomments": "내가 쓴 댓글",
+ "myreplies": "받은 댓글",
+ "new": "최신글",
+ "newer": "최근",
+ "next": "다음",
+ "no": "No",
+ "ok": "Ok",
+ "older": "이전",
+ "or": "or",
+ "order_placed": "주문 요청됨",
+ "password": "비밀번호",
+ "payouts": "글보상",
+ "permissions": "권한",
+ "phishy_message":
+ "Link expanded to plain text; beware of a potential phishing attempt",
+ "post": "글쓰기",
+ "post_as": "Post as",
+ "posts": "Posts",
+ "powered_up_100": "Powered Up 100%%",
+ "preview": "Preview",
+ "previous": "Previous",
+ "price": "가격",
+ "print": "출력",
+ "promote": "홍보",
+ "promoted": "홍보글",
+ "re": "RE",
+ "re_to": "RE: %(topic)s",
+ "recent_password": "Recent Password",
+ "receive": "Receive ",
+ "remove": "Remove",
+ "remove_vote": "보팅 취소",
+ "replied_to": "replied to %(account)s",
+ "replies": "받은 댓글",
+ "reply": "댓글 달기",
+ "reply_count": {
+ "zero": "댓글 없음",
+ "one": "하나의 댓글",
+ "other": "%(count)개의 댓글"
+ },
+ "reputation": "평판",
+ "reveal_comment": "댓글 보이기",
+ "request": "request",
+ "required": "Required",
+ "rewards": "보상",
+ "save": "Save",
+ "saved": "Saved",
+ "search": "Search",
+ "sell": "판매",
+ "settings": "설정",
+ "share_this_post": "이 포스트 공유하기",
+ "show": "Show",
+ "sign_in": "로그인",
+ "sign_up": "회원가입",
+ "since": "since",
+ "submit": "Submit",
+ "power_up": "파워 업",
+ "submit_a_story": "글쓰기",
+ "tag": "태그",
+ "to": " to ",
+ "topics": "Topics",
+ "toggle_nightmode": "야간모드",
+ "all_tags": "전체 태그",
+ "transfer": "송금 ",
+ "trending_topics": "Trending Topics",
+ "type": "Type",
+ "unfollow": "언팔로우",
+ "unmute": "차단 해제",
+ "unknown": "Unknown",
+ "upvote": "보팅",
+ "upvote_post": "이 글에 보팅하기",
+ "username": "사용자 이름",
+ "version": "버전",
+ "vote": "보팅",
+ "votes": "보팅",
+ "wallet": "지갑",
+ "warning": "경고",
+ "yes": "예",
+ "posting": "포스팅",
+ "owner": "소유자",
+ "active": "액티브",
+ "account_not_found": "계정을 찾을 수 없습니다",
+ "this_is_wrong_password": "잘못된 비밀번호 입니다",
+ "do_you_need_to": "Do you need to",
+ "account_name": "계정 이름",
+ "recover_your_account": "recover your account",
+ "reset_usernames_password": "Reset %(username)s's Password",
+ "this_will_update_usernames_authtype_key":
+ "This will update %(username)s %(authType)s key",
+ "passwords_do_not_match": "Passwords do not match",
+ "you_need_private_password_or_key_not_a_public_key":
+ "You need a private password or key (not a public key)",
+ "the_rules_of_APP_NAME": {
+ "one": "%(APP_NAME)s 첫번째 규칙: 비밀번호를 잃어버리지 마세요.",
+ "second": "%(APP_NAME)s 두번째 규칙: 비밀번호를 잃어버리지 마세요.",
+ "third":
+ "%(APP_NAME)s 세번째 규칙: 잃어버린 비밀번호는 복구 해드릴 방법이 없습니다.",
+ "fourth":
+ "네번째 규칙: 기억할수 있는 비밀번호는 안전하지 않은 비밀번호 입니다.",
+ "fifth": "다섯번째 규칙: 무작위로 생성된 비밀번호만 사용하세요.",
+ "sixth": "여섯번째 규칙: 비밀번호는 혼자만 간직하세요.",
+ "seventh": "일곱번째 규칙: 비밀번호를 반드시 백업해 두세요."
+ },
+ "recover_password": "계정 복구",
+ "current_password": "현재 비밀번호",
+ "generated_password": "생성된 비밀번호",
+ "backup_password_by_storing_it":
+ "패스워드는 반드시 관리 프로그램이나 메모장 등을 이용해서 보관하세요.",
+ "enter_account_show_password":
+ "Enter a valid account name to show the password",
+ "click_to_generate_password": "새 비밀번호를 만드시려면 클릭하세요",
+ "re_enter_generate_password": "위에 생성된 비밀번호를 다시 입력하세요",
+ "understand_that_APP_NAME_cannot_recover_password":
+ "비밀번호를 잃어버리면 %(APP_NAME)s이 복구해줄 수 없음을 숙지하였습니다.",
+ "i_saved_password": "안전한 곳에 비밀번호를 백업 해 두었습니다.",
+ "update_password": "새 비밀번호 적용",
+ "confirm_password": "비밀번호 확인",
+ "account_updated": "변경 사항이 적용 되었습니다.",
+ "password_must_be_characters_or_more":
+ "패스워드는 %(amount)s 글자 이상 이어야 합니다.",
+ "need_password_or_key":
+ "개인 암호 또는 키 (공개 키 아님)가 필요합니다.",
+ "login_to_see_memo": "login to see memo",
+ "new_password": "새 비밀번호",
+ "incorrect_password": "잘못된 비밀번호",
+ "username_does_not_exist": "존재하지 않는 사용자 계정",
+ "account_name_should_start_with_a_letter":
+ "계정명은 반드시 알파벳으로 시작해야 합니다.",
+ "account_name_should_be_shorter": "계정명이 너무 깁니다.",
+ "account_name_should_be_longer": "계정명이 너무 짧습니다.",
+ "account_name_should_have_only_letters_digits_or_dashes":
+ "계정명에는 알파벳과 숫자, 마침표, 대쉬만 사용 가능합니다.",
+ "cannot_increase_reward_of_post_within_the_last_minute_before_payout":
+ "Payout 전 마지막 순간에 게시물에 대한 보상을 늘릴 수 없습니다.",
+ "vote_currently_exists_user_must_be_indicate_a_to_reject_witness":
+ "vote currently exists, user must be indicate a desire to reject witness",
+ "only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes":
+ "매 10 분마다 IP 주소 당 단 하나의 Steem 계정만 허용됩니다.",
+ "resteem_this_post": "Resteem This Post",
+ "reblog": "리스팀",
+ "write_your_story": "내용을 입력하세요",
+ "remember_voting_and_posting_key": "Remember voting & posting key",
+ "auto_login_question_mark": "자동 로그인",
+ "hide_private_key": "개인 키 숨기기",
+ "show_private_key": "개인 키 보이기",
+ "login_to_show": "로그인 해 확인하기",
+ "not_valid_email": "유효하지 않은 이메일",
+ "thank_you_for_being_an_early_visitor_to_APP_NAME":
+ "Thank you for being an early visitor to %(APP_NAME)s. We will get back to you at the earliest possible opportunity.",
+ "author_rewards": "저자 보상",
+ "curation_rewards": "큐레이션 보상",
+ "sorry_your_reddit_account_doesnt_have_enough_karma":
+ "Sorry, your Reddit account doesn't have enough Reddit Karma to qualify for a free sign up. Please add your email for a place on the waiting list",
+ "register_with_facebook": "Register with Facebook",
+ "or_click_the_button_below_to_register_with_facebook":
+ "Or click the button below to register with Facebook",
+ "server_returned_error": "서버 오류",
+ "APP_NAME_support": "%(APP_NAME)s Support",
+ "please_email_questions_to": "Please email your questions to",
+ "next_7_strings_single_block": {
+ "authors_get_paid_when_people_like_you_upvote_their_post":
+ "보팅을 통해 작가들에게 금전적인 지원을 하실 수 있습니다.",
+ "if_you_enjoyed_what_you_read_earn_amount":
+ "즐겁게 읽으셨다면 여러분도 지금 바로 가입하셔서 가상화폐 STEEM 을 보상으로 받으세요!",
+ "free_steem": "FREE STEEM!",
+ "sign_up_earn_steem": "Sign up now to earn "
+ },
+ "next_3_strings_together": {
+ "show_more": "Show more",
+ "show_less": "Show fewer",
+ "value_posts": "low value posts"
+ },
+ "read_only_mode":
+ "서버 점검으로 인한 읽기 전용 모드입니다. 불편함을 드려 죄송합니다.",
+ "tags_and_topics": "태그",
+ "show_more_topics": "모든 태그 보기",
+ "basic": "Basic",
+ "advanced": "Advanced",
+ "views": {
+ "zero": "읽지 않음",
+ "one": "%(count)s명이 잃음",
+ "other": "%(count)s명이 읽음"
+ },
+ "responses": {
+ "zero": "댓글 없음",
+ "one": "%(count)s개의 댓글",
+ "other": "%(count)s개의 댓글"
+ },
+ "post_key_warning": {
+ "confirm":
+ "STEEM 개인 키 또는 마스터 비밀번호를 게시하려고 합니다. 관련된 계정과 모든 자산에 대한 제어권을 상실하게 될 것입니다.",
+ "warning":
+ "Steemit Inc.의 직원을 포함한 합법적 인 사용자는 어떠한 경우에도 개인 키 또는 마스터 비밀번호를 요구하지 않습니다.",
+ "checkbox": "네 이해합니다."
+ }
+ },
+ "navigation": {
+ "about": "스팀이란?",
+ "explore": "태그별 현황",
+ "APP_NAME_whitepaper": "%(APP_NAME)s 백서",
+ "buy_LIQUID_TOKEN": "%(LIQUID_TOKEN)s 구매",
+ "sell_LIQUID_TOKEN": "%(LIQUID_TOKEN)s 판매",
+ "currency_market": "거래소",
+ "stolen_account_recovery": "도난 계정 복구",
+ "change_account_password": "비밀번호 변경",
+ "witnesses": "증인",
+ "vote_for_witnesses": "증인 투표",
+ "privacy_policy": "개인정보 방침",
+ "terms_of_service": "이용 약관",
+ "sign_up": "가입",
+ "learn_more": "더 알아보기",
+ "welcome": "환영합니다!",
+ "faq": "자주 묻는 질문",
+ "shop": "스팀잇 스토어",
+ "chat": "스팀잇 채팅",
+ "app_center": "스팀잇 앱 센터",
+ "api_docs": "스팀잇 API 문서",
+ "bluepaper": "스팀 블루페이퍼",
+ "smt_whitepaper": "SMT 화이트페이퍼",
+ "whitepaper": "스팀 화이트페이퍼",
+ "intro_tagline": "생각의 가치",
+ "intro_paragraph":
+ "당신의 생각과 글은 소중합니다. 스팀잇은 고급 컨텐츠 생산자들과 큐레이터들에게 투명한 금전적 보상을 지원합니다. 지금 참여하세요."
+ },
+ "main_menu": {
+ "hot": "인기글",
+ "trending": "대세글"
+ },
+ "reply_editor": {
+ "shorten_title": "짧은 제목",
+ "exceeds_maximum_length": "최대 용량 초과 (%(maxKb)sKB)",
+ "including_the_category": " ('%(rootCategory)s' 포함)",
+ "use_limited_amount_of_tags":
+ "You have %(tagsLength)s tags total%(includingCategory)s. Please use only 5 in your post and category line.",
+ "are_you_sure_you_want_to_clear_this_form":
+ "Are you sure you want to clear this form?",
+ "uploading": "Uploading",
+ "draft_saved": "임시 저장.",
+ "editor": "에디터",
+ "insert_images_by_dragging_dropping":
+ "이미지를 추가하시려면 마우스로 끌어다가 놓으시거나, ",
+ "pasting_from_the_clipboard": "클립보드에서 붙여넣기 하시거나, ",
+ "selecting_them": "직접 업로드 하세요",
+ "image_upload": "사진 업로드",
+ "power_up_100": "100%% 스팀파워로 수령",
+ "default_50_50": "스팀파워 50%% + 스팀달러 50%%",
+ "decline_payout": "보상 받지않기",
+ "check_this_to_auto_upvote_your_post": "이 글에 자동으로 업보팅",
+ "markdown_styling_guide": "Markdown 설명서",
+ "or_by": "혹은",
+ "title": "제목",
+ "update_post": "저장",
+ "markdown_not_supported": "Markdown은 지원되지 않습니다."
+ },
+ "category_selector_jsx": {
+ "tag_your_story":
+ "태그는 최대 5개까지 입력 할 수 있습니다. 메인이 될 태그는 가장 먼저 입력하세요.",
+ "select_a_tag": "태그를 선택하세요.",
+ "maximum_tag_length_is_24_characters": "태그는 24 글자까지 가능합니다.",
+ "use_limited_amount_of_categories":
+ "태그는 최대 %(amount)s 개 까지 입력 가능합니다.",
+ "use_only_lowercase_letters": "소문자만 사용해 주세요.",
+ "use_one_dash": "대쉬는 한개만 사용 가능합니다.",
+ "use_spaces_to_separate_tags":
+ "태그와 태그 사이는 공백으로 구분 하세요.",
+ "use_only_allowed_characters":
+ "소문자, 숫자 그리고 대쉬만 사용 가능합니다.",
+ "must_start_with_a_letter": "태그는 반드시 문자로 시작해야 합니다.",
+ "must_end_with_a_letter_or_number":
+ "태그는 반드시 문자나 숫자로 끝나야 합니다."
+ },
+ "postfull_jsx": {
+ "this_post_is_not_available_due_to_a_copyright_claim":
+ "This post is not available due to a copyright claim.",
+ "share_on_facebook": "Facebook에 공유",
+ "share_on_twitter": "Twitter에 공유",
+ "share_on_linkedin": "Linkedin에 공유",
+ "recent_password": "최근 비밀번호",
+ "in_week_convert_DEBT_TOKEN_to_LIQUID_TOKEN":
+ "In 3.5 days, convert %(amount)s %(DEBT_TOKEN)s into %(LIQUID_TOKEN)s",
+ "view_the_full_context": "전체 글 보기",
+ "view_the_direct_parent": "상위 댓글 보기",
+ "you_are_viewing_a_single_comments_thread_from":
+ "You are viewing a single comment's thread from"
+ },
+ "market_jsx": {
+ "action": "Action",
+ "date_created": "주문 일시",
+ "last_price": "현재 가격",
+ "24h_volume": "거래량(24H)",
+ "spread": "매도/매수 갭",
+ "total": "SBD 계",
+ "available": "주문 가능 금액",
+ "lowest_ask": "매도 주문 최저가",
+ "highest_bid": "매수 주문 최고가",
+ "buy_orders": "매수 주문",
+ "sell_orders": "매도 주문",
+ "trade_history": "거래 이력",
+ "open_orders": "미체결 주문",
+ "sell_amount_for_atleast":
+ "%(min_to_receive)s을 %(amount_to_sell)s로 판매 하시겠습니까? (%(effectivePrice)s)",
+ "buy_atleast_amount_for":
+ "%(min_to_receive)s을 %(amount_to_sell)s로 구매 하시겠습니까? (%(effectivePrice)s)",
+ "price_warning_above":
+ "This price is well above the current market price of %(marketPrice)s, are you sure?",
+ "price_warning_below":
+ "This price is well below the current market price of %(marketPrice)s, are you sure?",
+ "order_cancel_confirm": "%(order_id)s 주문을 취소하시겠습니까?",
+ "order_cancelled": "%(order_id)s 주문이 취소되었습니다.",
+ "higher": "Higher",
+ "lower": "Lower",
+ "total_DEBT_TOKEN_SHORT_CURRENCY_SIGN":
+ "Total %(DEBT_TOKEN_SHORT)s (%(CURRENCY_SIGN)s)"
+ },
+ "recoveraccountstep1_jsx": {
+ "begin_recovery": "Begin Recovery",
+ "not_valid": "Not valid",
+ "account_name_is_not_found": "Account name is not found",
+ "unable_to_recover_account_not_change_ownership_recently":
+ "We are unable to recover this account, it has not changed ownership recently.",
+ "password_not_used_in_last_days":
+ "This password was not used on this account in the last 30 days.",
+ "request_already_submitted_contact_support":
+ "Your request has been already submitted and we are working on it. Please contact %(SUPPORT_EMAIL)s for the status of your request.",
+ "recover_account_intro":
+ "From time to time, a Steemian's owner key may be compromised. Stolen Account Recovery gives the rightful account owner 30 days to recover their account from the moment the thief changed their owner key. Stolen Account Recovery can only be used on %(APP_URL)s if the account owner had previously listed '%(APP_NAME)s' as their account trustee and complied with %(APP_NAME)s's Terms of Service.",
+ "login_with_facebook_or_reddit_media_to_verify_identity":
+ "Please login with Facebook or Reddit to verify your identity",
+ "login_with_social_media_to_verify_identity":
+ "Please login with %(provider)s to verify your identity",
+ "enter_email_toverify_identity":
+ "We need to verify your identity. Please enter your email address below to begin the verification.",
+ "continue_with_email": "Continue with Email",
+ "thanks_for_submitting_request_for_account_recovery":
+ "Thanks for submitting your request for Account Recovery using %(APP_NAME)s's blockchain-based multi factor authentication. We will respond to you as quickly as possible, however, please expect there may be some delay in response due to high volume of emails. Please be prepared to verify your identity.",
+ "recovering_account": "Recovering account",
+ "recover_account": "Recover Account",
+ "checking_account_owner": "Checking account owner",
+ "sending_recovery_request": "Sending recovery request",
+ "cant_confirm_account_ownership":
+ "We can't confirm account ownership. Check your password",
+ "account_recovery_request_not_confirmed":
+ "Account recovery request is not confirmed yet, please get back later, thank you for your patience."
+ },
+ "user_profile": {
+ "unknown_account": "Unknown Account",
+ "user_hasnt_made_any_posts_yet":
+ "%(name)s님은 아직 남긴 글이 없습니다.",
+ "user_hasnt_started_bloggin_yet":
+ "%(name)s님은 아직 블로깅을 시작하지 않았습니다.",
+ "user_hasnt_followed_anything_yet":
+ "Looks like %(name)s might not be following anyone yet! If %(name)s recently added new users to follow, their personalized feed will populate once new content is available.",
+ "user_hasnt_had_any_replies_yet": "%(name)s hasn't had any replies yet",
+ "looks_like_you_havent_posted_anything_yet":
+ "아직 포스팅을 하지 않았습니다.",
+ "create_a_post": "글쓰기",
+ "explore_trending_articles": "대세글 읽어보기",
+ "read_the_quick_start_guide": "빠른 시작 가이드",
+ "browse_the_faq": "자주 찾는 질문",
+ "followers": "팔로워",
+ "this_is_users_reputations_score_it_is_based_on_history_of_votes":
+ "이것은 %(name)s님의 평판 점수입니다.\n\n평판 점수는 %(name)s님이 받은 보팅 기록에 기반합니다. 이 평판 점수는 질이 나쁜 콘텐츠를 가려내기 위해 사용됩니다.",
+ "follower_count": {
+ "zero": "팔로워 없음",
+ "one": "한명의 팔로워",
+ "other": "%(count)s명의 팔로워"
+ },
+ "followed_count": {
+ "zero": "팔로우 없음",
+ "one": "한명 팔로우",
+ "other": "%(count)s명 팔로우"
+ },
+ "post_count": {
+ "zero": "게시글 없음",
+ "one": "하나의 게시글",
+ "other": "%(count)s 게시글"
+ }
+ },
+ "authorrewards_jsx": {
+ "estimated_author_rewards_last_week": "이번 주 예상 저자 보상금액",
+ "author_rewards_history": "저자 보상 내역"
+ },
+ "curationrewards_jsx": {
+ "estimated_curation_rewards_last_week": "이번주 예상 큐레이션 보상금액",
+ "curation_rewards_history": "큐레이션 보상 내역"
+ },
+ "post_jsx": {
+ "now_showing_comments_with_low_ratings":
+ "Now showing comments with low ratings",
+ "sort_order": "정렬 순서",
+ "comments_were_hidden_due_to_low_ratings":
+ "Comments were hidden due to low ratings"
+ },
+ "voting_jsx": {
+ "flagging_post_can_remove_rewards_the_flag_should_be_used_for_the_following":
+ "다운 보팅을 하시면 보상액을 없애고, 해당 게시물을 눈에 덜 띄게 만들 수 있습니다. 다운 보팅 사유는 다음과 같습니다.",
+ "disagreement_on_rewards": "동의할 수 없을 정도로 지나치게 많은 보상액",
+ "fraud_or_plagiarism": "사기 혹은 표절",
+ "hate_speech_or_internet_trolling":
+ "증오 및 혐오 발언, 악플과 비난 게시물",
+ "intentional_miss_categorized_content_or_spam":
+ "의도적인 태그 오용 혹은 스팸",
+ "pending_payout": "예상 보상금액: $%(value)s",
+ "payout_declined": "보상을 사양함",
+ "max_accepted_payout": "최대 허용 보상액 $%(value)s",
+ "promotion_cost": "홍보 비용 $%(value)s",
+ "past_payouts": "지급된 보상 $%(value)s",
+ "past_payouts_author": " - 저자 $%(value)s",
+ "past_payouts_curators": " - 큐레이터 $%(value)s",
+ "we_will_reset_curation_rewards_for_this_post":
+ "will reset your curation rewards for this post",
+ "removing_your_vote": "보팅 취소",
+ "changing_to_an_upvote": "Changing to an Up-Vote",
+ "changing_to_a_downvote": "Changing to a Down-Vote",
+ "confirm_flag": "Confirm Flag",
+ "and_more": "and %(count)s more",
+ "votes_plural": {
+ "one": "%(count)s 보팅",
+ "other": "%(count)s 보팅"
+ }
+ },
+ "witnesses_jsx": {
+ "witness_thread": "witness thread",
+ "top_witnesses": "증인 투표",
+ "you_have_votes_remaining": {
+ "zero": "더이상 투표 하실 수 없습니다.",
+ "one": "현재 1명에게 투표하실 수 있습니다.",
+ "other": "현재 %(count)s명에게 투표하실 수 있습니다."
+ },
+ "you_can_vote_for_maximum_of_witnesses":
+ "최대 30명에게 투표하실 수 있습니다.",
+ "witness": "증인",
+ "information": "Information",
+ "if_you_want_to_vote_outside_of_top_enter_account_name":
+ "상위 50위권 밖에 계신 분에게 증인 투표를 하시려면 아래 칸에 해당하는 분의 계정명을 입력하세요.",
+ "set_witness_proxy":
+ "You can also choose a proxy that will vote for witnesses for you. This will reset your current witness selection.",
+ "witness_set":
+ "이미 투표 위임 설정을 하셨습니다. 다시 증인 투표를 하시려면 위임을 철회하십시오.",
+ "witness_proxy_current": "당신의 투표 권한을 위임한 증인: ",
+ "witness_proxy_set": "위임 설정",
+ "witness_proxy_clear": "위임 철회",
+ "proxy_update_error": "Your proxy was not updated"
+ },
+ "votesandcomments_jsx": {
+ "no_responses_yet_click_to_respond":
+ "댓글이 없습니다. 댓글을 작성하시려면 클릭하세요.",
+ "response_count_tooltip": {
+ "zero": "댓글이 없습니다. 댓글을 작성하시려면 클릭하세요.",
+ "one": "한개의 댓글이 있습니다. 댓글을 작성하시려면 클릭하세요.",
+ "other":
+ "%(count)s개의 댓글이 있습니다. 댓글을 작성하시려면 클릭하세요."
+ },
+ "vote_count": {
+ "zero": "추천 없음",
+ "one": "1개의 추천",
+ "other": "%(count)s개의 추천"
+ }
+ },
+ "userkeys_jsx": {
+ "public": "공개",
+ "private": "개인",
+ "public_something_key": "공개 %(key)s 키",
+ "private_something_key": "개인 %(key)s 키",
+ "posting_key_is_required_it_should_be_different":
+ "포스팅 키는 새 글을 작성하거나 다른 회원의 글에 보팅할 때 필요합니다. 액티브 키나 오너 키와는 달라야 합니다.",
+ "the_active_key_is_used_to_make_transfers_and_place_orders":
+ "액티브 키는 스팀 달러나 스팀을 다른 이에게 전송하거나 내부 마켓에서 거래를 할 때 필요합니다.",
+ "the_owner_key_is_required_to_change_other_keys":
+ "오너 키는 계정의 마스터 키입니다. 다른 모든 키들을 바꿀 때 필요합니다.",
+ "the_private_key_or_password_should_be_kept_offline":
+ "개인 키와 오너 키의 비밀번호는 가능한 많이 오프라인에 저장해두세요.",
+ "the_memo_key_is_used_to_create_and_read_memos":
+ "메모 키는 사적인 메모를 작성하거나 읽을 때 필요합니다."
+ },
+ "suggestpassword_jsx": {
+ "APP_NAME_cannot_recover_passwords_keep_this_page_in_a_secure_location":
+ "%(APP_NAME)s cannot recover passwords. Keep this page in a secure location, such as a fireproof safe or safety deposit box.",
+ "APP_NAME_password_backup": "%(APP_NAME)s Password Backup",
+ "APP_NAME_password_backup_required":
+ "%(APP_NAME)s Password Backup (required)",
+ "after_printing_write_down_your_user_name":
+ "After printing, write down your user name"
+ },
+ "converttosteem_jsx": {
+ "your_existing_DEBT_TOKEN_are_liquid_and_transferable":
+ "Your existing %(DEBT_TOKEN)s are liquid and transferable. Instead you may wish to trade %(DEBT_TOKEN)s directly in this site under %(link)s or transfer to an external market.",
+ "this_is_a_price_feed_conversion":
+ "This is a price feed conversion. The 3.5 day delay is necessary to prevent abuse from gaming the price feed average",
+ "convert_to_LIQUID_TOKEN": "%(LIQUID_TOKEN)s 으로 전환",
+ "DEBT_TOKEN_will_be_unavailable":
+ "This action will take place 3.5 days from now and can not be canceled. These %(DEBT_TOKEN)s will immediately become unavailable"
+ },
+ "tips_js": {
+ "liquid_token":
+ "교환과 송금이 가능한 토큰입니다. 파워업을 통해 %(LIQUID_TOKEN)s을 %(VESTING_TOKEN)s으로 전환 하실 수 있습니다.",
+ "influence_token":
+ "스팀잇에서의 영향력을 나타냅니다. 스팀 파워가 높을수록 보팅 금액이 더 높아지고, 큐레이션 보상도 더 많이 받을 수 있습니다.",
+ "estimated_value":
+ "%(LIQUID_TOKEN)s의 평균 가격을 US달러로 환산한 기준입니다.",
+ "non_transferable":
+ "%(VESTING_TOKEN)s는 전송이 불가능하며, 다시 %(LIQUID_TOKEN)s으로 전환하기 위해서는 3달이 소요됩니다. (13회로 나누어 전환 됩니다)",
+ "converted_VESTING_TOKEN_can_be_sent_to_yourself_but_can_not_transfer_again":
+ "Converted %(VESTING_TOKEN)s can be sent to yourself or someone else but can not transfer again without converting back to %(LIQUID_TOKEN)s.",
+ "part_of_your_steem_power_is_currently_delegated":
+ "%(user_name)s 님은 STEEM POWER 를 임대 받고 있습니다. 임대 받는 양은 가입 시기에 따라 가변적입니다."
+ },
+ "promote_post_jsx": {
+ "promote_post": "Promote Post",
+ "spend_your_DEBT_TOKEN_to_advertise_this_post":
+ "%(DEBT_TOKEN)s를 지불하시면 '홍보글' 코너에 게시물이 올라갑니다.",
+ "you_successfully_promoted_this_post": "홍보 하였습니다.",
+ "this_post_was_hidden_due_to_low_ratings":
+ "다운보팅에 의해 블라인드 처리 되었습니다."
+ },
+ "about_jsx": {
+ "about_app": "About %(APP_NAME)s",
+ "about_app_details":
+ "%(APP_NAME)s is a social media platform where everyone gets paid for creating and curating content. It leverages a robust digital points system, called Steem, that supports real value for digital rewards through market price discovery and liquidity.",
+ "learn_more_at_app_url": "Learn more at %(APP_URL)s",
+ "resources": "Resources"
+ },
+ "markdownviewer_jsx": {
+ "images_were_hidden_due_to_low_ratings":
+ "Images were hidden due to low ratings."
+ },
+ "postsummary_jsx": {
+ "resteemed": "리스팀",
+ "resteemed_by": "리스팀 by",
+ "reveal_it": "Reveal this post",
+ "adjust_your": "adjust your",
+ "display_preferences": "display preferences",
+ "create_an_account": "create an account",
+ "to_save_your_preferences": "to save your preferences"
+ },
+ "posts_index": {
+ "empty_feed_1": "Looks like you haven't followed anything yet",
+ "empty_feed_2":
+ "If you recently added new users to follow, your personalized feed will populate once new content is available",
+ "empty_feed_3": "Explore Trending Articles",
+ "empty_feed_4": "Read The Quick Start Guide",
+ "empty_feed_5": "Browse The FAQ"
+ },
+ "transferhistoryrow_jsx": {
+ "to_savings": "to savings",
+ "from_savings": "from savings",
+ "cancel_transfer_from_savings": "Cancel transfer from savings",
+ "stop_power_down": "파워 다운 중지",
+ "start_power_down_of": "Start power down of",
+ "receive_interest_of": "Receive interest of"
+ },
+ "savingswithdrawhistory_jsx": {
+ "cancel_this_withdraw_request": "출금 요청을 취소하시겠습니까?",
+ "pending_savings_withdrawals": "출금 진행 중",
+ "withdraw": "%(amount)s 출금: ",
+ "to": "%(to)s로 전송",
+ "from_to": "%(from)s 에서 %(to)s로 전송"
+ },
+ "explorepost_jsx": {
+ "copied": "Copied!",
+ "copy": "COPY",
+ "alternative_sources": "Alternative Sources"
+ },
+ "header_jsx": {
+ "home": "home",
+ "create_a_post": "Create a post",
+ "change_account_password": "Change Account Password",
+ "create_account": "Create Account",
+ "stolen_account_recovery": "Stolen Account Recovery",
+ "people_following": "People following",
+ "people_followed_by": "People followed by",
+ "curation_rewards_by": "Curation rewards by",
+ "author_rewards_by": "Author rewards by",
+ "replies_to": "Replies to",
+ "comments_by": "Comments by"
+ },
+ "loginform_jsx": {
+ "you_need_a_private_password_or_key":
+ "You need a private password or key (not a public key)",
+ "cryptography_test_failed": "Cryptography test failed",
+ "unable_to_log_you_in":
+ "We will be unable to log you in with this browser.",
+ "the_latest_versions_of": "The latest versions of ",
+ "are_well_tested_and_known_to_work_with":
+ "are well tested and known to work with %(APP_URL)s.",
+ "due_to_server_maintenance":
+ "Due to server maintenance we are running in read only mode. We are sorry for the inconvenience.",
+ "login_to_vote": "Login to Vote",
+ "login_to_post": "Login to Post",
+ "login_to_comment": "Login to Comment",
+ "posting": "Posting",
+ "active_or_owner": "Active or Owner",
+ "this_password_is_bound_to_your_account_owner_key":
+ "This password is bound to your account's owner key and can not be used to login to this site.",
+ "however_you_can_use_it_to": "However, you can use it to ",
+ "update_your_password": "update your password",
+ "to_obtain_a_more_secure_set_of_keys":
+ "to obtain a more secure set of keys.",
+ "this_password_is_bound_to_your_account_active_key":
+ "This password is bound to your account's active key and can not be used to login to this page.",
+ "you_may_use_this_active_key_on_other_more":
+ "You may use this active key on other more secure pages like the Wallet or Market pages.",
+ "you_account_has_been_successfully_created":
+ "You account has been successfully created!",
+ "you_account_has_been_successfully_recovered":
+ "You account has been successfully recovered!",
+ "password_update_succes":
+ "The password for %(accountName)s was successfully updated",
+ "password_info":
+ "암호 또는 개인키가 잘못 입력되었습니다. 타자입력의 실수 또는 데이터 입력의 오류일 수 있습니다. 힌트: steemit 에서 생성된 암호 또는 개인키에는 0(숫자 0), O(영문자O), I(대문자I), l(소문자 L)을 절대로 포함하지 않습니다.",
+ "enter_your_username": "Enter your username",
+ "password_or_wif": "Password or WIF",
+ "this_operation_requires_your_key_or_master_password":
+ "이 작업은 %(authType)s 키 또는 마스터 비밀번호가 필요합니다.",
+ "keep_me_logged_in": "로그인 유지",
+ "amazing_community": "amazing community",
+ "to_comment_and_reward_others": " to comment and reward others.",
+ "signup_button": "Sign up now to earn ",
+ "signup_button_emphasis": "FREE STEEM!",
+ "sign_up_get_steem":
+ "계정을 만들고 가상화폐 STEEM 을 보상으로 받으세요.",
+ "returning_users": "Returning Users: ",
+ "join_our": "Join our"
+ },
+ "chainvalidation_js": {
+ "account_name_should": "Account name should ",
+ "not_be_empty": "not be empty.",
+ "be_longer": "be longer.",
+ "be_shorter": "be shorter.",
+ "each_account_segment_should": "Each account segment should ",
+ "start_with_a_letter": "start with a letter.",
+ "have_only_letters_digits_or_dashes":
+ "have only letters, digits, or dashes.",
+ "have_only_one_dash_in_a_row": "have only one dash in a row.",
+ "end_with_a_letter_or_digit": "end with a letter or digit.",
+ "verified_exchange_no_memo":
+ "You must include a memo for your exchange transfer."
+ },
+ "settings_jsx": {
+ "invalid_url": "잘못된 URL 입니다",
+ "name_is_too_long": "너무 긴 사용자 이름입니다",
+ "name_must_not_begin_with": "사용자 이름은 반드시 @로 시작해야 합니다",
+ "about_is_too_long": "About is too long",
+ "location_is_too_long": "너무 긴 지역명입니다",
+ "website_url_is_too_long": "너무 긴 웹사이트 URL입니다",
+ "public_profile_settings": "공개 프로파일 설정",
+ "preferences": "컨텐츠 표시 설정",
+ "not_safe_for_work_nsfw_content": "선정적이거나 폭력적인 컨텐츠",
+ "always_hide": "항상 숨기기",
+ "always_warn": "항상 경고하기",
+ "always_show": "항상 보이기",
+ "muted_users": "내가 차단한 사용자",
+ "update": "저장",
+ "profile_image_url": "프로파일 사진 경로",
+ "cover_image_url": "커버이미지 사진 경로",
+ "profile_name": "닉네임",
+ "profile_about": "한 줄 소개",
+ "profile_location": "지역",
+ "profile_website": "웹사이트"
+ },
+ "transfer_jsx": {
+ "amount_is_in_form": "Amount is in the form 99999.999",
+ "insufficient_funds": "잔고 부족",
+ "use_only_3_digits_of_precison": "최대 소수점 3자리까지 입력 가능",
+ "send_to_account": "Send to account",
+ "asset": "Asset",
+ "this_memo_is_private": "공개되지 않는 메모입니다.",
+ "this_memo_is_public": "모두에게 공개되는 메모입니다.",
+ "convert_to_VESTING_TOKEN": "Convert to %(VESTING_TOKEN)s",
+ "balance_subject_to_3_day_withdraw_waiting_period":
+ "3일간의 예치기간이 지나야 출금하실 수 있으며, ",
+ "move_funds_to_another_account": "다른 %(APP_NAME)s 계좌로 송금",
+ "protect_funds_by_requiring_a_3_day_withdraw_waiting_period":
+ "금고 보관 시 출금에 3일의 예치기간이 소요됩니다.",
+ "withdraw_funds_after_the_required_3_day_waiting_period":
+ "출금 시 3일의 예치기간이 소요됩니다.",
+ "from": "From",
+ "to": "To",
+ "asset_currently_collecting":
+ "%(asset)s의 연이율은 현재 %(interest)s%% 입니다.",
+ "beware_of_spam_and_phishing_links":
+ "메모에는 스팸과 피싱 링크가 포함 될 수 있으니 주의하십시오. 신뢰할 수없는 사용자의 링크를 열지 마십시오. 또한 다른 어떤 웹 사이트에도 개인키를 공개하지 마십시오."
+ },
+ "userwallet_jsx": {
+ "conversion_complete_tip": "Will complete on",
+ "in_conversion": "%(amount)s in conversion",
+ "transfer_to_savings": "금고로 전송",
+ "power_up": "파워 업",
+ "power_down": "파워 다운",
+ "market": "거래소",
+ "convert_to_LIQUID_TOKEN": "%(LIQUID_TOKEN)s 으로 전환",
+ "withdraw_LIQUID_TOKEN": "%(LIQUID_TOKEN)s 출금",
+ "withdraw_DEBT_TOKENS": "%(DEBT_TOKENS)s 출금",
+ "tokens_worth_about_1_of_LIQUID_TICKER":
+ "%(LIQUID_TICKER)s의 1달러 가치가 있는 토큰입니다. 현재 연이율은 %(sbdInterest)s%% 입니다.",
+ "savings": "예금",
+ "estimated_account_value": "추정 자산가치",
+ "next_power_down_is_scheduled_to_happen": "다음 파워다운 예정:",
+ "transfers_are_temporary_disabled":
+ "현재 일시적인 이유로 송금이 불가능합니다.",
+ "history": "거래 내역",
+ "redeem_rewards": "내 지갑으로 입금하기",
+ "buy_steem_or_steem_power": "STEEM, STEEM POWER 구입"
+ },
+ "powerdown_jsx": {
+ "power_down": "파워 다운",
+ "amount": "목표량",
+ "already_power_down":
+ "이미 %(AMOUNT)s %(LIQUID_TICKER)s의 파워 다운을 진행하고 있습니다(현재까지 %(WITHDRAWN)s %(LIQUID_TICKER)s 파워 다운). 파워다운 수량을 변경하게 되면 파워 다운 일정이 초기화되니 유의하십시오..",
+ "delegating":
+ "현재 %(AMOUNT)s %(LIQUID_TICKER)s을 임대 중입니다. 이 수량은 임대 종료 후 회수 기간이 완전히 지날 때까지는 파워 다운을 할 수 없습니다.",
+ "per_week": "That's ~%(AMOUNT)s %(LIQUID_TICKER)s per week.",
+ "warning":
+ "%(VESTING_TOKEN)s가 %(AMOUNT)s 이하로 내려가면 계정의 사용에 제약이 생깁니다.",
+ "error": "파워다운 실패: %(MESSAGE)s"
+ },
+ "checkloginowner_jsx": {
+ "your_password_permissions_were_reduced":
+ "Your password permissions were reduced",
+ "if_you_did_not_make_this_change":
+ "If you did not make this change please",
+ "ownership_changed_on": "Ownership Changed On ",
+ "deadline_for_recovery_is": "Deadline for recovery is",
+ "i_understand_dont_show_again": "이 메시지를 다시 보지 않기"
+ }
+}
diff --git a/src/app/locales/pl.json b/src/app/locales/pl.json
new file mode 100644
index 0000000000000000000000000000000000000000..a063b6e8c65545e71c6a0cd26d984f19ae835440
--- /dev/null
+++ b/src/app/locales/pl.json
@@ -0,0 +1,757 @@
+{
+ "g": {
+ "age": "wiek",
+ "amount": "Ilość",
+ "and": "oraz",
+ "are_you_sure": "Na pewno?",
+ "ask": "Oferty sprzedaży (ASK)",
+ "balance": "Saldo",
+ "balances": "Salda",
+ "bid": "Oferty kupna (BID) ",
+ "blog": "Blog",
+ "browse": "Przeglądaj",
+ "buy": "Kup",
+ "buy_or_sell": "Kup lub Sprzedaj",
+ "by": "przez",
+ "cancel": "Anuluj",
+ "change_password": "Zmień hasło",
+ "choose_language": "Wybierz język",
+ "clear": "Wyczyść",
+ "close": "Zamknij",
+ "collapse_or_expand": "Zwiń/Rozwiń",
+ "comments": "Komentarze",
+ "confirm": "Potwierdź",
+ "convert": "Konwersja",
+ "date": "Data",
+ "delete": "Usuń",
+ "dismiss": "Odrzuć",
+ "edit": "Edytuj",
+ "email": "Email",
+ "feed": "Strumień",
+ "follow": "Obserwuj",
+ "for": "za",
+ "from": "od",
+ "go_back": "Wstecz",
+ "hide": "Ukryj",
+ "in": "w",
+ "in_reply_to": "w odpowiedzi do",
+ "insufficient_balance": "Niewystarczające środki",
+ "invalid_amount": "Niepoprawna ilość",
+ "joined": "Dołączył",
+ "loading": "Wczytywanie",
+ "login": "Zaloguj",
+ "logout": "Wyloguj",
+ "memo": "Memo",
+ "mute": "Blokuj",
+ "myblog": "mój blog",
+ "mycomments": "moje komentarze",
+ "myreplies": "odpowiada mi",
+ "new": "nowe",
+ "newer": "Nowsze",
+ "next": "Następny",
+ "no": "Nie",
+ "ok": "Ok",
+ "older": "Starsze",
+ "or": "lub",
+ "order_placed": "Zlecenie przyjęte",
+ "password": "Hasło",
+ "payouts": "Płatności",
+ "permissions": "Uprawnienia",
+ "post": "Napisz",
+ "post_as": "Napisz jako",
+ "posts": "Posty",
+ "powered_up_100": "Zwiększono moc 100%%",
+ "preview": "Podgląd",
+ "previous": "Poprzedni",
+ "price": "Cena",
+ "print": "Drukuj",
+ "promote": "Promuj",
+ "promoted": "promowane",
+ "re": "ODP",
+ "re_to": "ODP: %(topic)s",
+ "recent_password": "Niedawne hasło",
+ "receive": "Odbierz",
+ "remove": "Usuń",
+ "remove_vote": "Usuń głos",
+ "replied_to": "odpowiedziano %(account)s",
+ "replies": "Odpowiedzi",
+ "reply": "Odpowiedz",
+ "reply_count": {
+ "zero": "brak odpowiedzi",
+ "one": "1 odpowiedź",
+ "other": "%(count)s odpowiedzi"
+ },
+ "reputation": "Reputacja",
+ "reveal_comment": "Odsłoń komentarz",
+ "request": "prośba",
+ "required": "Wymagany",
+ "rewards": "Nagrody",
+ "save": "Zapisz",
+ "saved": "Zapisane",
+ "search": "Szukaj",
+ "sell": "Sprzedaj",
+ "settings": "Ustawienia",
+ "share_this_post": "Udostępnij ten post",
+ "show": "Pokaż",
+ "sign_in": "Zaloguj się",
+ "sign_up": "Zapisz się",
+ "since": "od",
+ "submit": "Zatwierdź",
+ "power_up": "Zwiększ moc",
+ "submit_a_story": "Napisz",
+ "tag": "Tag",
+ "to": "do",
+ "topics": "Tematy",
+ "transfer": "Prześlij",
+ "trending_topics": "Popularne tematy",
+ "type": "Typ",
+ "unfollow": "Przestań obserwować",
+ "unmute": "Odblokuj",
+ "unknown": "Nieznany",
+ "upvote": "Zagłosuj",
+ "upvote_post": "Głosuj na wpis",
+ "username": "Nazwa użytkownika",
+ "version": "Wersja",
+ "vote": "Głos",
+ "votes": "głosy",
+ "wallet": "Portfel",
+ "warning": "ostrzeżenie",
+ "yes": "Tak",
+ "posting": "Publikacja",
+ "owner": "Właściciela",
+ "active": "Aktywny",
+ "account_not_found": "Konto nie znalezione",
+ "this_is_wrong_password": "To jest nieprawidłowe hasło",
+ "do_you_need_to": "Czy potrzebujesz",
+ "account_name": "Nazwa konta",
+ "recover_your_account": "odzyskaj swoje konto",
+ "reset_usernames_password": "Zresetuj hasło dla %(username)s",
+ "this_will_update_usernames_authtype_key":
+ "To dokona aktualizacji klucza %(authType)sdla %(username)s",
+ "passwords_do_not_match": "Hasła się różnią",
+ "you_need_private_password_or_key_not_a_public_key":
+ "Potrzebujesz hasła głównego lub klucza prywatnego (nie klucza publicznego)",
+ "the_rules_of_APP_NAME": {
+ "one": "Pierwsza zasada %(APP_NAME)sbrzmi: Nie zgub swojego hasła.",
+ "second": "Druga zasada %(APP_NAME)sbrzmi: Nie zgub swojego hasła.",
+ "third":
+ "Trzecia zasada %(APP_NAME)sbrzmi: Nie mamy możliwości odzyskania Twojego hasła.",
+ "fourth":
+ "Czwarta zasada: Jeśli potrafisz zapamiętać hasło to nie jest ono bezpieczne.",
+ "fifth":
+ "Piąta zasada: Używaj wyłącznie losowo generowanych haseł.",
+ "sixth": "Szósta zasada: Nie ujawniaj nikomu swojego hasła.",
+ "seventh":
+ "Siódma zasada: Zawsze miej kopię zapasową swojego hasła."
+ },
+ "recover_password": "Odzyskaj konto",
+ "current_password": "Obecne hasło",
+ "generated_password": "Wygenerowane hasło",
+ "backup_password_by_storing_it":
+ "Zachowaj je zapisując w menadżerze haseł lub w pliku tekstowym",
+ "enter_account_show_password":
+ "Wpisz prawidłową nazwę konta by pokazać hasło",
+ "click_to_generate_password": "Kliknij by wygenerować hasło",
+ "re_enter_generate_password": "Podaj ponownie wygenerowane hasło",
+ "understand_that_APP_NAME_cannot_recover_password":
+ "Rozumiem, że %(APP_NAME)snie ma możliwości odzyskania utraconych haseł",
+ "i_saved_password": "Zachowałem bezpiecznie moje wygenerowane hasło",
+ "update_password": "Zaktualizuj hasło",
+ "confirm_password": "Potwierdź hasło",
+ "account_updated": "Konto zaktualizowane",
+ "password_must_be_characters_or_more":
+ "Hasło musi posiadać %(amount)slub więcej znaków",
+ "need_password_or_key":
+ "Potrzebujesz hasła głównego lub klucza prywatnego (nie klucza publicznego)",
+ "login_to_see_memo": "zaloguj by zobaczyć memo",
+ "new_password": "Nowe hasło",
+ "incorrect_password": "Nieprawidłowe hasło",
+ "username_does_not_exist": "Nazwa użytkownika nie istnieje",
+ "account_name_should_start_with_a_letter":
+ "Nazwa konta powinna zaczynać się od litery",
+ "account_name_should_be_shorter": "Nazwa konta powinna być krótsza",
+ "account_name_should_be_longer": "Nazwa konta powinna być dłuższa",
+ "account_name_should_have_only_letters_digits_or_dashes":
+ "Nazwa konta powinna zawierać wyłącznie litery, cyfry, kropki lub myślniki",
+ "cannot_increase_reward_of_post_within_the_last_minute_before_payout":
+ "Nie można zwiększyć nagrody za post w ostatnich chwilach przed wypłatą",
+ "vote_currently_exists_user_must_be_indicate_a_to_reject_witness":
+ "głos oddany, użytkownik musi wskazać powód odrzucenia delegata",
+ "only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes":
+ "Dozwolone jest tylko jedno konto Steem dla danego adresu IP w ciągu 10 minut",
+ "resteem_this_post": "Resteemuj ten post",
+ "reblog": "Resteem",
+ "write_your_story": "Napisz swoją historię",
+ "remember_voting_and_posting_key":
+ "Zapamiętaj klucze do głosowania i tworzenia wpisów",
+ "auto_login_question_mark": "Automatyczne logowanie?",
+ "hide_private_key": "Ukryj klucz prywatny",
+ "show_private_key": "Pokaż klucz prywatny",
+ "login_to_show": "Zaloguj się by wyświetlić",
+ "not_valid_email": "Niepoprawny adres email",
+ "thank_you_for_being_an_early_visitor_to_APP_NAME":
+ "Dziękujemy za to, że jesteś jednym z pierwszych odwiedzających%(APP_NAME)s. Skontaktujemy się z tobą przy najbliższej okazji.",
+ "author_rewards": "Wynagrodzenia autorskie",
+ "curation_rewards": "Wynagrodzenia kuratorskie",
+ "sorry_your_reddit_account_doesnt_have_enough_karma":
+ "Twoje konto nie ma wystarczającej liczby punktów Reddit Karma, by zakwalifikować się na natychmiastową rejestrację. Podaj swój adres email by umieścić go na liście oczekujących ",
+ "register_with_facebook": "Zarejestruj się z użyciem Facebooka",
+ "or_click_the_button_below_to_register_with_facebook":
+ "Lub kliknij przycisk poniżej by zarejestrować się z użyciem Facebooka",
+ "server_returned_error": "serwer zwrócił błąd",
+ "APP_NAME_support": "Wsparcie %(APP_NAME)s",
+ "please_email_questions_to": "Proszę wysłać swoje zapytanie na maila",
+ "next_7_strings_single_block": {
+ "authors_get_paid_when_people_like_you_upvote_their_post":
+ "Autorzy otrzymują wypłatę gdy ludzie tacy jak Ty głosują na ich wpisy",
+ "if_you_enjoyed_what_you_read_earn_amount":
+ "Jeśli podobało Ci się to o czym tu czytałeś, jeszcze dziś załóż tu konto i zacznij zarabiać DARMOWE TOKENY STEEM!",
+ "free_steem": "DARMOWE TOKENY STEEM",
+ "sign_up_earn_steem": "Zarejestruj się by zarabiać"
+ },
+ "next_3_strings_together": {
+ "show_more": "Pokaż więcej",
+ "show_less": "Pokaż mniej",
+ "value_posts": "posty niskiej jakości"
+ },
+ "read_only_mode":
+ "Z powodu prac na serwerze działamy w trybie tylko do odczytu.\nPrzepraszamy za niedogodności.",
+ "tags_and_topics": "Kategorie",
+ "show_more_topics": "Pokaż więcej kategorii",
+ "basic": "Podstawowy",
+ "advanced": "Zaawansowany",
+ "views": {
+ "zero": "Brak wyświetleń",
+ "one": "%(count)s wyświetlenie",
+ "other": "%(count)s wyświetleń"
+ },
+ "responses": {
+ "zero": "Brak odpowiedzi",
+ "one": "%(count)sodpowiedź",
+ "other": "%(count)sodpowiedzi"
+ }
+ },
+ "navigation": {
+ "about": "O Steem",
+ "explore": "Przeglądaj",
+ "APP_NAME_whitepaper": "%(APP_NAME)s Whitepaper",
+ "buy_LIQUID_TOKEN": "Kup %(LIQUID_TOKEN)s",
+ "sell_LIQUID_TOKEN": "Sprzedaj %(LIQUID_TOKEN)s",
+ "currency_market": "Wymiana tokenów",
+ "stolen_account_recovery": "Odzyskiwanie skradzionych kont",
+ "change_account_password": "Zmiana hasła dla konta",
+ "witnesses": "Delegaci",
+ "vote_for_witnesses": "Głosuj na delegatów",
+ "privacy_policy": "Polityka prywatności",
+ "terms_of_service": "Warunki korzystania z usługi",
+ "sign_up": "Dołącz",
+ "learn_more": "Dowiedz się więcej",
+ "welcome": "Witaj",
+ "faq": "FAQ",
+ "chat": "Steem Chat",
+ "app_center": "Steemit App Center",
+ "api_docs": "Dokumentacja Steemit API",
+ "whitepaper": "Steem Whitepaper",
+ "intro_tagline": "Pieniądze mają głos.",
+ "intro_paragraph":
+ "Twój głos ma wartość. Dołącz do społeczności, która płaci za publikowanie i głosowanie na wysokiej jakości treści."
+ },
+ "main_menu": {
+ "hot": "gorące",
+ "trending": "aktywne"
+ },
+ "reply_editor": {
+ "shorten_title": "Tytuł skrócony",
+ "exceeds_maximum_length": "Przekracza maksymalną długość (%(maxKb)sKB)",
+ "including_the_category": "(wliczając kategorię '%(rootCategory)s')",
+ "use_limited_amount_of_tags":
+ "Masz %(tagsLength)s tagów total%(includingCategory)s. Ogranicz liczbę tagów do 5 w swoim poście.",
+ "are_you_sure_you_want_to_clear_this_form":
+ "Czy jesteś pewien, że chcesz wyczyścić ten formularz?",
+ "uploading": "Wysyłanie",
+ "draft_saved": "Szkic zapisany.",
+ "editor": "Edytor",
+ "insert_images_by_dragging_dropping":
+ "Wstaw obrazki przez przeciągnij i upuść.",
+ "pasting_from_the_clipboard": "wklejanie ze schowka,",
+ "selecting_them": "wybranie ich",
+ "image_upload": "Wgraj obrazek",
+ "power_up_100": "Zwiększ moc 100%%",
+ "default_50_50": "Domyślnie (50%% / 50%%)",
+ "decline_payout": "Odmowa wypłaty",
+ "check_this_to_auto_upvote_your_post":
+ "Zaznacz by automatycznie zagłosować na swój wpis",
+ "markdown_styling_guide": "Przewodnik formatowania z użyciem Markdown",
+ "or_by": "lub przez",
+ "title": "Tytuł",
+ "update_post": "Edytuj wpis",
+ "markdown_not_supported": "Formatowanie Markdown nie jest tu wspierane"
+ },
+ "category_selector_jsx": {
+ "tag_your_story":
+ "Kategorie (do 5 kategorii), pierwsza kategoria określa główną.",
+ "select_a_tag": "Wybierz kategorię",
+ "maximum_tag_length_is_24_characters":
+ "Maksymalna długość nazwy kategorii to 24 znaki",
+ "use_limited_amount_of_categories":
+ "Użyj proszę co najwyżej %(amount)s kategorii",
+ "use_only_lowercase_letters": "Użyj wyłącznie małych liter",
+ "use_one_dash": "Użyj tylko jednego myślnika",
+ "use_spaces_to_separate_tags":
+ "Użyj spacji do oddzielenia nazw kategorii",
+ "use_only_allowed_characters":
+ "Możesz użyć wyłącznie małych liter, cyfr i jednego znaku myślnika",
+ "must_start_with_a_letter": "Musi zaczynać się od litery",
+ "must_end_with_a_letter_or_number": "Musi kończyć się literą lub cyfrą"
+ },
+ "postfull_jsx": {
+ "this_post_is_not_available_due_to_a_copyright_claim":
+ "Ten wpis jest niedostępny z powodu roszczeń do praw autorskich.",
+ "share_on_facebook": "Podziel się na Facebooku",
+ "share_on_twitter": "Podziel się na Twitterze",
+ "share_on_linkedin": "Podziel się na Linkedin",
+ "recent_password": "Ostatnie hasło",
+ "in_week_convert_DEBT_TOKEN_to_LIQUID_TOKEN":
+ "W ciągu 3,5 dni, konwertuj %(amount)s %(DEBT_TOKEN)s w %(LIQUID_TOKEN)s",
+ "view_the_full_context": "Zobacz pełen kontekst.",
+ "view_the_direct_parent": "Zobacz wpis nadrzędny",
+ "you_are_viewing_a_single_comments_thread_from":
+ "Przeglądasz wątek pojedynczego komentarza"
+ },
+ "market_jsx": {
+ "action": "Akcja",
+ "date_created": "Data utworzenia",
+ "last_price": "Ostatnia cena",
+ "24h_volume": "Wolumen 24h",
+ "spread": "Spread",
+ "total": "Razem",
+ "available": "Dostępne",
+ "lowest_ask": "Najniższa oferta sprzedaży (ASK)",
+ "highest_bid": "Najwyższa oferta kupna (BID)",
+ "buy_orders": "Oferty zakupu",
+ "sell_orders": "Oferty sprzedaży",
+ "trade_history": "Historia transakcji",
+ "open_orders": "Otwarte oferty",
+ "sell_amount_for_atleast":
+ "Sprzedaj %(amount_to_sell)s za co najmniej %(min_to_receive)s (%(effectivePrice)s)",
+ "buy_atleast_amount_for":
+ "Kup przynajmniej %(min_to_receive)s za %(amount_to_sell)s (%(effectivePrice)s)",
+ "price_warning_above":
+ "Ta cena jest sporo wyższa od aktualnych cen rynkowych %(marketPrice)s, czy jesteś pewien(na)?",
+ "price_warning_below":
+ "Ta cena jest sporo niższa od aktualnych cen rynkowych %(marketPrice)s, czy jesteś pewien(na)?",
+ "order_cancel_confirm": "Anulować ofertę %(order_id)s od %(user)s?",
+ "order_cancelled": "Oferta %(order_id)s anulowana.",
+ "higher": "Wyżej",
+ "lower": "Niżej",
+ "total_DEBT_TOKEN_SHORT_CURRENCY_SIGN":
+ "Razem %(DEBT_TOKEN_SHORT)s (%(CURRENCY_SIGN)s)"
+ },
+ "recoveraccountstep1_jsx": {
+ "begin_recovery": "Rozpocznij odzyskiwanie konta",
+ "not_valid": "Wartość niepoprawna",
+ "account_name_is_not_found": "Nazwa konta nie została znaleziona",
+ "unable_to_recover_account_not_change_ownership_recently":
+ "Nie jesteśmy w stanie odzyskać tego konta, bo w ostatnim czasie nie zmieniło ono właściciela.",
+ "password_not_used_in_last_days":
+ "To hasło nie zostało użyte na tym koncie w ciągu ostatnich 30 dni.",
+ "request_already_submitted_contact_support":
+ "Twoje zapytanie zostało już wysłane i już nad nim pracujemy. Proszę kontaktować się z %(SUPPORT_EMAIL)s w celu uzyskania informacji o statusie jego przetwarzania.",
+ "recover_account_intro":
+ "Od czasu do czasu, klucz właściciela może zostać zagrożony. Odzyskiwanie konta pozwala prawowitemu właścicielowi na odzyskanie konta w ciągu 30 dni, liczone od momentu zmiany klucza właściciela przez złodzieja. Odzyskiwanie konta można zrobić na %(APP_URL)s o ile właściciel konta uprzednio wyszczególnił '%(APP_NAME)s' jako powiernika konta i spełnił warunki użytkowania %(APP_NAME)s's.",
+ "login_with_facebook_or_reddit_media_to_verify_identity":
+ "Proszę zalogować się z użyciem konta na Facebooku lub Reddicie by zweryfikować swoją tożsamość.",
+ "login_with_social_media_to_verify_identity":
+ "Proszę zalogować się z użyciem konta na %(provider)s by zweryfikować swoją tożsamość.",
+ "enter_email_toverify_identity":
+ "Musimy zweryfikować Twoją tożsamość. Prosimy o podanie swojego adresu email by rozpocząć proces weryfikacji.",
+ "continue_with_email": "Kontynuuj z adresem email",
+ "thanks_for_submitting_request_for_account_recovery":
+ "Dziękujemy za wysłanie zgłoszenia dotyczącego odzyskiwania konta używając wieloskładnikowej, opartej o blockchain autentykacji %(APP_NAME)s's. Odpowiemy najszybciej jak to możliwe, jednakże, możliwe są opóźnienia z powodu dużej ilości zgłoszeń. Proszę być przygotowanym do potwierdzenia tożsamości.",
+ "recovering_account": "Odzyskiwanie konta",
+ "recover_account": "Odzyskaj konto",
+ "checking_account_owner": "Sprawdzanie właściciela konta",
+ "sending_recovery_request": "Wysyłanie zapytania o odzyskanie konta",
+ "cant_confirm_account_ownership":
+ "Nie możemy potwierdzić przynależności konta. Sprawdź swoje hasło.",
+ "account_recovery_request_not_confirmed":
+ "Zapytanie o odzyskanie konta nie uzyskało jeszcze potwierdzenia, prosimy wrócić później, dziękujemy za Twoją cierpliwość."
+ },
+ "user_profile": {
+ "unknown_account": "Konto nieznane",
+ "user_hasnt_made_any_posts_yet":
+ "Wygląda na to, że %(name)s nie opublikował jeszcze żadnych wpisów!",
+ "user_hasnt_started_bloggin_yet":
+ "Wygląda na to, że %(name)s nie zaczął jeszcze blogowania!",
+ "user_hasnt_followed_anything_yet":
+ "Wygląda na to, że użytkownik %(name)s jeszcze nikogo nie obserwuje. Jeśli %(name)s zaczął(ęła) obserwować nowych użytkowników jego(jej) osobisty strumień zacznie się zapełniać, gdy powstaną nowe treści. ",
+ "user_hasnt_had_any_replies_yet":
+ "%(name)s nie ma jeszcze żadnych odpowiedzi",
+ "followers": "Obserwujący",
+ "this_is_users_reputations_score_it_is_based_on_history_of_votes":
+ "To są punkty reputacji użytkownika %(name)s.\n\nSystem punktów reputacji bazuje na historii otrzymanych przez użytkownika głosów i jest używany do ukrywania wpisów o niskiej jakości.",
+ "follower_count": {
+ "zero": "Brak obserwujących",
+ "one": "1 obserwujący",
+ "other": "%(count)s obserwujących"
+ },
+ "followed_count": {
+ "zero": "Brak obserwowanych",
+ "one": "1 obserwowany",
+ "other": "%(count)s obserwowanych"
+ },
+ "post_count": {
+ "zero": "Brak wpisów",
+ "one": "1 wpis",
+ "other": "%(count)s wpisów"
+ }
+ },
+ "authorrewards_jsx": {
+ "estimated_author_rewards_last_week":
+ "Szacowane wynagrodzenie autorskie w ostatnim tygodniu",
+ "author_rewards_history": "Historia wynagrodzeń autorskich"
+ },
+ "curationrewards_jsx": {
+ "estimated_curation_rewards_last_week":
+ "Szacowane wynagrodzenie kuratorskie w ostatnim tygodniu",
+ "curation_rewards_history": "Historia wynagrodzeń kuratorskich"
+ },
+ "post_jsx": {
+ "now_showing_comments_with_low_ratings":
+ "Od teraz komentarze o niskich ocenach będą wyświetlane",
+ "sort_order": "Kolejność sortowania",
+ "comments_were_hidden_due_to_low_ratings":
+ "Komentarze zostały ukryte z powodu otrzymania niskich ocen"
+ },
+ "voting_jsx": {
+ "flagging_post_can_remove_rewards_the_flag_should_be_used_for_the_following":
+ "Nadanie flagi może obniżać wynagrodzenia i spowodować mniejszą widoczność tej treści. Niektóre z powodów do oznaczania wpisów flagami",
+ "disagreement_on_rewards": "Niezgoda co do wysokości wynagrodzenia",
+ "fraud_or_plagiarism": "Oszustwo lub plagiat",
+ "hate_speech_or_internet_trolling": "Mowa nienawiści lub trolowanie",
+ "intentional_miss_categorized_content_or_spam":
+ "Świadome złe przydzielenie kategorii do treści lub spam",
+ "pending_payout": "Wypłata $%(value)s nastąpi",
+ "payout_declined": "Odmowa przyjęcia wypłaty",
+ "max_accepted_payout":
+ "Maksymalna akceptowana wysokość wypłaty $%(value)s",
+ "promotion_cost": "Koszty promocji $%(value)s",
+ "past_payouts": "Wcześniejsze wypłaty $%(value)s",
+ "past_payouts_author": "- Autor $%(value)s",
+ "past_payouts_curators": "- Kuratorzy $%(value)s",
+ "we_will_reset_curation_rewards_for_this_post":
+ "wyzeruje twoje wynagrodzenie kuratorskie dla tego wpisu",
+ "removing_your_vote": "Wycofanie twojego głosu",
+ "changing_to_an_upvote": "Zmień na głos za",
+ "changing_to_a_downvote": "Zmień na głos przeciw",
+ "confirm_flag": "Potwierdź oznaczenie flagą",
+ "and_more": "i %(count)s więcej",
+ "votes_plural": {
+ "one": "%(count)s głos",
+ "other": "%(count)s głosów"
+ }
+ },
+ "witnesses_jsx": {
+ "witness_thread": "wątek delegata",
+ "top_witnesses": "Głosowanie na delegatów",
+ "you_have_votes_remaining": {
+ "zero": "Nie masz już więcej głosów",
+ "one": "Pozostał ci 1 głos",
+ "other": "Pozostało ci %(count)s głosów"
+ },
+ "you_can_vote_for_maximum_of_witnesses":
+ "Możesz głosować co najwyżej na 30 delegatów",
+ "witness": "Delegat",
+ "information": "Informacja",
+ "if_you_want_to_vote_outside_of_top_enter_account_name":
+ "Jeśli chcesz zagłosować na delegata spoza pierwszej 50, podaj nazwę konta na które chcesz oddać głos",
+ "set_witness_proxy":
+ "Możesz również wybrać pełnomocnika, który zagłosuje na delegatów za ciebie. Wybór pełnomocnika wyczyści twoje bieżące głosy.",
+ "witness_set":
+ "Wybrałeś pełnomocnika. Jeśli chcesz wrócić do ręcznego oddawania głosów, usuń pełnomocnika.",
+ "witness_proxy_current": "Twoim pełnomocnikiem jest",
+ "witness_proxy_set": "Ustaw pełnomocnika",
+ "witness_proxy_clear": "Wyczyść pełnomocnika",
+ "proxy_update_error": "Twój pełnomocnik nie został zaktualizowany"
+ },
+ "votesandcomments_jsx": {
+ "no_responses_yet_click_to_respond":
+ "Brak odpowiedzi. Kliknij by odpowiedzieć.",
+ "response_count_tooltip": {
+ "zero": "brak odpowiedzi. Kliknij by odpowiedzieć.",
+ "one": "1 odpowiedź. Kliknij by odpowiedzieć.",
+ "other": "%(count)s odpowiedzi. Kliknij by odpowiedzieć."
+ },
+ "vote_count": {
+ "zero": "brak głosów",
+ "one": "1 głos",
+ "other": "%(count)s głosów"
+ }
+ },
+ "userkeys_jsx": {
+ "public": "Publiczny",
+ "private": "Prywatny",
+ "public_something_key": "Klucz publiczny %(key)s",
+ "private_something_key": "Klucz prywatny %(key)s",
+ "posting_key_is_required_it_should_be_different":
+ "Klucz do publikowania jest używany do publikowania treści, komentarzy i głosowania. Powinien różnić się od klucza aktywności i klucza właściciela.",
+ "the_active_key_is_used_to_make_transfers_and_place_orders":
+ "Klucz aktywności używany jest do przesyłania tokenów i składania ofert na wewnętrznym rynku wymiany walut.",
+ "the_owner_key_is_required_to_change_other_keys":
+ "Klucz właściciela jest kluczem głównym do twojego konta i jest wymagany do zmiany pozostałych kluczy.",
+ "the_private_key_or_password_should_be_kept_offline":
+ "Klucz prywatny właściciela lub hasło właściciela powinny być bezpiecznie przechowywane offline.",
+ "the_memo_key_is_used_to_create_and_read_memos":
+ "Klucz memo jest używany do tworzenia i czytania memo"
+ },
+ "suggestpassword_jsx": {
+ "APP_NAME_cannot_recover_passwords_keep_this_page_in_a_secure_location":
+ "%(APP_NAME)s nie jest w stanie odzyskiwać haseł. Trzymaj tę kartkę w bezpiecznym miejscu, takim jak ognioodporny sejf lub skrytka bankowa.",
+ "APP_NAME_password_backup": "%(APP_NAME)s Kopia zapasowa hasła",
+ "APP_NAME_password_backup_required":
+ "%(APP_NAME)s Kopia zapasowa hasła (wymagane)",
+ "after_printing_write_down_your_user_name":
+ "Po wydrukowaniu, zapisz swoją nazwę użytkownika"
+ },
+ "converttosteem_jsx": {
+ "your_existing_DEBT_TOKEN_are_liquid_and_transferable":
+ "Twoje %(DEBT_TOKEN)s są płynne i mogą być przetransferowane. Możesz to zrobić pod tym linkiem %(link)s lub przetransferować na zewnętrzną giełdę.",
+ "this_is_a_price_feed_conversion":
+ "Przeliczenie po kursie rynkowym. Okres 3,5 dnia jest niezbędny, aby zapobiec nadużyciom związanym z krótkoterminowymi zmianami średniej ceny rynkowej",
+ "convert_to_LIQUID_TOKEN": "Przekonwertuj tokeny na %(LIQUID_TOKEN)s",
+ "DEBT_TOKEN_will_be_unavailable":
+ "Ta akcja zajmie 3,5 dnia od teraz i nie może być anulowana. Te tokeny %(DEBT_TOKEN)s natychmiast staną się niedostępne."
+ },
+ "tips_js": {
+ "liquid_token":
+ "Zbywalne tokeny które mogą być przesłane gdziekolwiek w dowolnym momencie. %(LIQUID_TOKEN)s mogą zostać również przekonwertowane na %(VESTING_TOKEN)s w procesie nazywanym zwiększenie mocy.",
+ "influence_token":
+ "Tokeny wpływu, które zwiększają Twój wpływ na podział wypłat za publikowanie treści, oraz pozwalają Ci zarabiać na głosowaniu na treści.",
+ "estimated_value":
+ "Szacowana wartość bazuje na średniej cenie tokenu %(LIQUID_TOKEN)s w dolarach amerykańskich.",
+ "non_transferable":
+ "Jednostki %(VESTING_TOKEN)s są niezbywalne i wymagają 3 miesięcy (w 13 ratach) do konwersji z powrotem na tokeny %(LIQUID_TOKEN)s.",
+ "converted_VESTING_TOKEN_can_be_sent_to_yourself_but_can_not_transfer_again":
+ "Przekonwertowane jednostki %(VESTING_TOKEN)s możesz wysłać sobie lub komuś innemu ale nie możesz ich wysłać ponownie bez konwersji z powrotem do tokenów %(LIQUID_TOKEN)s.",
+ "part_of_your_steem_power_is_currently_delegated":
+ "Część z Twoich jednostek wpływu STEEM POWER jest Ci oddelegowana. Delegowane jednostek to czasowe użyczenie dla zwiększenia wpływu lub by pomóc nowym użytkownikom platformy w korzystaniu ze Steemit. Kwota oddelegowanych jednostek może się zmieniać w czasie."
+ },
+ "promote_post_jsx": {
+ "promote_post": "Promuj wpis",
+ "spend_your_DEBT_TOKEN_to_advertise_this_post":
+ "Wydaj swoje tokeny %(DEBT_TOKEN)s by zareklamować ten wpis w sekcji treści promowanych",
+ "you_successfully_promoted_this_post":
+ "Promowanie tego wpisu zakończyło się sukcesem",
+ "this_post_was_hidden_due_to_low_ratings":
+ "Ten wpis został ukryty z powodu niskich ocen"
+ },
+ "about_jsx": {
+ "about_app": "O %(APP_NAME)s",
+ "about_app_details":
+ "%(APP_NAME)s jest platformą mediów społecznościowych gdzie wszyscy są opłacani za tworzenie i głosowanie na treści. Bazuje na solidnym systemie cyfrowych tokenów o nazwie Steem, który reprezentuje realną wartość żetonów cyfrowych, opierając się na płynności i wolnorynkowej wycenie.",
+ "learn_more_at_app_url": "Dowiedz się więcej %(APP_URL)s",
+ "resources": "Zasoby"
+ },
+ "markdownviewer_jsx": {
+ "images_were_hidden_due_to_low_ratings":
+ "Obrazki zostały ukryte z powodu niskich ocen."
+ },
+ "postsummary_jsx": {
+ "resteemed": "Resteemowane",
+ "resteemed_by": "Resteemowane przez",
+ "this_post_is": "Ten post jest",
+ "you_can": "Możesz",
+ "reveal_it": "pokaż to",
+ "adjust_your": "dostosuj twój",
+ "display_preferences": "wyświetl ustawienia",
+ "create_an_account": "utwórz konto",
+ "to_save_your_preferences": "by zapisać twoje preferencje"
+ },
+ "posts_index": {
+ "empty_feed_1": "Wygląda na to, że jeszcze nikogo nie obserwujesz",
+ "empty_feed_2":
+ "Jeżeli dopiero zacząłeś kogoś obserwować, twój strumień zaktualizuje się, gdy pojawią się nowe treści",
+ "empty_feed_3": "Przeglądaj aktywne posty",
+ "empty_feed_4": "Przeczytaj Quick Start Guide",
+ "empty_feed_5": "Przeglądaj FAQ"
+ },
+ "transferhistoryrow_jsx": {
+ "to_savings": "na konto oszczędnościowe",
+ "from_savings": "z konta oszczędnościowego",
+ "cancel_transfer_from_savings":
+ "Anuluj przelew z konta oszczędnościowego",
+ "stop_power_down": "Zatrzymaj zmniejszanie mocy",
+ "start_power_down_of": "Zacznij zmniejszanie mocy",
+ "receive_interest_of": "Odbierz odsetki od"
+ },
+ "savingswithdrawhistory_jsx": {
+ "cancel_this_withdraw_request": "Anulować zlecenie wypłaty?",
+ "pending_savings_withdrawals": "WYPŁATY OSZCZĘDNOŚCI W TOKU",
+ "withdraw": "Wypłać %(amount)s",
+ "to": "do %(to)s",
+ "from_to": "od %(from)s do %(to)s"
+ },
+ "explorepost_jsx": {
+ "copied": "Skopiowano!",
+ "copy": "KOPIUJ",
+ "alternative_sources": "Alternatywne źródła"
+ },
+ "header_jsx": {
+ "home": "początek",
+ "create_a_post": "Napisz post",
+ "change_account_password": "Zmiana hasła konta",
+ "create_account": "Zakładanie konta",
+ "stolen_account_recovery": "Odzyskiwanie skradzionego konta",
+ "people_following": "Obserwowani ludzie",
+ "people_followed_by": "Obserwowani ludzie przez",
+ "curation_rewards_by": "Wynagrodzenia kuratorskie",
+ "author_rewards_by": "Wynagrodzenia autorskie",
+ "replies_to": "Odpowiedzi do",
+ "comments_by": "Komentarze"
+ },
+ "loginform_jsx": {
+ "you_need_a_private_password_or_key":
+ "Potrzebujesz prywatnego hasła lub klucza (nie klucz publiczny)",
+ "cryptography_test_failed": "Test kryptograficzny nieudany",
+ "unable_to_log_you_in":
+ "Nie będziemy mogli zalogować cię w tej przeglądarce.",
+ "the_latest_versions_of": "Ostatnie wersje",
+ "are_well_tested_and_known_to_work_with":
+ "zostały przetestowane i współpracują z %(APP_URL)s.",
+ "due_to_server_maintenance":
+ "Z powodu prac na serwerach, aktualnie można tylko przeglądać treści. Przepraszamy za niedogodności.",
+ "login_to_vote": "Zaloguj się, aby zagłosować",
+ "login_to_post": "Zaloguj się, aby napisać",
+ "login_to_comment": "Zaloguj się, aby skomentować",
+ "posting": "Publikacja",
+ "active_or_owner": "Aktywny lub właściciela",
+ "this_password_is_bound_to_your_account_owner_key":
+ "To hasło jest przypisane do klucza właściciela, i nie może być użyte do logowania na tej stronie.",
+ "however_you_can_use_it_to": "Jednakże, możesz użyć go do ",
+ "update_your_password": "aktualizacji swojego hasła",
+ "to_obtain_a_more_secure_set_of_keys":
+ "otrzymania bardziej bezpiecznego zestawu kluczy.",
+ "this_password_is_bound_to_your_account_active_key":
+ "To hasło jest przypisane do klucza aktywnego, i nie może być użyte do logowania na tej stronie.",
+ "you_may_use_this_active_key_on_other_more":
+ "Możesz używać klucza aktywnego na stronach takich jak Portfel czy Giełda.",
+ "you_account_has_been_successfully_created":
+ "Twoje konto zostało utworzone!",
+ "you_account_has_been_successfully_recovered":
+ "Twoje konto zostało odzyskane!",
+ "password_update_succes":
+ "Hasło %(accountName)s zostało zaktualizowane",
+ "password_info":
+ "To hasło lub klucz prywatny zostało wprowadzone błędnie. Sprawdź poprawność zapisu. Wskazówka: Hasło lub klucz prywatny wygenerowany przez Steemit, nigdy nie będzie zawierał znaków: 0 (zero), O (duża litera o), I (duża litera i) i l (mała litera L).",
+ "enter_your_username": "Podaj nazwę użytkownika",
+ "password_or_wif": "Hasło lub WIF",
+ "this_operation_requires_your_key_or_master_password":
+ "Ta operacja wymaga twojego klucza %(authType)s klub hasła głównego.",
+ "keep_me_logged_in": "Nie wylogowuj mnie",
+ "amazing_community": "niesamowitej społeczności",
+ "to_comment_and_reward_others": " aby komentować i nagradzać innych.",
+ "sign_up_now_to_earn": "Zarejestruj się aby zarabiać ",
+ "free_money": "DARMOWY STEEM!",
+ "returning_users": "Powracający użytkownicy: ",
+ "join_our": "Dołącz do"
+ },
+ "chainvalidation_js": {
+ "account_name_should": "Nazwa konta powinna ",
+ "not_be_empty": "nie być pusta.",
+ "be_longer": "być dłuższa.",
+ "be_shorter": "być krótsza.",
+ "each_account_segment_should": "Każda część nazwy powinna ",
+ "start_with_a_letter": "zaczynać się literą.",
+ "have_only_letters_digits_or_dashes":
+ "posiadać tylko litery, cyfry lub myślniki.",
+ "have_only_one_dash_in_a_row": "posiadać tylko jeden myślnik pod rząd.",
+ "end_with_a_letter_or_digit": "kończyć się literą lub cyfrą.",
+ "verified_exchange_no_memo": "Musisz dodać memo w swoim transferze."
+ },
+ "settings_jsx": {
+ "invalid_url": "Nieprawidłowy URL",
+ "name_is_too_long": "Nazwa jest za długa",
+ "name_must_not_begin_with": "Nazwa nie może zaczynać się od @",
+ "about_is_too_long": "O mnie jest za długie",
+ "location_is_too_long": "Lokalizacja jest za długa",
+ "website_url_is_too_long": "Strona www jest za długa",
+ "public_profile_settings": "Ustawienia profilu publicznego",
+ "preferences": "Prywatne ustawienia wyświetlania postów",
+ "not_safe_for_work_nsfw_content": "Treści niestosowne w pracy (NSFW)",
+ "always_hide": "Zawsze ukrywaj",
+ "always_warn": "Zawsze ostrzegaj",
+ "always_show": "Zawsze pokazuj",
+ "muted_users": "Blokowani użytkownicy",
+ "update": "Aktualizuj",
+ "profile_image_url": "URL obrazka profilowego",
+ "cover_image_url": "URL tła profilowego",
+ "profile_name": "Wyświetlana nazwa",
+ "profile_about": "Opis",
+ "profile_location": "Lokalizacja",
+ "profile_website": "Strona www"
+ },
+ "transfer_jsx": {
+ "amount_is_in_form": "Podana kwota musi być w formacie 99999.999",
+ "insufficient_funds": "Niewystarczające fundusze",
+ "use_only_3_digits_of_precison": "Używaj tylko 3 cyfr po przecinku",
+ "send_to_account": "Wyślij na konto",
+ "asset": "Aktywa",
+ "this_memo_is_private": "To memo jest prywatne",
+ "this_memo_is_public": "To memo jest publiczne",
+ "convert_to_VESTING_TOKEN": "Zamień na %(VESTING_TOKEN)s",
+ "balance_subject_to_3_day_withdraw_waiting_period":
+ "Saldo zależy od 3-dniowego okresu karencji wymaganego do wycofania środków,",
+ "move_funds_to_another_account":
+ "Przenieś fundusze na inne konto %(APP_NAME)s.",
+ "protect_funds_by_requiring_a_3_day_withdraw_waiting_period":
+ "Chroni fundusze poprzez 3-dniowy okres karencji.",
+ "withdraw_funds_after_the_required_3_day_waiting_period":
+ "Wypłata funduszy po 3-dniowym okresie karencji.",
+ "from": "Od",
+ "to": "Do",
+ "asset_currently_collecting":
+ "%(asset)s aktualnie zbierający %(interest)s%% APR."
+ },
+ "userwallet_jsx": {
+ "conversion_complete_tip": "Zakończy się",
+ "in_conversion": "%(amount)s po zamianie",
+ "transfer_to_savings": "Transfer do oszczędności",
+ "power_up": "Zwiększ moc",
+ "power_down": "Zmniejsz moc",
+ "market": "Giełda",
+ "convert_to_LIQUID_TOKEN": "Zamień na %(LIQUID_TOKEN)s",
+ "withdraw_LIQUID_TOKEN": "Wypłać %(LIQUID_TOKEN)s",
+ "withdraw_DEBT_TOKENS": "Wypłać %(DEBT_TOKENS)s",
+ "tokens_worth_about_1_of_LIQUID_TICKER":
+ "Tokeny warte około $1.00 z %(LIQUID_TICKER)s, aktualnie zbierają %(sbdInterest)s%% APR.",
+ "savings": "OSZCZĘDNOŚCI",
+ "estimated_account_value": "Szacowana wartość konta",
+ "next_power_down_is_scheduled_to_happen":
+ "Nastąpi następne zaplanowane zmniejszenie mocy",
+ "transfers_are_temporary_disabled": "Transfery tymczasowo wyłączone.",
+ "history": "HISTORIA",
+ "redeem_rewards": "Odbierz nagrody (transfer do salda)",
+ "buy_steem_or_steem_power": "Kup STEEM lub STEEM POWER"
+ },
+ "powerdown_jsx": {
+ "power_down": "Zmniejsz moc",
+ "amount": "Liczba",
+ "already_power_down":
+ "Aktualnie zmniejszasz moc %(AMOUNT)s %(LIQUID_TICKER)s (%(WITHDRAWN)s %(LIQUID_TICKER)s już wypłacono). Pamiętaj, że jeśli zmienisz ilość zmniejszanej mocy, to licznik dla następnej wypłaty zostanie wyzerowany.",
+ "delegating":
+ "Delegujesz %(AMOUNT)s %(LIQUID_TICKER)s. Kwota ta, jest zablokowana i nie jest dostępna do zmniejszenia mocy, dopóki delegacja się nie zakończy i upłynie pełen okres wypłacania nagród.",
+ "per_week": "To około%(AMOUNT)s %(LIQUID_TICKER)s na tydzień.",
+ "warning":
+ "Pozostawiając mniej niż %(AMOUNT)s %(VESTING_TOKEN)s na koncie, nie jest zalecane i może sprawić że twoje konto nie będzie działać.",
+ "error": "Nie można zmniejszyć mocy (BŁĄD: %(MESSAGE)s)"
+ },
+ "checkloginowner_jsx": {
+ "your_password_permissions_were_reduced":
+ "Twoje uprawnienia zostały zmniejszone",
+ "if_you_did_not_make_this_change":
+ "Jeżeli to nie ty wykonałeś tę zmianę",
+ "ownership_changed_on": "Nastąpiła zmiana właściciela",
+ "deadline_for_recovery_is": "Ostateczny czas na odzyskanie",
+ "i_understand_dont_show_again": "Rozumiem, nie pokazuj mi tego ponownie"
+ }
+}
diff --git a/src/app/locales/ru.json b/src/app/locales/ru.json
index 4fdad0b52576c73c93727356db07ced78a43b8a4..b841e5a4e219c704edbffab7bcd0c4d00c41bcf3 100644
--- a/src/app/locales/ru.json
+++ b/src/app/locales/ru.json
@@ -1,668 +1,798 @@
{
- "g": {
- "age": "возраст",
- "amount": "Количество",
- "and": "и",
- "are_you_sure": "Вы уверены?",
- "ask": "Продажа",
- "balance": "Баланс",
- "balances": "Балансы",
- "bid": "Покупка",
- "blog": "Блог",
- "browse": "Посмотреть",
- "buy": "Купить",
- "buy_or_sell": "Купить или Продать",
- "by": "от",
- "cancel": "Отмена",
- "change_password": "Сменить пароль",
- "choose_language": "Выберите язык",
- "clear": "Очистить",
- "close": "Закрыть",
- "collapse_or_expand": "Свернуть/Развернуть",
- "comments": "Комментарии",
- "confirm": "Подтвердить",
- "convert": "Конвертировать",
- "date": "Дата",
- "delete": "Удалить",
- "dismiss": "Скрыть",
- "edit": "Редактировать",
- "email": "Электронная почта",
- "feed": "Лента",
- "follow": "Подписаться",
- "for": " для ",
- "from": " от ",
- "go_back": "Назад",
- "hide": "Скрыть",
- "in": "в",
- "in_reply_to": "в ответ на",
- "insufficient_balance": "Недостаточный баланс",
- "invalid_amount": "Недостаточно средств",
- "joined": "Присоединился",
- "loading": "Загрузка",
- "login": "Войти",
- "logout": "Выйти",
- "memo": "Примечание",
- "mute": "Заблокировать",
- "new": "новое",
- "newer": "Новее",
- "next": "Следующий",
- "no": "Нет",
- "ok": "ОК",
- "older": "Старее",
- "or": "или",
- "order_placed": "Заказ размещен",
- "password": "Пароль",
- "payouts": "Выплаты",
- "permissions": "Разрешения",
- "phishy_message": "Link expanded to plain text; beware of a potential phishing attempt",
- "post": "Пост",
- "post_as": "Запостить как",
- "posts": "Посты",
- "powered_up_100": "100%% в Силе Голоса",
- "preview": "Предварительный просмотр",
- "previous": "Предыдущий",
- "price": "Цена",
- "print": "Распечатать",
- "promote": "Продвинуть",
- "promoted": "продвигаемое",
- "re": "RE",
- "re_to": "RE: %(topic)s",
- "recent_password": "Недавний пароль",
- "receive": "Получено ",
- "remove": "Удалить",
- "remove_vote": "Убрать голос",
- "replied_to": "ответил %(account)s",
- "replies": "Ответы",
- "reply": "Ответить",
- "reply_count": {
- "zero": "нет ответов",
- "one": "1 ответ",
- "few": "%(count)s ответа",
- "many": "%(count)s ответов",
- "other": "%(count)s ответов"
- },
- "reputation": "Репутация",
- "reveal_comment": "Показать комментарий",
- "request": "запрос",
- "required": "Обязательно",
- "rewards": "вознаграждение",
- "save": "Сохранить",
- "saved": "Сохранено",
- "search": "Поиск",
- "sell": "Продать",
- "settings": "Настройки",
- "share_this_post": "Поделиться этим постом",
- "show": "Показать",
- "sign_in": "Войти",
- "sign_up": "Регистрация",
- "since": "начиная с",
- "submit": "Отправить",
- "power_up": "Усилить силу голоса",
- "submit_a_story": "Добавить пост",
- "tag": "Тег",
- "to": " к ",
- "all_tags": "All tags",
- "transfer": "Перевод ",
- "trending_topics": "Популярное",
- "type": "Тип",
- "unfollow": "Отписаться",
- "unmute": "Разблокировать",
- "unknown": "Неизвестно",
- "upvote": "Голосовать за",
- "upvote_post": "Проголосовать за пост",
- "username": "Имя пользователя",
- "version": "Версия",
- "vote": "Проголосовать",
- "votes": "голосов",
- "wallet": "Кошелек",
- "warning": "внимание",
- "yes": "Да",
- "posting": "Постинг",
- "owner": "Владелец",
- "active": "Активный",
- "account_not_found": "Аккаунт не найден",
- "this_is_wrong_password": "Это неправильный пароль",
- "do_you_need_to": "Вам нужно",
- "account_name": "Имя аккаунта",
- "recover_your_account": "восстановить ваш аккаунт",
- "reset_usernames_password": "Сбросить пароль пользователя %(username)s",
- "this_will_update_usernames_authtype_key": "Это обновит %(username)s %(authType)s ключ",
- "passwords_do_not_match": "Пароли не совпадают",
- "you_need_private_password_or_key_not_a_public_key": "Вам нужен приватный пароль или ключ (не публичный ключ)",
- "the_rules_of_APP_NAME": {
- "one": "Первое правило сети %(APP_NAME)s: не теряйте свой пароль.",
- "second": "Второе правило %(APP_NAME)s: Не теряйте свой пароль.",
- "third": "Третье правило %(APP_NAME)s: мы не можем восстановить ваш пароль.",
- "fourth": "Четвертое правило: если вы можете запомнить свой пароль, значит он не безопасен.",
- "fifth": "Пятое правило: используйте только сгенерированные случайным образом пароли.",
- "sixth": "Шестое правило: Никому не говорите свой пароль.",
- "seventh": "Седьмое правило: Всегда надежно храните свой пароль."
- },
- "recover_password": "Восстановить аккаунт",
- "current_password": "Текущий пароль",
- "generated_password": "Сгенерированный пароль",
- "backup_password_by_storing_it": "Сделайте резервную копию в менеджере паролей или текстовом файле",
- "enter_account_show_password": "Введите действительное имя аккаунта, чтобы показать пароль",
- "click_to_generate_password": "Нажмите, чтобы сгененировать пароль",
- "re_enter_generate_password": "Повторно введите пароль",
- "understand_that_APP_NAME_cannot_recover_password": "Я понимаю, что %(APP_NAME)s не может восстановить потерянные пароли",
- "i_saved_password": "Я надежно сохранил сгенерированный пароль",
- "update_password": "Обновить пароль",
- "confirm_password": "Подтвердить пароль",
- "account_updated": "Аккаунт обновлен",
- "password_must_be_characters_or_more": "Пароль должен содержать %(amount)s символ(а) или больше",
- "need_password_or_key": "Вам нужен приватный пароль или ключ (не публичный ключ)",
- "login_to_see_memo": "войти чтобы увидеть примечание",
- "new_password": "Новый пароль",
- "incorrect_password": "Неправильный пароль",
- "username_does_not_exist": "Имя пользователя не найдено",
- "account_name_should_start_with_a_letter": "Имя аккаунта должно начинаться с буквы.",
- "account_name_should_be_shorter": "Имя аккаунта должно быть короче.",
- "account_name_should_be_longer": "Имя аккаунта должно быть длиннее.",
- "account_name_should_have_only_letters_digits_or_dashes": "Имя аккаунта должно должно состоять только из букв, цифр или дефисов.",
- "cannot_increase_reward_of_post_within_the_last_minute_before_payout": "Не удается увеличить вознаграждение за пост в последнюю минуту перед выплатой",
- "vote_currently_exists_user_must_be_indicate_a_to_reject_witness": "голос уже существует, пользователь должен обозначить желание убрать делегата",
- "only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes": "Только один Steem аккаунт разрешен с одного IP адреса каждые десять минут",
- "resteem_this_post": "Поделиться этим постом",
- "reblog": "Поделиться",
- "write_your_story": "Написать свою историю",
- "remember_voting_and_posting_key": "Запомнить голос и постинг ключ",
- "auto_login_question_mark": "Заходить автоматически?",
- "hide_private_key": "Скрыть приватный ключ",
- "show_private_key": "Показать приватный ключ",
- "login_to_show": "Войти, чтобы показать",
- "not_valid_email": "Не действительный адрес",
- "thank_you_for_being_an_early_visitor_to_APP_NAME": "Благодарим вас за то что являетесь ранним посетителем %(APP_NAME)s. Мы свяжемся с Вами при первой же возможности.",
- "author_rewards": "Авторские вознаграждения",
- "curation_rewards": "Кураторские вознаграждения",
- "sorry_your_reddit_account_doesnt_have_enough_karma": "Извините, у вашего Reddit аккаунта недостаточно Reddit кармы чтобы иметь возможность бесплатной регистрации. Пожалуйста, добавьте вашу электронную почту чтобы записаться в лист ожидания",
- "register_with_facebook": "Регистрация с Facebook",
- "or_click_the_button_below_to_register_with_facebook": "Или нажмите на кнопку ниже, чтобы зарегистрироваться в Facebook",
- "server_returned_error": "ошибка сервера",
- "APP_NAME_support": "%(APP_NAME)s поддержка",
- "please_email_questions_to": "Пожалуйста, шлите ваши вопросы на электронную почту",
- "next_7_strings_single_block": {
- "authors_get_paid_when_people_like_you_upvote_their_post": "Авторы получают вознаграждение, когда пользователи голосуют за их посты",
- "if_you_enjoyed_what_you_read_earn_amount": "Если Вам понравилось то, что Вы здесь прочитали, создайте свой аккаунт сегодня и начните зарабатывать БЕСПЛАТНЫЕ STEEM-ы!",
- "free_steem": "БЕСПЛАТНЫЕ STEEM!",
- "sign_up_earn_steem": "Зарегистрируйтесь сейчас, чтобы заработать "
- },
- "next_3_strings_together": {
- "show_more": "Показать больше",
- "show_less": "Показать меньше",
- "value_posts": "меньше сообщений низкой стоимости"
- },
- "read_only_mode": "По техническим причинам вебсайт доступен только для чтения, приносим свои извинения.",
- "tags_and_topics": "Теги и темы",
- "show_more_topics": "Показать больше тем",
- "basic": "Базовый",
- "advanced": "Подробнее",
- "views": {
- "zero": "Нет просмотров",
- "one": "%(count)s просмотр",
- "few": "%(count)s просмотра",
- "many": "%(count)s просмотров",
- "other": "%(count)s просмотров"
- },
- "responses": {
- "zero": "Нет ответов",
- "one": "%(count)s ответ",
- "few": "%(count)s ответа",
- "many": "%(count)s ответов",
- "other": "%(count)s ответов"
- },
- "post_key_warning": {
- "confirm": "Вы собираетесь опубликовать ваш приватный ключ или мастер-пароль, это может привести к потере вашего акканта и всех средств на нем.",
- "warning": "Если кто-то попросил вас опубликовать или показать ваш приватный ключ, это возможно злоумышленник, который пытается украсть ваши токены.",
- "checkbox": "Я понял"
- }
- },
- "navigation": {
- "about": "О проекте",
- "explore": "Исследовать",
- "APP_NAME_whitepaper": "Белая книга %(APP_NAME)s",
- "buy_LIQUID_TOKEN": "Купить %(LIQUID_TOKEN)s",
- "sell_LIQUID_TOKEN": "Продать %(LIQUID_TOKEN)s",
- "currency_market": "Биржа",
- "stolen_account_recovery": "Восстановление украденного аккаунта",
- "change_account_password": "Изменить пароль аккаунта",
- "witnesses": "Делегаты",
- "vote_for_witnesses": "Проголосовать за делегатов",
- "privacy_policy": "Политика Конфиденциальности",
- "terms_of_service": "Условия пользования",
- "sign_up": "Присоединиться",
- "learn_more": "Документация",
- "welcome": "Добро пожаловать",
- "faq": "ЧаВО",
- "shop": "Магазин Steemit",
- "chat": "Чат Steemit",
- "app_center": "Центр приложений Steemit",
- "api_docs": "API-документация Steemit",
- "bluepaper": "Синяя бумага Steem",
- "whitepaper": "Белая книга Steem",
- "intro_tagline": "Здесь говорят деньги.",
- "intro_paragraph": "Ваше мнение имеет цену. Присоединяйтесь к сообществу, которое платит за контент и за работу по отбору самого лучшего контента."
- },
- "main_menu": {
- "hot": "актуальное",
- "trending": "популярное"
- },
- "reply_editor": {
- "shorten_title": "Сократите заголовок",
- "exceeds_maximum_length": "Превышает максимальную длину (%(maxKb)sKB)",
- "including_the_category": "(включая категорию «%(rootCategory)s»)",
- "use_limited_amount_of_tags": "У вас %(tagsLength)s тегов, включая %(includingCategory)s. Пожалуйста, используйте не более 5 в посте и категории.",
- "are_you_sure_you_want_to_clear_this_form": "Вы уверены, что вы хотите очистить эту форму?",
- "uploading": "Загрузка",
- "draft_saved": "Черновик сохранен.",
- "editor": "Редактор",
- "insert_images_by_dragging_dropping": "Вставьте изображения, перетащив их, ",
- "pasting_from_the_clipboard": "или вставив из буфера обмена, ",
- "selecting_them": "выбрав их",
- "image_upload": "Загрузка изображения",
- "power_up_100": "Сила Голоса 100%%",
- "default_50_50": "По умолчанию (50%% / 50%%)",
- "decline_payout": "Отказаться от выплаты",
- "check_this_to_auto_upvote_your_post": "Отметьте, чтобы проголосовать за свой пост",
- "markdown_styling_guide": "Руководство стилизации в Markdown",
- "or_by": "или",
- "title": "Заголовок",
- "update_post": "Update Post",
- "markdown_not_supported": "Markdown здесь не поддерживается"
- },
- "category_selector_jsx": {
- "tag_your_story": "Добавь теги (до 5 штук), первый тег станет основной категорией.",
- "select_a_tag": "Выбрать тег",
- "maximum_tag_length_is_24_characters": "Максимальная длина категории 24 знака",
- "use_limited_amount_of_categories": "Пожалуйста, используйте только %(amount)s категории",
- "use_only_lowercase_letters": "Используйте только символы нижнего регистра",
- "use_one_dash": "Используйте только одно тире",
- "use_spaces_to_separate_tags": "Используйте пробел чтобы разделить теги",
- "use_only_allowed_characters": "Используйте только строчные буквы, цифры и одно тире",
- "must_start_with_a_letter": "Должно начинаться с буквы",
- "must_end_with_a_letter_or_number": "Должно заканчиваться с буквы или номера"
- },
- "postfull_jsx": {
- "this_post_is_not_available_due_to_a_copyright_claim": "Этот пост недоступен из-за жалобы о нарушении авторских прав.",
- "share_on_facebook": "Поделитесь в Facebook",
- "share_on_twitter": "Поделиться в Twitter",
- "share_on_linkedin": "Поделиться в Linkedin",
- "recent_password": "Недавний пароль",
- "in_week_convert_DEBT_TOKEN_to_LIQUID_TOKEN": "В 3,5 дня перевести %(amount)s %(DEBT_TOKEN)s в %(LIQUID_TOKEN)s",
- "view_the_full_context": "Показать полный контекст",
- "view_the_direct_parent": "Просмотр прямого родителя",
- "you_are_viewing_a_single_comments_thread_from": "Вы читаете одну нить комментариев от"
- },
- "market_jsx": {
- "action": "Действие",
- "date_created": "Дата создания",
- "last_price": "Последняя цена",
- "24h_volume": "Объем за 24 часа",
- "spread": "Спред",
- "total": "Итого",
- "available": "Доступно",
- "lowest_ask": "Лучшая цена продажи",
- "highest_bid": "Лучшая цена покупки",
- "buy_orders": "Заказы на покупку",
- "sell_orders": "Заказы на продажу",
- "trade_history": "История сделок",
- "open_orders": "Открытые сделки",
- "sell_amount_for_atleast": "Продать %(amount_to_sell)s за %(min_to_receive)s по цене (%(effectivePrice)s)",
- "buy_atleast_amount_for": "Купить по крайней мере %(min_to_receive)s за %(amount_to_sell)s (%(effectivePrice)s)",
- "price_warning_above": "Эта цена намного выше текущей рыночной цены %(marketPrice)s, вы уверены?",
- "price_warning_below": "Эта цена намного выше текущей рыночной цены %(marketPrice)s, вы уверены?",
- "order_cancel_confirm": "Отменить заказ %(order_id)s от %(user)s?",
- "order_cancelled": "Заказ %(order_id)s отменен.",
- "higher": "Дороже",
- "lower": "Дешевле",
- "total_DEBT_TOKEN_SHORT_CURRENCY_SIGN": "Сумма %(DEBT_TOKEN_SHORT)s (%(CURRENCY_SIGN)s)"
- },
- "recoveraccountstep1_jsx": {
- "begin_recovery": "Начать восстановление",
- "not_valid": "Недействительно",
- "account_name_is_not_found": "Имя аккаунта не найдено",
- "unable_to_recover_account_not_change_ownership_recently": "Мы не можем восстановить эту учетную запись, она не изменила владельца в последнее время.",
- "password_not_used_in_last_days": "Этот пароль не использовался в этой учетной записи за последние 30 дней.",
- "request_already_submitted_contact_support": "Ваш запрос был отправлен, и мы работаем над этим. Пожалуйста, свяжитесь с %(SUPPORT_EMAIL)s для получения статуса вашего запроса.",
- "recover_account_intro": "Иногда бывает что ключ владельца может быть скомпрометирован. Восстановление украденного аккаунта дает законному владельцу 30 дней чтобы вернуть аккаунт с момента изменения владельческого ключа мошенником. Восстановление украденного аккаунта в %(APP_URL)s возможно только если владелец аккаунта ранее указал %(APP_NAME)s's в качестве доверенного лица и согласился с Условиями Использования сайта %(APP_NAME)s's.",
- "login_with_facebook_or_reddit_media_to_verify_identity": "Пожалуйста, войдите используя Facebook или Reddit для подтверждения вашей личности",
- "login_with_social_media_to_verify_identity": "Пожалуйста, войдите используя %(provider)s для подтверждения вашей личности",
- "enter_email_toverify_identity": "Нам нужно подтвердить вашу личность. Пожалуйста, укажите вашу электронную почту ниже для начала проверки.",
- "continue_with_email": "Продолжить с электронной почтой",
- "thanks_for_submitting_request_for_account_recovery": "Благодарим Вас за отправку запроса на восстановление аккаунта используя основанную на блокчейне мультифакторную аутентификацию %(APP_NAME)s’a.
Мы ответим Вам как можно быстрее, однако, пожалуйста, ожидайте что может быть некоторая задержка из-за большого объема писем.
Пожалуйста, будьте готовы подтвердить свою личность.
С уважением,
Ned Scott
CEO Steemit
",
- "recovering_account": "Восстанавливаем аккаунт",
- "recover_account": "Восстановить аккаунт",
- "checking_account_owner": "Проверяем владельца аккаунта",
- "sending_recovery_request": "Отправляем запрос восстановления",
- "cant_confirm_account_ownership": "Мы не можем подтвердить владение аккаунтом. Проверьте ваш пароль",
- "account_recovery_request_not_confirmed": "Запрос восстановления аккаунта еще не подтвержден, пожалуйста проверьте позднее. Спасибо за ваше терпение."
- },
- "user_profile": {
- "unknown_account": "Неизвестный аккаунт",
- "user_hasnt_made_any_posts_yet": "Похоже, что %(name)s еще не написал постов!",
- "user_hasnt_started_bloggin_yet": "Похоже. что %(name)s еще не завёл блог!",
- "user_hasnt_followed_anything_yet": "Похоже, что %(name)s еще ни на кого не подписан! Если, %(name)s недавно подписался на новых пользователей, их персонализированный канал будет заполняться сразу после появления нового контента.",
- "user_hasnt_had_any_replies_yet": "%(name)s еще не получил ответов",
- "looks_like_you_havent_posted_anything_yet": "Похоже, ты еще ничего не опубликовал.",
- "create_a_post": "Создать сообщение",
- "explore_trending_articles": "Посмотреть статьи, набирающие популярность",
- "read_the_quick_start_guide": "Прочтите краткое руководство",
- "browse_the_faq": "Просмотреть ЧаВО",
- "followers": "Подписчики",
- "this_is_users_reputations_score_it_is_based_on_history_of_votes": "Это репутация %(name)s.\n\nРепутация рассчитывается на основе истории полученных голосов и используется для сокрытия низкокачественного контента.",
- "follower_count": {
- "zero": "Нет подписчиков",
- "one": "1 подписчик",
- "few": "%(count)s подписчика",
- "many": "%(count)s подписчиков",
- "other": "%(count)s подписчиков"
- },
- "followed_count": {
- "zero": "Ни на кого не подписан",
- "one": "1 подписок",
- "few": "%(count)s подписки",
- "many": "%(count)s подписок",
- "other": "%(count)s подписок"
- },
- "post_count": {
- "zero": "Постов нет",
- "one": "1 пост",
- "few": "%(count)s поста",
- "many": "%(count)s постов",
- "other": "%(count)s постов"
- }
- },
- "authorrewards_jsx": {
- "estimated_author_rewards_last_week": "Оценочные авторские вознаграждения за прошлую неделю",
- "author_rewards_history": "История авторских наград"
- },
- "curationrewards_jsx": {
- "estimated_curation_rewards_last_week": "Оценочные кураторские вознаграждения за последнюю неделю",
- "curation_rewards_history": "История кураторских наград"
- },
- "post_jsx": {
- "now_showing_comments_with_low_ratings": "Отображаем комментарии с низким рейтингом",
- "sort_order": "Порядок сортировки",
- "comments_were_hidden_due_to_low_ratings": "Комментарии были скрыты из-за низкого рейтинга"
- },
- "voting_jsx": {
- "flagging_post_can_remove_rewards_the_flag_should_be_used_for_the_following": "Голосование против уменьшает вознаграждение и снижает позицию в рейтинге.",
- "disagreement_on_rewards": "Несогласие с вознаграждением",
- "fraud_or_plagiarism": "Мошенничество или плагиат",
- "hate_speech_or_internet_trolling": "Разжигание ненависти или Интернет троллинг",
- "intentional_miss_categorized_content_or_spam": "Преднамеренная неправильная категоризация контента или спам",
- "pending_payout": "Ожидаемая выплата",
- "payout_declined": "Автор отказался от вознаграждения",
- "max_accepted_payout": "Максимально допустимое вознаграждение: $%(value)s",
- "promotion_cost": "Цена продвижения: $%(value)s",
- "past_payouts": "Предыдущие выплаты $%(value)s",
- "past_payouts_author": " - Авторские $%(value)s",
- "past_payouts_curators": " - Кураторские $%(value)s",
- "we_will_reset_curation_rewards_for_this_post": "это сбросит выплаты за курирование",
- "removing_your_vote": "Удаление голоса",
- "changing_to_an_upvote": "Изменить на голосование 'за'",
- "changing_to_a_downvote": "Изменить на голосование 'против'",
- "confirm_flag": "Подтвердить голос 'против'",
- "and_more": "и %(count)s больше",
- "votes_plural": {
- "one": "%(count)s голоса",
- "few": "%(count)s голоса",
- "many": "%(count)s голосов",
- "other": "%(count)s голосов"
- }
- },
- "witnesses_jsx": {
- "witness_thread": "пост делегата",
- "top_witnesses": "Топ делегатов",
- "you_have_votes_remaining": {
- "zero": "У Вас не осталось голосов",
- "one": "У Вас остался 1 голос",
- "few": "У Вас осталось %(count)s голоса",
- "many": "У Вас осталось %(count)s голосов",
- "other": "У Вас осталось %(count)s голосов"
- },
- "you_can_vote_for_maximum_of_witnesses": "Вы можете голосовать максимум за 30 делегатов",
- "witness": "Делегаты",
- "information": "Информация",
- "if_you_want_to_vote_outside_of_top_enter_account_name": "Если вы хотите проголосовать за делегата вне top 50, введите имя аккаунта ниже",
- "set_witness_proxy": "Вы также можете выбрать прокси, который будет вместо вас голосовать за делегатов. Это сбросит ваш текущий выбор делегата.",
- "witness_set": "Вы установили прокси для голосования. Если вы хотите голосовать вручную, пожалуйста, очистите ваш прокси.",
- "witness_proxy_current": "Ваш текущий прокси",
- "witness_proxy_set": "Установить прокси",
- "witness_proxy_clear": "Очистить прокси",
- "proxy_update_error": "Ваш прокси не был обновлен"
- },
- "votesandcomments_jsx": {
- "no_responses_yet_click_to_respond": "Ответов пока нет. Нажмите чтобы ответить.",
- "response_count_tooltip": {
- "zero": "ответов пока нет. Нажмите чтобы ответить.",
- "one": "1 ответ. Нажмите чтобы ответить.",
- "few": "%(count)s ответа. Нажмите чтобы ответить.",
- "many": "%(count)s ответов. Нажмите чтобы ответить.",
- "other": "%(count)s ответов. Нажмите чтобы ответить."
- },
- "vote_count": {
- "zero": "нет голосов",
- "one": "1 голос",
- "few": "%(count)s голоса",
- "many": "%(count)s голосов",
- "other": "%(count)s голосов"
+ "g": {
+ "age": "возраст",
+ "amount": "Количество",
+ "and": "и",
+ "are_you_sure": "Вы уверены?",
+ "ask": "Продажа",
+ "balance": "Баланс",
+ "balances": "Балансы",
+ "bid": "Покупка",
+ "blog": "Блог",
+ "browse": "Посмотреть",
+ "buy": "Купить",
+ "buy_or_sell": "Купить или Продать",
+ "by": "от",
+ "cancel": "Отмена",
+ "change_password": "Сменить пароль",
+ "choose_language": "Выберите язык",
+ "clear": "Очистить",
+ "close": "Закрыть",
+ "collapse_or_expand": "Свернуть/Развернуть",
+ "comments": "Комментарии",
+ "confirm": "Подтвердить",
+ "convert": "Конвертировать",
+ "date": "Дата",
+ "delete": "Удалить",
+ "dismiss": "Скрыть",
+ "edit": "Редактировать",
+ "email": "Электронная почта",
+ "feed": "Лента",
+ "follow": "Подписаться",
+ "for": " для ",
+ "from": " от ",
+ "go_back": "Назад",
+ "hide": "Скрыть",
+ "in": "в",
+ "in_reply_to": "в ответ на",
+ "insufficient_balance": "Недостаточный баланс",
+ "invalid_amount": "Недостаточно средств",
+ "joined": "Присоединился",
+ "loading": "Загрузка",
+ "login": "Войти",
+ "logout": "Выйти",
+ "memo": "Примечание",
+ "mute": "Заблокировать",
+ "new": "новое",
+ "newer": "Новее",
+ "next": "Следующий",
+ "no": "Нет",
+ "ok": "ОК",
+ "older": "Старее",
+ "or": "или",
+ "order_placed": "Заказ размещен",
+ "password": "Пароль",
+ "payouts": "Выплаты",
+ "permissions": "Разрешения",
+ "phishy_message":
+ "Link expanded to plain text; beware of a potential phishing attempt",
+ "post": "Пост",
+ "post_as": "Запостить как",
+ "posts": "Посты",
+ "powered_up_100": "100%% в Силе Голоса",
+ "preview": "Предварительный просмотр",
+ "previous": "Предыдущий",
+ "price": "Цена",
+ "print": "Распечатать",
+ "promote": "Продвинуть",
+ "promoted": "продвигаемое",
+ "re": "RE",
+ "re_to": "RE: %(topic)s",
+ "recent_password": "Недавний пароль",
+ "receive": "Получено ",
+ "remove": "Удалить",
+ "remove_vote": "Убрать голос",
+ "replied_to": "ответил %(account)s",
+ "replies": "Ответы",
+ "reply": "Ответить",
+ "reply_count": {
+ "zero": "нет ответов",
+ "one": "1 ответ",
+ "few": "%(count)s ответа",
+ "many": "%(count)s ответов",
+ "other": "%(count)s ответов"
+ },
+ "reputation": "Репутация",
+ "reveal_comment": "Показать комментарий",
+ "request": "запрос",
+ "required": "Обязательно",
+ "rewards": "вознаграждение",
+ "save": "Сохранить",
+ "saved": "Сохранено",
+ "search": "Поиск",
+ "sell": "Продать",
+ "settings": "Настройки",
+ "share_this_post": "Поделиться этим постом",
+ "show": "Показать",
+ "sign_in": "Войти",
+ "sign_up": "Регистрация",
+ "since": "начиная с",
+ "submit": "Отправить",
+ "power_up": "Усилить силу голоса",
+ "submit_a_story": "Добавить пост",
+ "tag": "Тег",
+ "to": " к ",
+ "all_tags": "All tags",
+ "transfer": "Перевод ",
+ "trending_topics": "Популярное",
+ "type": "Тип",
+ "unfollow": "Отписаться",
+ "unmute": "Разблокировать",
+ "unknown": "Неизвестно",
+ "upvote": "Голосовать за",
+ "upvote_post": "Проголосовать за пост",
+ "username": "Имя пользователя",
+ "version": "Версия",
+ "vote": "Проголосовать",
+ "votes": "голосов",
+ "wallet": "Кошелек",
+ "warning": "внимание",
+ "yes": "Да",
+ "posting": "Постинг",
+ "owner": "Владелец",
+ "active": "Активный",
+ "account_not_found": "Аккаунт не найден",
+ "this_is_wrong_password": "Это неправильный пароль",
+ "do_you_need_to": "Вам нужно",
+ "account_name": "Имя аккаунта",
+ "recover_your_account": "восстановить ваш аккаунт",
+ "reset_usernames_password": "Сбросить пароль пользователя %(username)s",
+ "this_will_update_usernames_authtype_key":
+ "Это обновит %(username)s %(authType)s ключ",
+ "passwords_do_not_match": "Пароли не совпадают",
+ "you_need_private_password_or_key_not_a_public_key":
+ "Вам нужен приватный пароль или ключ (не публичный ключ)",
+ "the_rules_of_APP_NAME": {
+ "one": "Первое правило сети %(APP_NAME)s: не теряйте свой пароль.",
+ "second": "Второе правило %(APP_NAME)s: Не теряйте свой пароль.",
+ "third":
+ "Третье правило %(APP_NAME)s: мы не можем восстановить ваш пароль.",
+ "fourth":
+ "Четвертое правило: если вы можете запомнить свой пароль, значит он не безопасен.",
+ "fifth":
+ "Пятое правило: используйте только сгенерированные случайным образом пароли.",
+ "sixth": "Шестое правило: Никому не говорите свой пароль.",
+ "seventh": "Седьмое правило: Всегда надежно храните свой пароль."
+ },
+ "recover_password": "Восстановить аккаунт",
+ "current_password": "Текущий пароль",
+ "generated_password": "Сгенерированный пароль",
+ "backup_password_by_storing_it":
+ "Сделайте резервную копию в менеджере паролей или текстовом файле",
+ "enter_account_show_password":
+ "Введите действительное имя аккаунта, чтобы показать пароль",
+ "click_to_generate_password": "Нажмите, чтобы сгененировать пароль",
+ "re_enter_generate_password": "Повторно введите пароль",
+ "understand_that_APP_NAME_cannot_recover_password":
+ "Я понимаю, что %(APP_NAME)s не может восстановить потерянные пароли",
+ "i_saved_password": "Я надежно сохранил сгенерированный пароль",
+ "update_password": "Обновить пароль",
+ "confirm_password": "Подтвердить пароль",
+ "account_updated": "Аккаунт обновлен",
+ "password_must_be_characters_or_more":
+ "Пароль должен содержать %(amount)s символ(а) или больше",
+ "need_password_or_key":
+ "Вам нужен приватный пароль или ключ (не публичный ключ)",
+ "login_to_see_memo": "войти чтобы увидеть примечание",
+ "new_password": "Новый пароль",
+ "incorrect_password": "Неправильный пароль",
+ "username_does_not_exist": "Имя пользователя не найдено",
+ "account_name_should_start_with_a_letter":
+ "Имя аккаунта должно начинаться с буквы.",
+ "account_name_should_be_shorter": "Имя аккаунта должно быть короче.",
+ "account_name_should_be_longer": "Имя аккаунта должно быть длиннее.",
+ "account_name_should_have_only_letters_digits_or_dashes":
+ "Имя аккаунта должно должно состоять только из букв, цифр или дефисов.",
+ "cannot_increase_reward_of_post_within_the_last_minute_before_payout":
+ "Не удается увеличить вознаграждение за пост в последнюю минуту перед выплатой",
+ "vote_currently_exists_user_must_be_indicate_a_to_reject_witness":
+ "голос уже существует, пользователь должен обозначить желание убрать делегата",
+ "only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes":
+ "Только один Steem аккаунт разрешен с одного IP адреса каждые десять минут",
+ "resteem_this_post": "Поделиться этим постом",
+ "reblog": "Поделиться",
+ "write_your_story": "Написать свою историю",
+ "remember_voting_and_posting_key": "Запомнить голос и постинг ключ",
+ "auto_login_question_mark": "Заходить автоматически?",
+ "hide_private_key": "Скрыть приватный ключ",
+ "show_private_key": "Показать приватный ключ",
+ "login_to_show": "Войти, чтобы показать",
+ "not_valid_email": "Не действительный адрес",
+ "thank_you_for_being_an_early_visitor_to_APP_NAME":
+ "Благодарим вас за то что являетесь ранним посетителем %(APP_NAME)s. Мы свяжемся с Вами при первой же возможности.",
+ "author_rewards": "Авторские вознаграждения",
+ "curation_rewards": "Кураторские вознаграждения",
+ "sorry_your_reddit_account_doesnt_have_enough_karma":
+ "Извините, у вашего Reddit аккаунта недостаточно Reddit кармы чтобы иметь возможность бесплатной регистрации. Пожалуйста, добавьте вашу электронную почту чтобы записаться в лист ожидания",
+ "register_with_facebook": "Регистрация с Facebook",
+ "or_click_the_button_below_to_register_with_facebook":
+ "Или нажмите на кнопку ниже, чтобы зарегистрироваться в Facebook",
+ "server_returned_error": "ошибка сервера",
+ "APP_NAME_support": "%(APP_NAME)s поддержка",
+ "please_email_questions_to":
+ "Пожалуйста, шлите ваши вопросы на электронную почту",
+ "next_7_strings_single_block": {
+ "authors_get_paid_when_people_like_you_upvote_their_post":
+ "Авторы получают вознаграждение, когда пользователи голосуют за их посты",
+ "if_you_enjoyed_what_you_read_earn_amount":
+ "Если Вам понравилось то, что Вы здесь прочитали, создайте свой аккаунт сегодня и начните зарабатывать БЕСПЛАТНЫЕ STEEM-ы!",
+ "free_steem": "БЕСПЛАТНЫЕ STEEM!",
+ "sign_up_earn_steem": "Зарегистрируйтесь сейчас, чтобы заработать "
+ },
+ "next_3_strings_together": {
+ "show_more": "Показать больше",
+ "show_less": "Показать меньше",
+ "value_posts": "меньше сообщений низкой стоимости"
+ },
+ "read_only_mode":
+ "По техническим причинам вебсайт доступен только для чтения, приносим свои извинения.",
+ "tags_and_topics": "Теги и темы",
+ "show_more_topics": "Показать больше тем",
+ "basic": "Базовый",
+ "advanced": "Подробнее",
+ "views": {
+ "zero": "Нет просмотров",
+ "one": "%(count)s просмотр",
+ "few": "%(count)s просмотра",
+ "many": "%(count)s просмотров",
+ "other": "%(count)s просмотров"
+ },
+ "responses": {
+ "zero": "Нет ответов",
+ "one": "%(count)s ответ",
+ "few": "%(count)s ответа",
+ "many": "%(count)s ответов",
+ "other": "%(count)s ответов"
+ },
+ "post_key_warning": {
+ "confirm":
+ "Вы собираетесь опубликовать ваш приватный ключ или мастер-пароль, это может привести к потере вашего акканта и всех средств на нем.",
+ "warning":
+ "Если кто-то попросил вас опубликовать или показать ваш приватный ключ, это возможно злоумышленник, который пытается украсть ваши токены.",
+ "checkbox": "Я понял"
+ }
+ },
+ "navigation": {
+ "about": "О проекте",
+ "explore": "Исследовать",
+ "APP_NAME_whitepaper": "Белая книга %(APP_NAME)s",
+ "buy_LIQUID_TOKEN": "Купить %(LIQUID_TOKEN)s",
+ "sell_LIQUID_TOKEN": "Продать %(LIQUID_TOKEN)s",
+ "currency_market": "Биржа",
+ "stolen_account_recovery": "Восстановление украденного аккаунта",
+ "change_account_password": "Изменить пароль аккаунта",
+ "witnesses": "Делегаты",
+ "vote_for_witnesses": "Проголосовать за делегатов",
+ "privacy_policy": "Политика Конфиденциальности",
+ "terms_of_service": "Условия пользования",
+ "sign_up": "Присоединиться",
+ "learn_more": "Документация",
+ "welcome": "Добро пожаловать",
+ "faq": "ЧаВО",
+ "shop": "Магазин Steemit",
+ "chat": "Чат Steemit",
+ "app_center": "Центр приложений Steemit",
+ "api_docs": "API-документация Steemit",
+ "bluepaper": "Синяя бумага Steem",
+ "smt_whitepaper": "Белая книга SMT",
+ "whitepaper": "Белая книга Steem",
+ "intro_tagline": "Здесь говорят деньги.",
+ "intro_paragraph":
+ "Ваше мнение имеет цену. Присоединяйтесь к сообществу, которое платит за контент и за работу по отбору самого лучшего контента."
+ },
+ "main_menu": {
+ "hot": "актуальное",
+ "trending": "популярное"
+ },
+ "reply_editor": {
+ "shorten_title": "Сократите заголовок",
+ "exceeds_maximum_length": "Превышает максимальную длину (%(maxKb)sKB)",
+ "including_the_category": "(включая категорию «%(rootCategory)s»)",
+ "use_limited_amount_of_tags":
+ "У вас %(tagsLength)s тегов, включая %(includingCategory)s. Пожалуйста, используйте не более 5 в посте и категории.",
+ "are_you_sure_you_want_to_clear_this_form":
+ "Вы уверены, что вы хотите очистить эту форму?",
+ "uploading": "Загрузка",
+ "draft_saved": "Черновик сохранен.",
+ "editor": "Редактор",
+ "insert_images_by_dragging_dropping":
+ "Вставьте изображения, перетащив их, ",
+ "pasting_from_the_clipboard": "или вставив из буфера обмена, ",
+ "selecting_them": "выбрав их",
+ "image_upload": "Загрузка изображения",
+ "power_up_100": "Сила Голоса 100%%",
+ "default_50_50": "По умолчанию (50%% / 50%%)",
+ "decline_payout": "Отказаться от выплаты",
+ "check_this_to_auto_upvote_your_post":
+ "Отметьте, чтобы проголосовать за свой пост",
+ "markdown_styling_guide": "Руководство стилизации в Markdown",
+ "or_by": "или",
+ "title": "Заголовок",
+ "update_post": "Update Post",
+ "markdown_not_supported": "Markdown здесь не поддерживается"
+ },
+ "category_selector_jsx": {
+ "tag_your_story":
+ "Добавь теги (до 5 штук), первый тег станет основной категорией.",
+ "select_a_tag": "Выбрать тег",
+ "maximum_tag_length_is_24_characters":
+ "Максимальная длина категории 24 знака",
+ "use_limited_amount_of_categories":
+ "Пожалуйста, используйте только %(amount)s категории",
+ "use_only_lowercase_letters":
+ "Используйте только символы нижнего регистра",
+ "use_one_dash": "Используйте только одно тире",
+ "use_spaces_to_separate_tags":
+ "Используйте пробел чтобы разделить теги",
+ "use_only_allowed_characters":
+ "Используйте только строчные буквы, цифры и одно тире",
+ "must_start_with_a_letter": "Должно начинаться с буквы",
+ "must_end_with_a_letter_or_number":
+ "Должно заканчиваться с буквы или номера"
+ },
+ "postfull_jsx": {
+ "this_post_is_not_available_due_to_a_copyright_claim":
+ "Этот пост недоступен из-за жалобы о нарушении авторских прав.",
+ "share_on_facebook": "Поделитесь в Facebook",
+ "share_on_twitter": "Поделиться в Twitter",
+ "share_on_linkedin": "Поделиться в Linkedin",
+ "recent_password": "Недавний пароль",
+ "in_week_convert_DEBT_TOKEN_to_LIQUID_TOKEN":
+ "В 3,5 дня перевести %(amount)s %(DEBT_TOKEN)s в %(LIQUID_TOKEN)s",
+ "view_the_full_context": "Показать полный контекст",
+ "view_the_direct_parent": "Просмотр прямого родителя",
+ "you_are_viewing_a_single_comments_thread_from":
+ "Вы читаете одну нить комментариев от"
+ },
+ "market_jsx": {
+ "action": "Действие",
+ "date_created": "Дата создания",
+ "last_price": "Последняя цена",
+ "24h_volume": "Объем за 24 часа",
+ "spread": "Спред",
+ "total": "Итого",
+ "available": "Доступно",
+ "lowest_ask": "Лучшая цена продажи",
+ "highest_bid": "Лучшая цена покупки",
+ "buy_orders": "Заказы на покупку",
+ "sell_orders": "Заказы на продажу",
+ "trade_history": "История сделок",
+ "open_orders": "Открытые сделки",
+ "sell_amount_for_atleast":
+ "Продать %(amount_to_sell)s за %(min_to_receive)s по цене (%(effectivePrice)s)",
+ "buy_atleast_amount_for":
+ "Купить по крайней мере %(min_to_receive)s за %(amount_to_sell)s (%(effectivePrice)s)",
+ "price_warning_above":
+ "Эта цена намного выше текущей рыночной цены %(marketPrice)s, вы уверены?",
+ "price_warning_below":
+ "Эта цена намного выше текущей рыночной цены %(marketPrice)s, вы уверены?",
+ "order_cancel_confirm": "Отменить заказ %(order_id)s от %(user)s?",
+ "order_cancelled": "Заказ %(order_id)s отменен.",
+ "higher": "Дороже",
+ "lower": "Дешевле",
+ "total_DEBT_TOKEN_SHORT_CURRENCY_SIGN":
+ "Сумма %(DEBT_TOKEN_SHORT)s (%(CURRENCY_SIGN)s)"
+ },
+ "recoveraccountstep1_jsx": {
+ "begin_recovery": "Начать восстановление",
+ "not_valid": "Недействительно",
+ "account_name_is_not_found": "Имя аккаунта не найдено",
+ "unable_to_recover_account_not_change_ownership_recently":
+ "Мы не можем восстановить эту учетную запись, она не изменила владельца в последнее время.",
+ "password_not_used_in_last_days":
+ "Этот пароль не использовался в этой учетной записи за последние 30 дней.",
+ "request_already_submitted_contact_support":
+ "Ваш запрос был отправлен, и мы работаем над этим. Пожалуйста, свяжитесь с %(SUPPORT_EMAIL)s для получения статуса вашего запроса.",
+ "recover_account_intro":
+ "Иногда бывает что ключ владельца может быть скомпрометирован. Восстановление украденного аккаунта дает законному владельцу 30 дней чтобы вернуть аккаунт с момента изменения владельческого ключа мошенником. Восстановление украденного аккаунта в %(APP_URL)s возможно только если владелец аккаунта ранее указал %(APP_NAME)s's в качестве доверенного лица и согласился с Условиями Использования сайта %(APP_NAME)s's.",
+ "login_with_facebook_or_reddit_media_to_verify_identity":
+ "Пожалуйста, войдите используя Facebook или Reddit для подтверждения вашей личности",
+ "login_with_social_media_to_verify_identity":
+ "Пожалуйста, войдите используя %(provider)s для подтверждения вашей личности",
+ "enter_email_toverify_identity":
+ "Нам нужно подтвердить вашу личность. Пожалуйста, укажите вашу электронную почту ниже для начала проверки.",
+ "continue_with_email": "Продолжить с электронной почтой",
+ "thanks_for_submitting_request_for_account_recovery":
+ "Благодарим Вас за отправку запроса на восстановление аккаунта используя основанную на блокчейне мультифакторную аутентификацию %(APP_NAME)s’a.
Мы ответим Вам как можно быстрее, однако, пожалуйста, ожидайте что может быть некоторая задержка из-за большого объема писем.
Пожалуйста, будьте готовы подтвердить свою личность.
С уважением,
Ned Scott
CEO Steemit
",
+ "recovering_account": "Восстанавливаем аккаунт",
+ "recover_account": "Восстановить аккаунт",
+ "checking_account_owner": "Проверяем владельца аккаунта",
+ "sending_recovery_request": "Отправляем запрос восстановления",
+ "cant_confirm_account_ownership":
+ "Мы не можем подтвердить владение аккаунтом. Проверьте ваш пароль",
+ "account_recovery_request_not_confirmed":
+ "Запрос восстановления аккаунта еще не подтвержден, пожалуйста проверьте позднее. Спасибо за ваше терпение."
+ },
+ "user_profile": {
+ "unknown_account": "Неизвестный аккаунт",
+ "user_hasnt_made_any_posts_yet":
+ "Похоже, что %(name)s еще не написал постов!",
+ "user_hasnt_started_bloggin_yet":
+ "Похоже. что %(name)s еще не завёл блог!",
+ "user_hasnt_followed_anything_yet":
+ "Похоже, что %(name)s еще ни на кого не подписан! Если, %(name)s недавно подписался на новых пользователей, их персонализированный канал будет заполняться сразу после появления нового контента.",
+ "user_hasnt_had_any_replies_yet": "%(name)s еще не получил ответов",
+ "looks_like_you_havent_posted_anything_yet":
+ "Похоже, ты еще ничего не опубликовал.",
+ "create_a_post": "Создать сообщение",
+ "explore_trending_articles":
+ "Посмотреть статьи, набирающие популярность",
+ "read_the_quick_start_guide": "Прочтите краткое руководство",
+ "browse_the_faq": "Просмотреть ЧаВО",
+ "followers": "Подписчики",
+ "this_is_users_reputations_score_it_is_based_on_history_of_votes":
+ "Это репутация %(name)s.\n\nРепутация рассчитывается на основе истории полученных голосов и используется для сокрытия низкокачественного контента.",
+ "follower_count": {
+ "zero": "Нет подписчиков",
+ "one": "1 подписчик",
+ "few": "%(count)s подписчика",
+ "many": "%(count)s подписчиков",
+ "other": "%(count)s подписчиков"
+ },
+ "followed_count": {
+ "zero": "Ни на кого не подписан",
+ "one": "1 подписок",
+ "few": "%(count)s подписки",
+ "many": "%(count)s подписок",
+ "other": "%(count)s подписок"
+ },
+ "post_count": {
+ "zero": "Постов нет",
+ "one": "1 пост",
+ "few": "%(count)s поста",
+ "many": "%(count)s постов",
+ "other": "%(count)s постов"
+ }
+ },
+ "authorrewards_jsx": {
+ "estimated_author_rewards_last_week":
+ "Оценочные авторские вознаграждения за прошлую неделю",
+ "author_rewards_history": "История авторских наград"
+ },
+ "curationrewards_jsx": {
+ "estimated_curation_rewards_last_week":
+ "Оценочные кураторские вознаграждения за последнюю неделю",
+ "curation_rewards_history": "История кураторских наград"
+ },
+ "post_jsx": {
+ "now_showing_comments_with_low_ratings":
+ "Отображаем комментарии с низким рейтингом",
+ "sort_order": "Порядок сортировки",
+ "comments_were_hidden_due_to_low_ratings":
+ "Комментарии были скрыты из-за низкого рейтинга"
+ },
+ "voting_jsx": {
+ "flagging_post_can_remove_rewards_the_flag_should_be_used_for_the_following":
+ "Голосование против уменьшает вознаграждение и снижает позицию в рейтинге.",
+ "disagreement_on_rewards": "Несогласие с вознаграждением",
+ "fraud_or_plagiarism": "Мошенничество или плагиат",
+ "hate_speech_or_internet_trolling":
+ "Разжигание ненависти или Интернет троллинг",
+ "intentional_miss_categorized_content_or_spam":
+ "Преднамеренная неправильная категоризация контента или спам",
+ "pending_payout": "Ожидаемая выплата $%(value)s",
+ "payout_declined": "Автор отказался от вознаграждения",
+ "max_accepted_payout":
+ "Максимально допустимое вознаграждение: $%(value)s",
+ "promotion_cost": "Цена продвижения: $%(value)s",
+ "past_payouts": "Предыдущие выплаты $%(value)s",
+ "past_payouts_author": " - Авторские $%(value)s",
+ "past_payouts_curators": " - Кураторские $%(value)s",
+ "we_will_reset_curation_rewards_for_this_post":
+ "это сбросит выплаты за курирование",
+ "removing_your_vote": "Удаление голоса",
+ "changing_to_an_upvote": "Изменить на голосование 'за'",
+ "changing_to_a_downvote": "Изменить на голосование 'против'",
+ "confirm_flag": "Подтвердить голос 'против'",
+ "and_more": "и %(count)s больше",
+ "votes_plural": {
+ "one": "%(count)s голоса",
+ "few": "%(count)s голоса",
+ "many": "%(count)s голосов",
+ "other": "%(count)s голосов"
+ }
+ },
+ "witnesses_jsx": {
+ "witness_thread": "пост делегата",
+ "top_witnesses": "Топ делегатов",
+ "you_have_votes_remaining": {
+ "zero": "У Вас не осталось голосов",
+ "one": "У Вас остался 1 голос",
+ "few": "У Вас осталось %(count)s голоса",
+ "many": "У Вас осталось %(count)s голосов",
+ "other": "У Вас осталось %(count)s голосов"
+ },
+ "you_can_vote_for_maximum_of_witnesses":
+ "Вы можете голосовать максимум за 30 делегатов",
+ "witness": "Делегаты",
+ "information": "Информация",
+ "if_you_want_to_vote_outside_of_top_enter_account_name":
+ "Если вы хотите проголосовать за делегата вне top 50, введите имя аккаунта ниже",
+ "set_witness_proxy":
+ "Вы также можете выбрать прокси, который будет вместо вас голосовать за делегатов. Это сбросит ваш текущий выбор делегата.",
+ "witness_set":
+ "Вы установили прокси для голосования. Если вы хотите голосовать вручную, пожалуйста, очистите ваш прокси.",
+ "witness_proxy_current": "Ваш текущий прокси",
+ "witness_proxy_set": "Установить прокси",
+ "witness_proxy_clear": "Очистить прокси",
+ "proxy_update_error": "Ваш прокси не был обновлен"
+ },
+ "votesandcomments_jsx": {
+ "no_responses_yet_click_to_respond":
+ "Ответов пока нет. Нажмите чтобы ответить.",
+ "response_count_tooltip": {
+ "zero": "ответов пока нет. Нажмите чтобы ответить.",
+ "one": "1 ответ. Нажмите чтобы ответить.",
+ "few": "%(count)s ответа. Нажмите чтобы ответить.",
+ "many": "%(count)s ответов. Нажмите чтобы ответить.",
+ "other": "%(count)s ответов. Нажмите чтобы ответить."
+ },
+ "vote_count": {
+ "zero": "нет голосов",
+ "one": "1 голос",
+ "few": "%(count)s голоса",
+ "many": "%(count)s голосов",
+ "other": "%(count)s голосов"
+ }
+ },
+ "userkeys_jsx": {
+ "public": "Публичное",
+ "private": "Приватное",
+ "public_something_key": "Публичный %(key)s ключ",
+ "private_something_key": "Приватный %(key)s ключ",
+ "posting_key_is_required_it_should_be_different":
+ "Постинг ключ используется для постинга и голосования. Он должен отличаться от активного ключа и ключа владельца.",
+ "the_active_key_is_used_to_make_transfers_and_place_orders":
+ "Активный ключ используется для переводов и размещения заказов на внутреннем рынке.",
+ "the_owner_key_is_required_to_change_other_keys":
+ "Ключ владельца это главный ключ ко всему аккаунта, он необходим для изменения других ключей.",
+ "the_private_key_or_password_should_be_kept_offline":
+ "Приватный ключ или пароль должен храниться в оффлайне так часто насколько возможно.",
+ "the_memo_key_is_used_to_create_and_read_memos":
+ "Ключ примечаний используется для создания и чтения примечаний."
+ },
+ "suggestpassword_jsx": {
+ "APP_NAME_cannot_recover_passwords_keep_this_page_in_a_secure_location":
+ "%(APP_NAME)s не может восстановить пароли. Сохраните эту страницу в безопасном месте, например, в огнестойком сейфе или в депозитарной ячейке.",
+ "APP_NAME_password_backup": "%(APP_NAME)s резервное копирование пароля",
+ "APP_NAME_password_backup_required":
+ "%(APP_NAME)s резервное копирование пароля (обязательно!)",
+ "after_printing_write_down_your_user_name":
+ "После печати запишите ваше имя пользователя"
+ },
+ "converttosteem_jsx": {
+ "your_existing_DEBT_TOKEN_are_liquid_and_transferable":
+ "Ваши %(DEBT_TOKEN)s токены ликвидны. Вы можете конвертировать %(DEBT_TOKEN)s на этом сайте (%(link)s) или вывести на биржу/обменник.",
+ "this_is_a_price_feed_conversion":
+ "Конвертация на сайте выполняется три с половиной дня - это требуется, чтобы исключить манипуляции с ценами.",
+ "convert_to_LIQUID_TOKEN": "Ковертировать в %(LIQUID_TOKEN)s",
+ "DEBT_TOKEN_will_be_unavailable":
+ "Эта операция будет проходить 3-5 дней от настоящего момента и ее нельзя отменить. Эти %(DEBT_TOKEN)s мгновенно станут недоступны"
+ },
+ "tips_js": {
+ "liquid_token":
+ "Ликвидные цифровые токены, которые могут переданы куда угодно в любой момент. %(LIQUID_TOKEN)s может быть конвертирован в %(VESTING_TOKEN)s, этот процесс называется \"увеличение Силы Голоса\".",
+ "influence_token":
+ "Токены дают вам возможность влиять на вознаграждения за контент, а также возможность зарабатывать на курации контента.",
+ "estimated_value":
+ "Сметная стоимость основана на среднем значении %(LIQUID_TOKEN)s в долларах США.",
+ "non_transferable":
+ "%(VESTING_TOKEN)s - не ликвидные токены, требуется три месяца (13 еженедальных выплат) чтобы сконвертировать их в ликвидные токены %(LIQUID_TOKEN)s.",
+ "converted_VESTING_TOKEN_can_be_sent_to_yourself_but_can_not_transfer_again":
+ "Конвертированные %(VESTING_TOKEN)s токены могут быть отправлены себе или кому-либо еще, но не могут быть переданы вновь без конвертации в %(LIQUID_TOKEN)s.",
+ "part_of_your_steem_power_is_currently_delegated":
+ "Часть STEEM POWER вам делегирована, это увеличивает ваше влияние на платформе. Количество делегированных токенов со временем может изменяться."
+ },
+ "promote_post_jsx": {
+ "promote_post": "Продвинуть пост",
+ "spend_your_DEBT_TOKEN_to_advertise_this_post":
+ "Используйте ваши %(DEBT_TOKEN)s чтобы прорекламировать этот пост в секции продвигаемого контента",
+ "you_successfully_promoted_this_post":
+ "Операция продвижения успешно завершена",
+ "this_post_was_hidden_due_to_low_ratings":
+ "Этот пост был скрыт из-за низкого рейтинга"
+ },
+ "about_jsx": {
+ "about_app": "О %(APP_NAME)s",
+ "about_app_details":
+ "%(APP_NAME)s - это социальная медиа платформа в которой каждый зарабатывает за создание и курирование контента. Он использует надежную систему цифровых очков под названием Голос, который поддерживает реальную ценность для цифровых наград через выявление рыночной цены и ликвидности.",
+ "learn_more_at_app_url": "Узнать больше в %(APP_URL)s",
+ "resources": "Ресурсы"
+ },
+ "markdownviewer_jsx": {
+ "images_were_hidden_due_to_low_ratings":
+ "Изображения были скрыты из-за низкого рейтинга."
+ },
+ "postsummary_jsx": {
+ "resteemed": "Поделиться",
+ "resteemed_by": "Репостнуто",
+ "reveal_it": "посмотреть пост",
+ "adjust_your": "откорректируйте свои",
+ "display_preferences": "настройки отображения",
+ "create_an_account": "зарегистрироваться",
+ "to_save_your_preferences": "сохранить ваши настройки"
+ },
+ "posts_index": {
+ "empty_feed_1": "Похоже, что Вы еще ни на кого не подписаны",
+ "empty_feed_2":
+ "Если Вы недавно подписались на новых пользователей, Ваша персональная лента будет заполняться, когда будет доступен новый контент",
+ "empty_feed_3": "Посмотреть статьи, набирающие популярность",
+ "empty_feed_4": "Прочтите краткое руководство",
+ "empty_feed_5": "Просмотреть ЧаВО"
+ },
+ "transferhistoryrow_jsx": {
+ "to_savings": "в сейф",
+ "from_savings": "из сейфа",
+ "cancel_transfer_from_savings": "Отменить перевод из сейфа",
+ "stop_power_down": "Ослабление Силы Голоса остановлено",
+ "start_power_down_of": "Ослабление Силы Голоса начато с",
+ "receive_interest_of": "Получать проценты по"
+ },
+ "savingswithdrawhistory_jsx": {
+ "cancel_this_withdraw_request": "Отменить запрос вывода средств?",
+ "pending_savings_withdrawals": "Выплаты из сейфа",
+ "withdraw": "Снять %(amount)s",
+ "to": "для %(to)s",
+ "from_to": "от %(from)s к %(to)s"
+ },
+ "explorepost_jsx": {
+ "copied": "Скопировано!",
+ "copy": "Копировать",
+ "alternative_sources": "Альтернативные источники"
+ },
+ "header_jsx": {
+ "home": "лента",
+ "create_a_post": "Создать пост",
+ "change_account_password": "Изменить пароль аккаунта",
+ "create_account": "Создать Аккаунт",
+ "stolen_account_recovery": "Возврат украденного аккаунта",
+ "people_following": "Подписчики",
+ "people_followed_by": "Подписчики",
+ "curation_rewards_by": "Награда за курирование",
+ "author_rewards_by": "Автор награжден",
+ "replies_to": "Ответы на",
+ "comments_by": "Комментарии"
+ },
+ "loginform_jsx": {
+ "you_need_a_private_password_or_key":
+ "Вам нужен приватный пароль или ключ (не публичный ключ)",
+ "cryptography_test_failed": "Криптографический тест не пройден",
+ "unable_to_log_you_in":
+ "У нас не получится залогинить вас в этом браузере.",
+ "the_latest_versions_of": "Последние версии ",
+ "are_well_tested_and_known_to_work_with":
+ "хорошо протестированы и работают с %(APP_URL)s.",
+ "due_to_server_maintenance":
+ "Из-за технического обслуживания сервера мы работаем в режиме чтения. Извините за неудобства.",
+ "login_to_vote": "Войти, чтобы проголосовать",
+ "login_to_post": "Войти, чтобы написать пост",
+ "login_to_comment": "Войти, чтобы оставить комментарий",
+ "posting": "Постинг",
+ "active_or_owner": "Активный или Владельца",
+ "this_password_is_bound_to_your_account_owner_key":
+ "Этот пароль привязан к главному ключу аккаунта и не может быть использован для входа на этот сайт.",
+ "however_you_can_use_it_to":
+ "Тем не менее его можно использовать чтобы ",
+ "update_your_password": "обновить Ваш пароль",
+ "to_obtain_a_more_secure_set_of_keys":
+ "для получения более безопасного набора ключей.",
+ "this_password_is_bound_to_your_account_active_key":
+ "Этот пароль привязан к главному ключу аккаунта и не может быть использован для входа на этот сайт.",
+ "you_may_use_this_active_key_on_other_more":
+ "Вы можете использовать этот активный ключ на других более безопасных страниц, таких как страницы: Кошелек или Биржа.",
+ "you_account_has_been_successfully_created":
+ "Ваш аккаунт был успешно создан!",
+ "you_account_has_been_successfully_recovered":
+ "Ваш аккаунт был успешно восстановлен!",
+ "password_update_succes":
+ "Пароль для %(accountName)s был успешно обновлен",
+ "password_info":
+ "Этот пароль или закрытый ключ был введен неправильно. Вероятно, есть ошибка почерка или ввода данных. Подсказка: пароль или закрытый ключ, сгенерированный Steemit, никогда не будет содержать символы 0 (ноль), O (прописная o), I (прописная i) и l (нижний регистр L).",
+ "enter_your_username": "Введи свое имя пользователя",
+ "password_or_wif": "Пароль или WIF",
+ "this_operation_requires_your_key_or_master_password":
+ "Для осуществления данной операции нужен ваш %(authType)s ключ или Основной пароль.",
+ "keep_me_logged_in": "Оставить меня залогиненным",
+ "amazing_community": "удивительное сообщество",
+ "to_comment_and_reward_others":
+ " комментировать и вознаграждать других.",
+ "sign_up_get_steem": "Sign up. Get STEEM",
+ "signup_button": "Зарегистрируйтесь",
+ "signup_button_emphasis": " сейчас!",
+ "returning_users": "Вернувшиеся пользователи: ",
+ "join_our": "Присоединяйтесь к нашему"
+ },
+ "chainvalidation_js": {
+ "account_name_should": "Имя аккаунта должно быть ",
+ "not_be_empty": "не может быть пустым.",
+ "be_longer": "длиннее.",
+ "be_shorter": "короче.",
+ "each_account_segment_should": "Имя аккаунта должно начинаться с ",
+ "start_with_a_letter": "должно начинаться с буквы.",
+ "have_only_letters_digits_or_dashes":
+ "должно должно состоять только из букв, цифр или дефисов.",
+ "have_only_one_dash_in_a_row": "иметь только одно тире в строке.",
+ "end_with_a_letter_or_digit": "заканчиваться буквой или цифрой.",
+ "verified_exchange_no_memo":
+ "Для перевода на биржу Вы должны указать примечание."
+ },
+ "settings_jsx": {
+ "invalid_url": "Недопустимый URL-адрес",
+ "name_is_too_long": "Имя слишком длинное",
+ "name_must_not_begin_with": "Имя не должно начинаться с @",
+ "about_is_too_long": "Информация о Вашем блоге слишком длинная",
+ "location_is_too_long": "Местоположение слишком длинное",
+ "website_url_is_too_long": "URL-адрес веб-сайта слишком длинный",
+ "public_profile_settings": "Настройки Публичного Профиля",
+ "preferences": "Настройки отображения приватных постов",
+ "not_safe_for_work_nsfw_content":
+ "Небезопасный для работы (NSFW) контент",
+ "always_hide": "Всегда скрывать",
+ "always_warn": "Всегда предупреждать",
+ "always_show": "Отображать всегда",
+ "muted_users": "Заблокированные пользователи",
+ "update": "Обновить",
+ "profile_image_url": "Добавьте url вашего изображения",
+ "cover_image_url": "URL-адрес изображения обложки",
+ "profile_name": "Отображаемое имя",
+ "profile_about": "О себе",
+ "profile_location": "Местоположение",
+ "profile_website": "Веб-сайт"
+ },
+ "transfer_jsx": {
+ "amount_is_in_form": "Сумма должна быть в формате 99999.999",
+ "insufficient_funds": "Недостаточно средств",
+ "use_only_3_digits_of_precison": "Используйте только 3 цифры точности",
+ "send_to_account": "Отправить аккаунту",
+ "asset": "Актив",
+ "this_memo_is_private": "Это примечание является приватным",
+ "this_memo_is_public": "Это примечание является публичным",
+ "convert_to_VESTING_TOKEN": "Перевести в %(VESTING_TOKEN)s",
+ "balance_subject_to_3_day_withdraw_waiting_period":
+ "Вывод баланса из сейфа на обычный счет, занимает 3 дня,",
+ "move_funds_to_another_account":
+ "Отправить средства на другой %(APP_NAME)s аккаунт.",
+ "protect_funds_by_requiring_a_3_day_withdraw_waiting_period":
+ "Защитите средства от вывода 3-х дневным периодом ожидания.",
+ "withdraw_funds_after_the_required_3_day_waiting_period":
+ "Снять средства после необходимого 3 дневного периода ожидания.",
+ "from": "От",
+ "to": "Кому",
+ "asset_currently_collecting":
+ "начисляемые годовые на %(asset)s: %(interest)s%%.",
+ "beware_of_spam_and_phishing_links":
+ "Остерегайтесь спама и фишинговых ссылок в передачах. Не открывайте ссылки от пользователей, которым вы не доверяете. Не предоставляйте свои личные ключи третьим сторонам."
+ },
+ "userwallet_jsx": {
+ "conversion_complete_tip": "Завершается",
+ "in_conversion": "%(amount)s на конвертации",
+ "transfer_to_savings": "Отправить в сейф",
+ "power_up": "Усилить силу голоса",
+ "power_down": "Уменьшить силу голоса",
+ "market": "Биржа",
+ "convert_to_LIQUID_TOKEN": "Перевести в %(LIQUID_TOKEN)s",
+ "withdraw_LIQUID_TOKEN": "Снять %(LIQUID_TOKEN)s",
+ "withdraw_DEBT_TOKENS": "Снять %(DEBT_TOKENS)s",
+ "tokens_worth_about_1_of_LIQUID_TICKER":
+ "Стоимость токенов $1.00 в %(LIQUID_TICKER)s, начисляемые годовые %(sbdInterest)s%%.",
+ "savings": "Сберегательный счет",
+ "estimated_account_value": "Приблизительная стоимость аккаунта",
+ "next_power_down_is_scheduled_to_happen":
+ "Следующее понижение силы голоса будет",
+ "transfers_are_temporary_disabled": "Переводы временно преостановлены.",
+ "history": "ИСТОРИЯ",
+ "redeem_rewards": "Получить вознаграждение",
+ "buy_steem_or_steem_power": "Купить STEEM или STEEM POWER"
+ },
+ "powerdown_jsx": {
+ "power_down": "Уменьшить силу голоса (power down)",
+ "amount": "Количество",
+ "already_power_down":
+ "Вы уже запустили понижение силы голоса на %(AMOUNT)s %(LIQUID_TICKER)s (%(WITHDRAWN)s %(LIQUID_TICKER)s уже выплачено). Если вы измените количество, отсчет времени сбросится и составит 13 недель от сегодняшего дня.",
+ "delegating":
+ "Вы делегируете %(AMOUNT)s %(LIQUID_TICKER)s. Это количество заблокировано и не может быть выведено пока делегирование не будет отменено и не пройдет один полный цикл выплат вознаграждений.",
+ "per_week": "Это ~%(AMOUNT)s %(LIQUID_TICKER)s в неделю.",
+ "warning":
+ "Оставлять меньше чем %(AMOUNT)s %(LIQUID_TICKER)s не рекомендуется, т.к. это может остановить все транзакции с использованием это аккаунта.",
+ "error": "Неполучается уменьшить силу голоса (ERROR: %(MESSAGE)s)"
+ },
+ "checkloginowner_jsx": {
+ "your_password_permissions_were_reduced":
+ "Your password permissions were reduced",
+ "if_you_did_not_make_this_change":
+ "If you did not make this change please",
+ "ownership_changed_on": "Владелец аккаунта или пароль были изменены ",
+ "deadline_for_recovery_is": "Вы можете восстановить доступ до ",
+ "i_understand_dont_show_again": "Понятно, больше не показывать"
}
- },
- "userkeys_jsx": {
- "public": "Публичное",
- "private": "Приватное",
- "public_something_key": "Публичный %(key)s ключ",
- "private_something_key": "Приватный %(key)s ключ",
- "posting_key_is_required_it_should_be_different": "Постинг ключ используется для постинга и голосования. Он должен отличаться от активного ключа и ключа владельца.",
- "the_active_key_is_used_to_make_transfers_and_place_orders": "Активный ключ используется для переводов и размещения заказов на внутреннем рынке.",
- "the_owner_key_is_required_to_change_other_keys": "Ключ владельца это главный ключ ко всему аккаунта, он необходим для изменения других ключей.",
- "the_private_key_or_password_should_be_kept_offline": "Приватный ключ или пароль должен храниться в оффлайне так часто насколько возможно.",
- "the_memo_key_is_used_to_create_and_read_memos": "Ключ примечаний используется для создания и чтения примечаний."
- },
- "suggestpassword_jsx": {
- "APP_NAME_cannot_recover_passwords_keep_this_page_in_a_secure_location": "%(APP_NAME)s не может восстановить пароли. Сохраните эту страницу в безопасном месте, например, в огнестойком сейфе или в депозитарной ячейке.",
- "APP_NAME_password_backup": "%(APP_NAME)s резервное копирование пароля",
- "APP_NAME_password_backup_required": "%(APP_NAME)s резервное копирование пароля (обязательно!)",
- "after_printing_write_down_your_user_name": "После печати запишите ваше имя пользователя"
- },
- "converttosteem_jsx": {
- "your_existing_DEBT_TOKEN_are_liquid_and_transferable": "Ваши %(DEBT_TOKEN)s токены ликвидны. Вы можете конвертировать %(DEBT_TOKEN)s на этом сайте (%(link)s) или вывести на биржу/обменник.",
- "this_is_a_price_feed_conversion": "Конвертация на сайте выполняется три с половиной дня - это требуется, чтобы исключить манипуляции с ценами.",
- "convert_to_LIQUID_TOKEN": "Ковертировать в %(LIQUID_TOKEN)s",
- "DEBT_TOKEN_will_be_unavailable": "Эта операция будет проходить 3-5 дней от настоящего момента и ее нельзя отменить. Эти %(DEBT_TOKEN)s мгновенно станут недоступны"
- },
- "tips_js": {
- "liquid_token": "Ликвидные цифровые токены, которые могут переданы куда угодно в любой момент. %(LIQUID_TOKEN)s может быть конвертирован в %(VESTING_TOKEN)s, этот процесс называется \"увеличение Силы Голоса\".",
- "influence_token": "Токены дают вам возможность влиять на вознаграждения за контент, а также возможность зарабатывать на курации контента.",
- "estimated_value": "Сметная стоимость основана на среднем значении %(LIQUID_TOKEN)s в долларах США.",
- "non_transferable": "%(VESTING_TOKEN)s - не ликвидные токены, требуется три месяца (13 еженедальных выплат) чтобы сконвертировать их в ликвидные токены %(LIQUID_TOKEN)s.",
- "converted_VESTING_TOKEN_can_be_sent_to_yourself_but_can_not_transfer_again": "Конвертированные %(VESTING_TOKEN)s токены могут быть отправлены себе или кому-либо еще, но не могут быть переданы вновь без конвертации в %(LIQUID_TOKEN)s.",
- "part_of_your_steem_power_is_currently_delegated": "Часть STEEM POWER вам делегирована, это увеличивает ваше влияние на платформе. Количество делегированных токенов со временем может изменяться."
- },
- "promote_post_jsx": {
- "promote_post": "Продвинуть пост",
- "spend_your_DEBT_TOKEN_to_advertise_this_post": "Используйте ваши %(DEBT_TOKEN)s чтобы прорекламировать этот пост в секции продвигаемого контента",
- "you_successfully_promoted_this_post": "Операция продвижения успешно завершена",
- "this_post_was_hidden_due_to_low_ratings": "Этот пост был скрыт из-за низкого рейтинга"
- },
- "about_jsx": {
- "about_app": "О %(APP_NAME)s",
- "about_app_details": "%(APP_NAME)s - это социальная медиа платформа в которой каждый зарабатывает за создание и курирование контента. Он использует надежную систему цифровых очков под названием Голос, который поддерживает реальную ценность для цифровых наград через выявление рыночной цены и ликвидности.",
- "learn_more_at_app_url": "Узнать больше в %(APP_URL)s",
- "resources": "Ресурсы"
- },
- "markdownviewer_jsx": {
- "images_were_hidden_due_to_low_ratings": "Изображения были скрыты из-за низкого рейтинга."
- },
- "postsummary_jsx": {
- "resteemed": "Поделиться",
- "resteemed_by": "Репостнуто",
- "reveal_it": "посмотреть пост",
- "adjust_your": "откорректируйте свои",
- "display_preferences": "настройки отображения",
- "create_an_account": "зарегистрироваться",
- "to_save_your_preferences": "сохранить ваши настройки"
- },
- "posts_index": {
- "empty_feed_1": "Похоже, что Вы еще ни на кого не подписаны",
- "empty_feed_2": "Если Вы недавно подписались на новых пользователей, Ваша персональная лента будет заполняться, когда будет доступен новый контент",
- "empty_feed_3": "Посмотреть статьи, набирающие популярность",
- "empty_feed_4": "Прочтите краткое руководство",
- "empty_feed_5": "Просмотреть ЧаВО"
- },
- "transferhistoryrow_jsx": {
- "to_savings": "в сейф",
- "from_savings": "из сейфа",
- "cancel_transfer_from_savings": "Отменить перевод из сейфа",
- "stop_power_down": "Ослабление Силы Голоса остановлено",
- "start_power_down_of": "Ослабление Силы Голоса начато с",
- "receive_interest_of": "Получать проценты по"
- },
- "savingswithdrawhistory_jsx": {
- "cancel_this_withdraw_request": "Отменить запрос вывода средств?",
- "pending_savings_withdrawals": "Выплаты из сейфа",
- "withdraw": "Снять %(amount)s",
- "to": "для %(to)s",
- "from_to": "от %(from)s к %(to)s"
- },
- "explorepost_jsx": {
- "copied": "Скопировано!",
- "copy": "Копировать",
- "alternative_sources": "Альтернативные источники"
- },
- "header_jsx": {
- "home": "лента",
- "create_a_post": "Создать пост",
- "change_account_password": "Изменить пароль аккаунта",
- "create_account": "Создать Аккаунт",
- "stolen_account_recovery": "Возврат украденного аккаунта",
- "people_following": "Подписчики",
- "people_followed_by": "Подписчики",
- "curation_rewards_by": "Награда за курирование",
- "author_rewards_by": "Автор награжден",
- "replies_to": "Ответы на",
- "comments_by": "Комментарии"
- },
- "loginform_jsx": {
- "you_need_a_private_password_or_key": "Вам нужен приватный пароль или ключ (не публичный ключ)",
- "cryptography_test_failed": "Криптографический тест не пройден",
- "unable_to_log_you_in": "У нас не получится залогинить вас в этом браузере.",
- "the_latest_versions_of": "Последние версии ",
- "are_well_tested_and_known_to_work_with": "хорошо протестированы и работают с %(APP_URL)s.",
- "due_to_server_maintenance": "Из-за технического обслуживания сервера мы работаем в режиме чтения. Извините за неудобства.",
- "login_to_vote": "Войти, чтобы проголосовать",
- "login_to_post": "Войти, чтобы написать пост",
- "login_to_comment": "Войти, чтобы оставить комментарий",
- "posting": "Постинг",
- "active_or_owner": "Активный или Владельца",
- "this_password_is_bound_to_your_account_owner_key": "Этот пароль привязан к главному ключу аккаунта и не может быть использован для входа на этот сайт.",
- "however_you_can_use_it_to": "Тем не менее его можно использовать чтобы ",
- "update_your_password": "обновить Ваш пароль",
- "to_obtain_a_more_secure_set_of_keys": "для получения более безопасного набора ключей.",
- "this_password_is_bound_to_your_account_active_key": "Этот пароль привязан к главному ключу аккаунта и не может быть использован для входа на этот сайт.",
- "you_may_use_this_active_key_on_other_more": "Вы можете использовать этот активный ключ на других более безопасных страниц, таких как страницы: Кошелек или Биржа.",
- "you_account_has_been_successfully_created": "Ваш аккаунт был успешно создан!",
- "you_account_has_been_successfully_recovered": "Ваш аккаунт был успешно восстановлен!",
- "password_update_succes": "Пароль для %(accountName)s был успешно обновлен",
- "password_info": "Этот пароль или закрытый ключ был введен неправильно. Вероятно, есть ошибка почерка или ввода данных. Подсказка: пароль или закрытый ключ, сгенерированный Steemit, никогда не будет содержать символы 0 (ноль), O (прописная o), I (прописная i) и l (нижний регистр L).",
- "enter_your_username": "Введи свое имя пользователя",
- "password_or_wif": "Пароль или WIF",
- "this_operation_requires_your_key_or_master_password": "Для осуществления данной операции нужен ваш %(authType)s ключ или Основной пароль.",
- "keep_me_logged_in": "Оставить меня залогиненным",
- "amazing_community": "удивительное сообщество",
- "to_comment_and_reward_others": " комментировать и вознаграждать других.",
- "sign_up_get_steem": "Sign up. Get STEEM",
- "signup_button": "Зарегистрируйтесь",
- "signup_button_emphasis": " сейчас!",
- "returning_users": "Вернувшиеся пользователи: ",
- "join_our": "Присоединяйтесь к нашему"
- },
- "chainvalidation_js": {
- "account_name_should": "Имя аккаунта должно быть ",
- "not_be_empty": "не может быть пустым.",
- "be_longer": "длиннее.",
- "be_shorter": "короче.",
- "each_account_segment_should": "Имя аккаунта должно начинаться с ",
- "start_with_a_letter": "должно начинаться с буквы.",
- "have_only_letters_digits_or_dashes": "должно должно состоять только из букв, цифр или дефисов.",
- "have_only_one_dash_in_a_row": "иметь только одно тире в строке.",
- "end_with_a_letter_or_digit": "заканчиваться буквой или цифрой.",
- "verified_exchange_no_memo": "Для перевода на биржу Вы должны указать примечание."
- },
- "settings_jsx": {
- "invalid_url": "Недопустимый URL-адрес",
- "name_is_too_long": "Имя слишком длинное",
- "name_must_not_begin_with": "Имя не должно начинаться с @",
- "about_is_too_long": "Информация о Вашем блоге слишком длинная",
- "location_is_too_long": "Местоположение слишком длинное",
- "website_url_is_too_long": "URL-адрес веб-сайта слишком длинный",
- "public_profile_settings": "Настройки Публичного Профиля",
- "private_post_display_settings": "Настройки отображения приватных постов",
- "not_safe_for_work_nsfw_content": "Небезопасный для работы (NSFW) контент",
- "always_hide": "Всегда скрывать",
- "always_warn": "Всегда предупреждать",
- "always_show": "Отображать всегда",
- "muted_users": "Заблокированные пользователи",
- "update": "Обновить",
- "profile_image_url": "Добавьте url вашего изображения",
- "cover_image_url": "URL-адрес изображения обложки",
- "profile_name": "Отображаемое имя",
- "profile_about": "О себе",
- "profile_location": "Местоположение",
- "profile_website": "Веб-сайт"
- },
- "transfer_jsx": {
- "amount_is_in_form": "Сумма должна быть в формате 99999.999",
- "insufficient_funds": "Недостаточно средств",
- "use_only_3_digits_of_precison": "Используйте только 3 цифры точности",
- "send_to_account": "Отправить аккаунту",
- "asset": "Актив",
- "this_memo_is_private": "Это примечание является приватным",
- "this_memo_is_public": "Это примечание является публичным",
- "convert_to_VESTING_TOKEN": "Перевести в %(VESTING_TOKEN)s",
- "balance_subject_to_3_day_withdraw_waiting_period": "Вывод баланса из сейфа на обычный счет, занимает 3 дня,",
- "move_funds_to_another_account": "Отправить средства на другой %(APP_NAME)s аккаунт.",
- "protect_funds_by_requiring_a_3_day_withdraw_waiting_period": "Защитите средства от вывода 3-х дневным периодом ожидания.",
- "withdraw_funds_after_the_required_3_day_waiting_period": "Снять средства после необходимого 3 дневного периода ожидания.",
- "from": "От",
- "to": "Кому",
- "asset_currently_collecting": "начисляемые годовые на %(asset)s: %(interest)s%%.",
- "beware_of_spam_and_phishing_links": "Остерегайтесь спама и фишинговых ссылок в передачах. Не открывайте ссылки от пользователей, которым вы не доверяете. Не предоставляйте свои личные ключи третьим сторонам."
- },
- "userwallet_jsx": {
- "conversion_complete_tip": "Завершается",
- "in_conversion": "%(amount)s на конвертации",
- "transfer_to_savings": "Отправить в сейф",
- "power_up": "Усилить силу голоса",
- "power_down": "Уменьшить силу голоса",
- "market": "Биржа",
- "convert_to_LIQUID_TOKEN": "Перевести в %(LIQUID_TOKEN)s",
- "withdraw_LIQUID_TOKEN": "Снять %(LIQUID_TOKEN)s",
- "withdraw_DEBT_TOKENS": "Снять %(DEBT_TOKENS)s",
- "tokens_worth_about_1_of_LIQUID_TICKER": "Стоимость токенов $1.00 в %(LIQUID_TICKER)s, начисляемые годовые %(sbdInterest)s%%.",
- "savings": "Сберегательный счет",
- "estimated_account_value": "Приблизительная стоимость аккаунта",
- "next_power_down_is_scheduled_to_happen": "Следующее понижение силы голоса будет",
- "transfers_are_temporary_disabled": "Переводы временно преостановлены.",
- "history": "ИСТОРИЯ",
- "redeem_rewards": "Получить вознаграждение",
- "buy_steem_or_steem_power": "Купить STEEM или STEEM POWER"
- },
- "powerdown_jsx": {
- "power_down": "Уменьшить силу голоса (power down)",
- "amount": "Количество",
- "already_power_down": "Вы уже запустили понижение силы голоса на %(AMOUNT)s %(LIQUID_TICKER)s (%(WITHDRAWN)s %(LIQUID_TICKER)s уже выплачено). Если вы измените количество, отсчет времени сбросится и составит 13 недель от сегодняшего дня.",
- "delegating": "Вы делегируете %(AMOUNT)s %(LIQUID_TICKER)s. Это количество заблокировано и не может быть выведено пока делегирование не будет отменено и не пройдет один полный цикл выплат вознаграждений.",
- "per_week": "Это ~%(AMOUNT)s %(LIQUID_TICKER)s в неделю.",
- "warning": "Оставлять меньше чем %(AMOUNT)s %(LIQUID_TICKER)s не рекомендуется, т.к. это может остановить все транзакции с использованием это аккаунта.",
- "error": "Неполучается уменьшить силу голоса (ERROR: %(MESSAGE)s)"
- },
- "checkloginowner_jsx": {
- "your_password_permissions_were_reduced": "Your password permissions were reduced",
- "if_you_did_not_make_this_change": "If you did not make this change please",
- "ownership_changed_on": "Владелец аккаунта или пароль были изменены ",
- "deadline_for_recovery_is": "Вы можете восстановить доступ до ",
- "i_understand_dont_show_again": "Понятно, больше не показывать"
- }
}
diff --git a/src/app/locales/zh.json b/src/app/locales/zh.json
new file mode 100644
index 0000000000000000000000000000000000000000..eb5a213d8a787bc40ef7f45386b880e367ef9b40
--- /dev/null
+++ b/src/app/locales/zh.json
@@ -0,0 +1,713 @@
+{
+ "g": {
+ "age": "时间",
+ "amount": "数量",
+ "and": "和",
+ "are_you_sure": "确定?",
+ "ask": "卖价",
+ "balance": "余额",
+ "balances": "余额",
+ "bid": "买价",
+ "blog": "博客",
+ "browse": "浏览",
+ "buy": "购买",
+ "buy_or_sell": "买或卖",
+ "by": "by",
+ "cancel": "取消",
+ "change_password": "修改密码",
+ "choose_language": "选择语言",
+ "clear": "清除",
+ "close": "关闭",
+ "collapse_or_expand": "折叠/展开",
+ "comments": "评论",
+ "confirm": "确认",
+ "convert": "转换",
+ "date": "日期",
+ "delete": "删除",
+ "dismiss": "关闭",
+ "edit": "编辑",
+ "email": "邮件",
+ "feed": "动态",
+ "follow": "关注",
+ "for": "对于",
+ "from": "从",
+ "go_back": "返回",
+ "hide": "隐藏",
+ "in": "在",
+ "in_reply_to": "回复",
+ "insufficient_balance": "余额不足",
+ "invalid_amount": "金额无效",
+ "joined": "加入",
+ "loading": "正在载入",
+ "login": "登录",
+ "logout": "登出",
+ "memo": "备注",
+ "mute": "屏蔽",
+ "new": "最新",
+ "newer": "较新的",
+ "next": "下一个",
+ "no": "不是",
+ "ok": "好",
+ "older": "较旧的",
+ "or": "或者",
+ "order_placed": "下单成功",
+ "password": "密码",
+ "payouts": "赏金",
+ "permissions": "权限",
+ "post": "发布",
+ "post_as": "发布为",
+ "posts": "文章",
+ "powered_up_100": "Power Up 100%%",
+ "preview": "预览",
+ "previous": "以前",
+ "price": "价格",
+ "print": "打印",
+ "promote": "推广",
+ "promoted": "推广",
+ "re": "回复",
+ "re_to": "回复%(topic)s",
+ "recent_password": "最近的密码",
+ "receive": "收到",
+ "remove": "取消",
+ "remove_vote": "取消投票",
+ "replied_to": "回复了 %(account)s",
+ "replies": "留言",
+ "reply": "回复",
+ "reply_count": {
+ "zero": "没有留言",
+ "one": "1个回复",
+ "other": "%(count)s个回复"
+ },
+ "reputation": "声誉",
+ "reveal_comment": "显示评论",
+ "request": "请求",
+ "required": "需要",
+ "rewards": "奖励",
+ "save": "保存",
+ "saved": "已保存",
+ "search": "搜索",
+ "sell": "卖出",
+ "settings": "设置",
+ "share_this_post": "分享这篇文章",
+ "show": "显示",
+ "sign_in": "登录",
+ "sign_up": "注册",
+ "since": "自从",
+ "submit": "提交",
+ "power_up": "Power Up",
+ "submit_a_story": "发表故事",
+ "tag": "标签",
+ "to": "至",
+ "topics": "主题",
+ "toggle_nightmode": "切换夜间模式",
+
+ "all_tags": "所有标签",
+ "transfer": "转账",
+ "trending_topics": "热门话题",
+ "type": "类型",
+ "unfollow": "取消关注",
+ "unmute": "取消屏蔽",
+ "unknown": "未知",
+ "upvote": "点赞",
+ "upvote_post": "点赞的文章",
+ "username": "用户名",
+ "version": "版本",
+ "vote": "点赞",
+ "votes": "点赞数",
+ "wallet": "钱包",
+ "warning": "警告",
+ "yes": "是的",
+ "posting": "发帖",
+ "owner": "拥有者",
+ "active": "活跃",
+ "account_not_found": "账号不存在",
+ "this_is_wrong_password": "密码错误",
+ "do_you_need_to": "你需要吗",
+ "account_name": "用户名",
+ "recover_your_account": "恢复你的账号",
+ "reset_usernames_password": "重置%(username)s的密码",
+ "this_will_update_usernames_authtype_key":
+ "确定更改%(username)s%(authType)s的密钥",
+ "passwords_do_not_match": "密码不匹配",
+ "you_need_private_password_or_key_not_a_public_key":
+ "你需要一个私钥或密码(不能用公钥)",
+ "the_rules_of_APP_NAME": {
+ "one": "%(APP_NAME)s的第一条规则是: 不要丢失你的密码。",
+ "second": "%(APP_NAME)s的第二条规则是: 不要丢失你的密码。",
+ "third": "%(APP_NAME)s的第三条规则是: 我们无法恢复你的密码。",
+ "fourth": "第四条规则是: 如果你能记住密码,那就不安全了。",
+ "fifth": "第五条规则是: 只能使用随机生成的密码。",
+ "sixth": "第六条规则是: 请不要把你的密码告诉任何人。",
+ "seventh": "第七条规则是: 始终备份你的密码。"
+ },
+ "recover_password": "恢复账号",
+ "current_password": "当前密码",
+ "generated_password": "生成密码",
+ "backup_password_by_storing_it": "将你的密码备份到密码管理器或者文件",
+ "enter_account_show_password": "输入一个有效的帐户名称以显示密码",
+ "click_to_generate_password": "点击生成密码",
+ "re_enter_generate_password": "重新输入生成的密码",
+ "understand_that_APP_NAME_cannot_recover_password":
+ "我知道%(APP_NAME)s无法恢复丢失的密码",
+ "i_saved_password": "我安全地保存了我生成的密码",
+ "update_password": "修改密码",
+ "confirm_password": "确认密码",
+ "account_updated": "更新账号",
+ "password_must_be_characters_or_more": "密码必须是%(amount)s个字母以上",
+ "need_password_or_key": "你需要一个私人密码或密钥(而不是公钥)",
+ "login_to_see_memo": "登录查看备注",
+ "new_password": "新密码",
+ "incorrect_password": "密码错误",
+ "username_does_not_exist": "用户名不存在",
+ "account_name_should_start_with_a_letter": "帐户名称应该以字母开头",
+ "account_name_should_be_shorter": "账户名应该更短",
+ "account_name_should_be_longer": "账户名应该更长",
+ "account_name_should_have_only_letters_digits_or_dashes":
+ "帐户名称应该只有字母、数字或破折号",
+ "cannot_increase_reward_of_post_within_the_last_minute_before_payout":
+ "在收到奖励前的最后一分钟内不能增加奖励",
+ "vote_currently_exists_user_must_be_indicate_a_to_reject_witness":
+ "已经投过此见证人,你是否想取消此见证人的投票",
+ "only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes":
+ "每10分钟一个IP地址只允许一个Steem账号",
+ "resteem_this_post": "转发这这篇文章",
+ "reblog": "转发",
+ "write_your_story": "写下你的故事",
+ "remember_voting_and_posting_key": "记住密码",
+ "auto_login_question_mark": "自动登录?",
+ "hide_private_key": "隐藏私钥",
+ "show_private_key": "显示私钥",
+ "login_to_show": "登录显示",
+ "not_valid_email": "不是有效的电子邮件",
+ "thank_you_for_being_an_early_visitor_to_APP_NAME":
+ "感谢你成为%(APP_NAME)早期访问者。我们将尽快回复你。",
+ "author_rewards": "作者奖励",
+ "curation_rewards": "审查奖励",
+ "sorry_your_reddit_account_doesnt_have_enough_karma":
+ "不好意思,你的Reddit级别不够高,我们不能为你免费注册账号。请在等候名单上加上你的电子邮件地址",
+ "register_with_facebook": "用Facebook注册",
+ "or_click_the_button_below_to_register_with_facebook":
+ "或者点击下面的按钮,用Facebook注册",
+ "server_returned_error": "服务器返回错误",
+ "APP_NAME_support": "%(APP_NAME)s的支持",
+ "please_email_questions_to": "请把你的问题发邮件给",
+ "next_7_strings_single_block": {
+ "authors_get_paid_when_people_like_you_upvote_their_post":
+ "当你和其他人给帖子点赞时,作者会得到报酬",
+ "if_you_enjoyed_what_you_read_earn_amount":
+ "如果你喜欢阅读这里的内容,请立即创建你的帐户,并开始免费赚取STEEM!",
+ "free_steem": "免费的Steem代币!",
+ "sign_up_earn_steem": "现在注册来赚取"
+ },
+ "next_3_strings_together": {
+ "show_more": "显示更多",
+ "show_less": "显示更少",
+ "value_posts": "低价值的帖子"
+ },
+ "read_only_mode":
+ "由于服务器维护,我们只在只读模式下运行。很抱歉给您带来不便。",
+ "tags_and_topics": "标签和主题",
+ "show_more_topics": "显示更多的主题",
+ "basic": "基本",
+ "advanced": "高级",
+ "views": {
+ "zero": "没有浏览量",
+ "one": "%(count)s个浏览",
+ "other": "%(count)s个浏览"
+ },
+ "responses": {
+ "zero": "没有回复",
+ "one": "%(count)s回复",
+ "other": "%(count)s个回复"
+ }
+ },
+ "navigation": {
+ "about": "关于",
+ "explore": "探索",
+ "APP_NAME_whitepaper": "%(APP_NAME)s的白皮书",
+ "buy_LIQUID_TOKEN": "购买%(LIQUID_TOKEN)s",
+ "sell_LIQUID_TOKEN": "出售%(LIQUID_TOKEN)s",
+ "currency_market": "货币市场",
+ "stolen_account_recovery": "被盗账户恢复",
+ "change_account_password": "更改帐户密码",
+ "witnesses": "见证人",
+ "vote_for_witnesses": "投票给见证人",
+ "privacy_policy": "隐私政策",
+ "terms_of_service": "服务条款",
+ "sign_up": "注册",
+ "learn_more": "了解更多",
+ "welcome": "欢迎",
+ "faq": "常见问题",
+ "chat": "Steemit聊天",
+ "app_center": "Steemit应用中心",
+ "api_docs": "Steemit API文档",
+ "whitepaper": "Steem白皮书",
+ "intro_tagline": "妙笔生金",
+ "intro_paragraph":
+ "你的思想是有有价值的。赶快加入发表文章获得赏金的社区。"
+ },
+ "main_menu": {
+ "hot": "热门",
+ "trending": "流行"
+ },
+ "reply_editor": {
+ "shorten_title": "缩短标题",
+ "exceeds_maximum_length": "超过最大长度(%(maxKb)sKB)",
+ "including_the_category": "(包括类别'%(rootCategory)s ')",
+ "use_limited_amount_of_tags":
+ "你总共可以标记%(tagsLength)s个标签%(includingCategory)s。请在你的文章分类栏中最多使用5个标签。",
+ "are_you_sure_you_want_to_clear_this_form": "你确定要清除这个表格吗?",
+ "uploading": "上传",
+ "draft_saved": "草稿已保存。",
+ "editor": "编辑器",
+ "insert_images_by_dragging_dropping": "通过拖拽插入图片",
+ "pasting_from_the_clipboard": "从剪贴板粘贴",
+ "selecting_them": "选择它们",
+ "image_upload": "图片上传",
+ "power_up_100": "Power Up 100%%",
+ "default_50_50": "默认(50%% / 50%%)",
+ "decline_payout": "拒绝赏金",
+ "check_this_to_auto_upvote_your_post": "点击按钮,自动投票你的帖子",
+ "markdown_styling_guide": "Markdown的格式指南",
+ "or_by": "或通过",
+ "title": "标题",
+ "update_post": "更新帖子",
+ "markdown_not_supported": "这里不支持Markdown标记语言"
+ },
+ "category_selector_jsx": {
+ "tag_your_story": "标签(最多5个标签),第一个标签是您文章的主要类别。",
+ "select_a_tag": "选择一个标签",
+ "maximum_tag_length_is_24_characters": "最大标签长度为24个字符",
+ "use_limited_amount_of_categories": "请只使用%(amount)s个类别",
+ "use_only_lowercase_letters": "只使用小写字母",
+ "use_one_dash": "只使用一个破折号",
+ "use_spaces_to_separate_tags": "使用空格分隔标签",
+ "use_only_allowed_characters": "只使用小写字母、数字和一个破折号",
+ "must_start_with_a_letter": "必须从一个字母开始",
+ "must_end_with_a_letter_or_number": "必须以字母或数字结尾"
+ },
+ "postfull_jsx": {
+ "this_post_is_not_available_due_to_a_copyright_claim":
+ "由于版权限制,暂不能显示这篇文章。",
+ "share_on_facebook": "分享到脸书",
+ "share_on_twitter": "分享到推特",
+ "share_on_linkedin": "分享到Linkedin",
+ "recent_password": "最近的密码",
+ "in_week_convert_DEBT_TOKEN_to_LIQUID_TOKEN":
+ "在3.5天内,将%(amount)s%(DEBT_TOKEN)s兑换为%(LIQUID_TOKEN)s",
+ "view_the_full_context": "查看全文",
+ "view_the_direct_parent": "查看上一级",
+ "you_are_viewing_a_single_comments_thread_from":
+ "你正在查看单个评论的主题"
+ },
+ "market_jsx": {
+ "action": "功能",
+ "date_created": "创建日期",
+ "last_price": "上一个成交价格",
+ "24h_volume": "24小时交易量",
+ "spread": "波动",
+ "total": "总量",
+ "available": "有效的",
+ "lowest_ask": "最低卖价",
+ "highest_bid": "最高买价",
+ "buy_orders": "买单",
+ "sell_orders": "卖单",
+ "trade_history": "交易历史",
+ "open_orders": "订单",
+ "sell_amount_for_atleast":
+ "出售%(amount_to_sell)s至少为%(min_to_receive)s(%(effectivePrice)s)",
+ "buy_atleast_amount_for":
+ "购买%(min_to_receive)s在%(amount_to_sell)s(%(effectivePrice)s)",
+ "price_warning_above":
+ "这个价格远高于目前的市场价%(marketPrice)s,您确定吗?",
+ "price_warning_below":
+ "这个价格远低于目前的市场价%(marketPrice)s,您确定吗?",
+ "order_cancel_confirm": "从%(user)s中取消订单%(order_id)s ?",
+ "order_cancelled": "订单%(order_id)s取消了。",
+ "higher": "更高的",
+ "lower": "更低的",
+ "total_DEBT_TOKEN_SHORT_CURRENCY_SIGN":
+ "总共%(DEBT_TOKEN_SHORT)s (%(CURRENCY_SIGN)s)"
+ },
+ "recoveraccountstep1_jsx": {
+ "begin_recovery": "开始恢复",
+ "not_valid": "无效的",
+ "account_name_is_not_found": "未找到帐户名",
+ "unable_to_recover_account_not_change_ownership_recently":
+ "我们无法恢复这个帐户,它最近没有改变所有权。",
+ "password_not_used_in_last_days":
+ "在过去的30天里这个帐户没有使用过这个密码。",
+ "request_already_submitted_contact_support":
+ "您的请求已经提交,我们正在处理。请联系%(SUPPORT_EMAIL)s以获得您的请求的状态。",
+ "recover_account_intro":
+ "有时候,Steemit 的拥有者钥匙可能会被盗用。被盗帐户恢复给予合法的帐户所有者30天,从小偷更改其所有者密钥的时候恢复其帐户。盗用帐户恢复只能在%(APP_URL)s上使用,如果帐户所有者已经明确列出 %(APP_NAME)s作为其帐户受信任者,并遵守了 %(APP_NAME)s 的服务条款。",
+ "login_with_facebook_or_reddit_media_to_verify_identity":
+ "请登录Facebook或Reddit以验证你的身份",
+ "login_with_social_media_to_verify_identity":
+ "请登录%(provider)s以验证你的身份",
+ "enter_email_toverify_identity":
+ "我们需要核实您的身份。请输入你的电子邮件地址,并开始验证。",
+ "continue_with_email": "继续使用邮箱",
+ "thanks_for_submitting_request_for_account_recovery":
+ "感谢你使用%(APP_NAME)s基于区块链的多因素身份验证提交帐户恢复请求。我们会尽快给你答复,但是由于大量的邮件可能会有一些延迟。请准备核实你的身份。",
+ "recovering_account": "正在恢复账户",
+ "recover_account": "恢复帐户",
+ "checking_account_owner": "验证账户所有者",
+ "sending_recovery_request": "发送恢复请求",
+ "cant_confirm_account_ownership":
+ "我们不能确认帐户所有权。请检查你的密码",
+ "account_recovery_request_not_confirmed":
+ "帐户恢复请求尚未确认,请稍后回来,谢谢你的耐心。"
+ },
+ "user_profile": {
+ "unknown_account": "未知的账户",
+ "user_hasnt_made_any_posts_yet": "看起来%(name)s还没有发过任何帖子!",
+ "user_hasnt_started_bloggin_yet": "看起来%(name)s还没有开始写博客!",
+ "user_hasnt_followed_anything_yet":
+ "看起来%(name)s还没有关注任何人!如果%(name)s最近添加关注了新的用户,他们的个性化主页上将会有显示。",
+ "user_hasnt_had_any_replies_yet": "%(name)s目前还没有回复",
+ "followers": "关注者",
+ "this_is_users_reputations_score_it_is_based_on_history_of_votes":
+ "这是%(name)s的声誉分数。声誉分数取决于账户收到的历史投票记录, 用于隐藏低质量的内容。",
+ "follower_count": {
+ "zero": "没有关注者",
+ "one": "1个关注者",
+ "other": "%(count)s个关注者"
+ },
+ "followed_count": {
+ "zero": "没有关注任何人",
+ "one": "关注1人",
+ "other": "关注%(count)s人"
+ },
+ "post_count": {
+ "zero": "没有帖子",
+ "one": "1个帖子",
+ "other": "%(count)s个帖子"
+ }
+ },
+ "authorrewards_jsx": {
+ "estimated_author_rewards_last_week": "预计上周作者奖励",
+ "author_rewards_history": "作者奖励历史"
+ },
+ "curationrewards_jsx": {
+ "estimated_curation_rewards_last_week": "预计上周审查奖励",
+ "curation_rewards_history": "审查奖励历史"
+ },
+ "post_jsx": {
+ "now_showing_comments_with_low_ratings": "正在显示低评级的评论",
+ "sort_order": "排序",
+ "comments_were_hidden_due_to_low_ratings": "评论由于评级不足而被隐藏"
+ },
+ "voting_jsx": {
+ "flagging_post_can_remove_rewards_the_flag_should_be_used_for_the_following":
+ "举报帖子可撤销奖励且使其不可见。常见举报原因",
+ "disagreement_on_rewards": "奖励不一致",
+ "fraud_or_plagiarism": "欺诈或剽窃",
+ "hate_speech_or_internet_trolling": "仇恨言论或互联网钓鱼",
+ "intentional_miss_categorized_content_or_spam":
+ "故意错误分类或垃圾信息",
+ "pending_payout": "待获得赏金$%(value)s",
+ "payout_declined": "拒绝赏金",
+ "max_accepted_payout": "赏金上限$%(value)s",
+ "promotion_cost": "推广费$%(value)s",
+ "past_payouts": "累计赏金$%(value)s",
+ "past_payouts_author": "- 作者收入 $%(value)s",
+ "past_payouts_curators": " - 审查收入 $%(value)s",
+ "we_will_reset_curation_rewards_for_this_post":
+ "将重置你对这篇帖子的审查奖励",
+ "removing_your_vote": "取消你的投票",
+ "changing_to_an_upvote": "改为投票",
+ "changing_to_a_downvote": "改为差评",
+ "confirm_flag": "确认差评",
+ "and_more": "还有%(count)s次",
+ "votes_plural": {
+ "one": "%(count)s个投票",
+ "other": "%(count)s个投票"
+ }
+ },
+ "witnesses_jsx": {
+ "witness_thread": "见证人帖子",
+ "top_witnesses": "见证人投票",
+ "you_have_votes_remaining": {
+ "zero": "你无剩余选票",
+ "one": "你还剩1张选票",
+ "other": "你还剩%(count)s张选票"
+ },
+ "you_can_vote_for_maximum_of_witnesses": "你最多可以投票30位见证人",
+ "witness": "见证人",
+ "information": "信息",
+ "if_you_want_to_vote_outside_of_top_enter_account_name":
+ "如果你想为50名以外的见证人投票,请输入帐户名称进行投票",
+ "set_witness_proxy":
+ "你也可以指定代理人来代替你给见证人投票。这将重置你当前的见证人选择。",
+ "witness_set":
+ "你已经设置投票代理。如果你想重新启用手动投票,请清除你的代理。",
+ "witness_proxy_current": "你当前的投票代理人是",
+ "witness_proxy_set": "设置投票代理",
+ "witness_proxy_clear": "清除投票代理",
+ "proxy_update_error": "你的投票代理未更新"
+ },
+ "votesandcomments_jsx": {
+ "no_responses_yet_click_to_respond": "暂无回复。点击回复。",
+ "response_count_tooltip": {
+ "zero": "暂无回复。点击回复。",
+ "one": "1个回复。点击回复。",
+ "other": "%(count)s个回复。点击回复。"
+ },
+ "vote_count": {
+ "zero": "暂无投票",
+ "one": "1个投票",
+ "other": "%(count)s个投票"
+ }
+ },
+ "userkeys_jsx": {
+ "public": "公开的",
+ "private": "私有的",
+ "public_something_key": "公开的%(key)s密钥",
+ "private_something_key": "私有的%(key)s密钥",
+ "posting_key_is_required_it_should_be_different":
+ "Posting Key用于发帖和投票。它应与Active Key和Owner Key区分使用。",
+ "the_active_key_is_used_to_make_transfers_and_place_orders":
+ "Active Key用于转帐和在内部市场下单。",
+ "the_owner_key_is_required_to_change_other_keys":
+ "Owner Key是帐户的主密钥,用于更改其它密钥。",
+ "the_private_key_or_password_should_be_kept_offline":
+ "Owner Key的私钥或密码应尽可能保持离线。",
+ "the_memo_key_is_used_to_create_and_read_memos":
+ "Memo Key用于创建和读取备注。"
+ },
+ "suggestpassword_jsx": {
+ "APP_NAME_cannot_recover_passwords_keep_this_page_in_a_secure_location":
+ "%(APP_NAME)s无法恢复密码。请将此页面保存到安全的位置如防火保险箱。",
+ "APP_NAME_password_backup": "%(APP_NAME)s密码备份",
+ "APP_NAME_password_backup_required": "%(APP_NAME)s密码备份(必填)",
+ "after_printing_write_down_your_user_name": "打印后,请写下你的用户名"
+ },
+ "converttosteem_jsx": {
+ "your_existing_DEBT_TOKEN_are_liquid_and_transferable":
+ "你现有的%(DEBT_TOKEN)s是可流动和可转让的。你可以希望直接在本网站%(link)s交易%(DEBT_TOKEN)s或转移到外部市场。",
+ "this_is_a_price_feed_conversion":
+ "这通过系统喂价来进行转换。为了防止恶意欺骗系统喂价,你的转换需要等待3.5天",
+ "convert_to_LIQUID_TOKEN": "转换为%(LIQUID_TOKEN)s",
+ "DEBT_TOKEN_will_be_unavailable":
+ "此操作将在3.5天内完成且不能取消。这些%(DEBT_TOKEN)s将立即变得不可用"
+ },
+ "tips_js": {
+ "liquid_token":
+ "可交易代币可以在任何时候发送到任何地方。%(LIQUID_TOKEN)s可以在一个被称为Power Up的过程中被转换成%(VESTING_TOKEN)s。",
+ "influence_token":
+ "代币的影响力可以使你对文章的赏金有更大的控制权,并可以获得审查奖励。",
+ "estimated_value": "基于美元计算,%(LIQUID_TOKEN)s的估值。",
+ "non_transferable":
+ "%(VESTING_TOKEN)s是不可转让的,需要3个月(13笔付款)才可换回%(LIQUID_TOKEN)s",
+ "converted_VESTING_TOKEN_can_be_sent_to_yourself_but_can_not_transfer_again":
+ "%(VESTING_TOKEN)s可以转给你自己或其他人,但是只有转回%(LIQUID_TOKEN)s后,才可以进行下一次转账。",
+ "part_of_your_steem_power_is_currently_delegated":
+ "有一部分STEEM POWER是代理给你使用的。代理的STEEM POWER是为了帮助新用户在steemit上进行操作。你被代理的数量可能会有波动。"
+ },
+ "promote_post_jsx": {
+ "promote_post": "推广帖子",
+ "spend_your_DEBT_TOKEN_to_advertise_this_post":
+ "花费%(DEBT_TOKEN)s在推广模块宣传这篇帖子",
+ "you_successfully_promoted_this_post": "你成功的推广了这个帖子",
+ "this_post_was_hidden_due_to_low_ratings": "此贴由于评级不足而被隐藏"
+ },
+ "about_jsx": {
+ "about_app": "关于%(APP_NAME)s",
+ "about_app_details":
+ "%(APP_NAME)s是一个社交媒体平台,通过写文章和审查文章内容,每个人都可以得到赏金。它有一个强大的数字积分系统,称为Steem,其通过市场价格发现机制和流动性,来支撑数字奖励的真实价值。",
+ "learn_more_at_app_url": "了解更多%(APP_URL)s",
+ "resources": "资源"
+ },
+ "markdownviewer_jsx": {
+ "images_were_hidden_due_to_low_ratings": "图片由于评级不足而被隐藏。"
+ },
+ "postsummary_jsx": {
+ "resteemed": "已转发的",
+ "resteemed_by": "被转发的",
+ "this_post_is": "这篇帖子是",
+ "you_can": "你可以",
+ "reveal_it": "显示它",
+ "adjust_your": "调整你的",
+ "display_preferences": "显示偏好",
+ "create_an_account": "创建帐户",
+ "to_save_your_preferences": "保存你的偏好"
+ },
+ "posts_index": {
+ "empty_feed_1": "看起来你还没有关注任何人",
+ "empty_feed_2":
+ "如果你最近关注了新的用户,更新内容将会显示在你的个性化主页",
+ "empty_feed_3": "浏览流行文章",
+ "empty_feed_4": "阅读快速入门指南",
+ "empty_feed_5": "浏览常见问题解答"
+ },
+ "transferhistoryrow_jsx": {
+ "to_savings": "到储蓄账户",
+ "from_savings": "从储蓄账户",
+ "cancel_transfer_from_savings": "取消从储蓄账户转账",
+ "stop_power_down": "停止Power Down",
+ "start_power_down_of": "开始Power Down",
+ "receive_interest_of": "获得的利息"
+ },
+ "savingswithdrawhistory_jsx": {
+ "cancel_this_withdraw_request": "确认取消提款请求吗?",
+ "pending_savings_withdrawals": "即将取出存款",
+ "withdraw": "取%(amount)s",
+ "to": "到%(to)s",
+ "from_to": "从%(from)s到%(to)s"
+ },
+ "explorepost_jsx": {
+ "copied": "已复制!",
+ "copy": "复制",
+ "alternative_sources": "其他资源"
+ },
+ "header_jsx": {
+ "home": "主页",
+ "create_a_post": "发表帖子",
+ "change_account_password": "修改账户密码",
+ "create_account": "创建账户",
+ "stolen_account_recovery": "被盗账户恢复",
+ "people_following": "正在关注",
+ "people_followed_by": "关注 by",
+ "curation_rewards_by": "审查收入 by",
+ "author_rewards_by": "作者收入 by",
+ "replies_to": "回复",
+ "comments_by": "评论"
+ },
+ "loginform_jsx": {
+ "you_need_a_private_password_or_key":
+ "你需要一个私人密码或密钥(非公钥)",
+ "cryptography_test_failed": "加密测试失败",
+ "unable_to_log_you_in": "我们不允许使用当前浏览器登录。",
+ "the_latest_versions_of": "最新版本的",
+ "are_well_tested_and_known_to_work_with":
+ "是经过良好测试,并可以正常使用%(APP_URL)s的。",
+ "due_to_server_maintenance":
+ "由于服务器维护,我们只在只读模式下运行。很抱歉给您带来不便。",
+ "login_to_vote": "登录后投票",
+ "login_to_post": "登录后发帖",
+ "login_to_comment": "登录后评论",
+ "posting": "发帖",
+ "active_or_owner": "Active 或 Owner",
+ "this_password_is_bound_to_your_account_owner_key":
+ "此密码已绑定到您的帐户的Owner Key,不能用于登录到此站点。",
+ "however_you_can_use_it_to": "但是,您可以使用它来",
+ "update_your_password": "修改密码",
+ "to_obtain_a_more_secure_set_of_keys": "获取一组更安全的密钥。",
+ "this_password_is_bound_to_your_account_active_key":
+ "此密码已绑定到你的帐户的Active Key,不能用于登录到此页面。",
+ "you_may_use_this_active_key_on_other_more":
+ "你可以在其他更安全的页面上使用这个Active Key,比如钱包或市场页面。",
+ "you_account_has_been_successfully_created": "您的帐号已经成功创建!",
+ "you_account_has_been_successfully_recovered": "您的帐号已经成功恢复!",
+ "password_update_succes": "%(accountName)s的密码成功修改",
+ "password_info":
+ "密码或私钥输入不正确。有可能是输入错误。提示:Steemit创建的密码或私钥中永远不包含 0(零), O(大写O), I(大写i)和l (小写L)。",
+ "enter_your_username": "输入您的用户名",
+ "password_or_wif": "密码或WIF",
+ "this_operation_requires_your_key_or_master_password":
+ "此操作需要您的%(authType)s密钥或主密码。",
+ "keep_me_logged_in": "保持登录状态",
+ "amazing_community": "神奇的社区",
+ "to_comment_and_reward_others": "评论和奖励他人。",
+ "sign_up_now_to_earn": "现在就来注册赚取",
+ "free_money": "免费的钱!",
+ "returning_users": "返回用户:",
+ "join_our": "加入我们"
+ },
+ "chainvalidation_js": {
+ "account_name_should": "帐户名称应该",
+ "not_be_empty": "不是空的。",
+ "be_longer": "更长。",
+ "be_shorter": "更短。",
+ "each_account_segment_should": "每个帐户段应该",
+ "start_with_a_letter": "从一个字母开始。",
+ "have_only_letters_digits_or_dashes": "只有字母、数字或破折号",
+ "have_only_one_dash_in_a_row": "一行只有一个破折号",
+ "end_with_a_letter_or_digit": "字母或数字结尾",
+ "verified_exchange_no_memo": "如果你要转账到交易所,你必须填写备注。"
+ },
+ "settings_jsx": {
+ "invalid_url": "无效的URL",
+ "name_is_too_long": "名字太长了",
+ "name_must_not_begin_with": "名称必须以@开头",
+ "about_is_too_long": "关于字段的字符过多",
+ "location_is_too_long": "位置字段的字符过多",
+ "website_url_is_too_long": "网站URL太长",
+ "public_profile_settings": "公开主页设置",
+ "preferences": "显示私人文章设置",
+ "not_safe_for_work_nsfw_content": "不适合在工作时显示的(NSFW)内容",
+ "always_hide": "总是隐藏",
+ "always_warn": "总是警告",
+ "always_show": "总是显示",
+ "muted_users": "屏蔽的用户",
+ "update": "更新",
+ "profile_image_url": "个人头像的网址",
+ "cover_image_url": "封面图片的网址",
+ "profile_name": "显示名称",
+ "profile_about": "关于",
+ "profile_location": "位置",
+ "profile_website": "网站"
+ },
+ "transfer_jsx": {
+ "amount_is_in_form": "金额以99999.999的形式出现",
+ "insufficient_funds": "资金不足",
+ "use_only_3_digits_of_precison": "只能使用3位数的精度",
+ "send_to_account": "发送到账户",
+ "asset": "资产",
+ "this_memo_is_private": "这个备注是私有的",
+ "this_memo_is_public": "这个备注是公开的",
+ "convert_to_VESTING_TOKEN": "转换成%(VESTING_TOKEN)s",
+ "balance_subject_to_3_day_withdraw_waiting_period":
+ "余额取决于3天的提款等待期,",
+ "move_funds_to_another_account":
+ "将资金转移给另一个%(APP_NAME)s的用户。",
+ "protect_funds_by_requiring_a_3_day_withdraw_waiting_period":
+ "通过设置3天的提款等待期来保护资金。",
+ "withdraw_funds_after_the_required_3_day_waiting_period":
+ "需要在3天的等待期后提取资金。",
+ "from": "从",
+ "to": "到",
+ "asset_currently_collecting": "%(asset)s目前获得%(interest)s%%利息"
+ },
+ "userwallet_jsx": {
+ "conversion_complete_tip": "将完成在",
+ "in_conversion": "%(amount)s在转换",
+ "transfer_to_savings": "转移到储蓄",
+ "power_up": "Power Up",
+ "power_down": "Power Down",
+ "market": "市场",
+ "convert_to_LIQUID_TOKEN": "转换为%(LIQUID_TOKEN)s",
+ "withdraw_LIQUID_TOKEN": "取出%(LIQUID_TOKEN)s",
+ "withdraw_DEBT_TOKENS": "取出%(DEBT_TOKENS)s",
+ "tokens_worth_about_1_of_LIQUID_TICKER":
+ "价值约为1.00美金的%(LIQUID_TICKER)s,目前正在获得%(sbdInterest)s%%的利息。",
+ "savings": "储蓄",
+ "estimated_account_value": "账户估值",
+ "next_power_down_is_scheduled_to_happen":
+ "下一次的Power Down计划发生在",
+ "transfers_are_temporary_disabled": "转移功能暂时被禁用。",
+ "history": "历史",
+ "redeem_rewards": "赎回奖励(转移至余额)",
+ "buy_steem_or_steem_power": "购买STEEM或STEEM Power"
+ },
+ "powerdown_jsx": {
+ "power_down": "Power Down",
+ "amount": "数量",
+ "already_power_down":
+ "您已经在Power Down%(AMOUNT)s%(LIQUID_TICKER)s(%(WITHDRAWN)s目前得到%(LIQUID_TICKER)s)。如果你想改变Power Down的总额,你的周期固定奖励数量也会发生变化。",
+ "delegating":
+ "你正在代理出%(AMOUNT)s%(LIQUID_TICKER)s。该数量将被锁定并且不能Power Down,直到你取消代理,并经过一个完整的支付周期。",
+ "per_week": "这是每周%(AMOUNT)s%(LIQUID_TICKER)s 。",
+ "warning":
+ "不建议在你的帐户中持有少于%(AMOUNT)s%(VESTING_TOKEN)s,否则可能导致你的帐户处于不可用状态。",
+ "error": "无法Power Down(错误:%(MESSAGE)s)"
+ },
+ "checkloginowner_jsx": {
+ "your_password_permissions_were_reduced": "您的密码权限被减少",
+ "if_you_did_not_make_this_change": "如果你没有做这个更改,请",
+ "ownership_changed_on": "所有权变更",
+ "deadline_for_recovery_is": "恢复的截止日期是",
+ "i_understand_dont_show_again": "我明白,不要再显示"
+ }
+}
diff --git a/src/app/redux/AppReducer.js b/src/app/redux/AppReducer.js
index cb3e3ed8bc99c816dee97cfd8e380476bf8624d2..36828cbbffd1afeb0a56da3ce69606899bddd56c 100644
--- a/src/app/redux/AppReducer.js
+++ b/src/app/redux/AppReducer.js
@@ -1,13 +1,22 @@
-import {Map, OrderedMap} from 'immutable';
+import { Map, OrderedMap } from 'immutable';
import tt from 'counterpart';
-const defaultState = Map({
- requests: {},
+const STEEM_API_ERROR = 'app/STEEM_API_ERROR';
+const FETCH_DATA_BEGIN = 'app/FETCH_DATA_BEGIN';
+const FETCH_DATA_END = 'app/FETCH_DATA_END';
+const ADD_NOTIFICATION = 'app/ADD_NOTIFICATION';
+const REMOVE_NOTIFICATION = 'app/REMOVE_NOTIFICATION';
+const UPDATE_NOTIFICOUNTERS = 'app/UPDATE_NOTIFICOUNTERS';
+export const SET_USER_PREFERENCES = 'app/SET_USER_PREFERENCES';
+export const TOGGLE_NIGHTMODE = 'app/TOGGLE_NIGHTMODE';
+export const TOGGLE_BLOGMODE = 'app/TOGGLE_BLOGMODE';
+export const RECEIVE_FEATURE_FLAGS = 'app/RECEIVE_FEATURE_FLAGS';
+
+export const defaultState = Map({
loading: false,
error: '',
location: {},
notifications: null,
- ignoredLoadingRequestCount: 0,
notificounters: Map({
total: 0,
feed: 0,
@@ -19,60 +28,126 @@ const defaultState = Map({
reply: 0,
account_update: 0,
message: 0,
- receive: 0
+ receive: 0,
}),
user_preferences: Map({
locale: null,
nsfwPref: 'warn',
- theme: 'light',
+ nightmode: false,
blogmode: false,
- currency: 'USD'
- })
+ currency: 'USD',
+ }),
+ featureFlags: Map({}),
});
-export default function reducer(state = defaultState, action) {
- if (action.type === '@@router/LOCATION_CHANGE') {
- return state.set('location', {pathname: action.payload.pathname});
- }
- if (action.type === 'STEEM_API_ERROR') {
- return state.set('error', action.error).set('loading', false);
- }
- let res = state;
- if (action.type === 'FETCH_DATA_BEGIN') {
- res = state.set('loading', true);
- }
- if (action.type === 'FETCH_DATA_END') {
- res = state.set('loading', false);
- }
- if (action.type === 'ADD_NOTIFICATION') {
- const n = {
- action: tt('g.dismiss'),
- dismissAfter: 10000,
- ...action.payload
- };
- res = res.update('notifications', s => {
- return s ? s.set(n.key, n) : OrderedMap({[n.key]: n});
- });
- }
- if (action.type === 'REMOVE_NOTIFICATION') {
- res = res.update('notifications', s => s.delete(action.payload.key));
- }
- if (action.type === 'UPDATE_NOTIFICOUNTERS' && action.payload) {
- const nc = action.payload;
- if (nc.follow > 0) {
- nc.total -= nc.follow;
- nc.follow = 0;
+export default function reducer(state = defaultState, action = {}) {
+ switch (action.type) {
+ case '@@router/LOCATION_CHANGE':
+ return state.set('location', { pathname: action.payload.pathname });
+ case STEEM_API_ERROR:
+ // Until we figure out how to better handle these errors, let em slide.
+ // This action is the only part of the app that marks an error in state.app.error,
+ // and the only part of the app which pays attn to this part of the state is in App.jsx.
+ //return state.set('error', action.error).set('loading', false);
+ return state;
+ case FETCH_DATA_BEGIN:
+ return state.set('loading', true);
+ case FETCH_DATA_END:
+ return state.set('loading', false);
+ case ADD_NOTIFICATION: {
+ const n = {
+ action: tt('g.dismiss'),
+ dismissAfter: 10000,
+ ...action.payload,
+ };
+ return state.update('notifications', s => {
+ return s ? s.set(n.key, n) : OrderedMap({ [n.key]: n });
+ });
}
- res = res.set('notificounters', Map(nc));
- }
- if (action.type === 'SET_USER_PREFERENCES') {
- res = res.set('user_preferences', Map(action.payload));
- }
- if (action.type === 'TOGGLE_NIGHTMODE') {
- res = res.setIn(['user_preferences', 'nightmode'], !res.getIn(['user_preferences', 'nightmode']));
- }
- if (action.type === 'TOGGLE_BLOGMODE') {
- res = res.setIn(['user_preferences', 'blogmode'], !res.getIn(['user_preferences', 'blogmode']));
+ case REMOVE_NOTIFICATION:
+ return state.update('notifications', s =>
+ s.delete(action.payload.key)
+ );
+ case UPDATE_NOTIFICOUNTERS: {
+ if (action.payload) {
+ const nc = action.payload;
+ if (nc.follow > 0) {
+ nc.total -= nc.follow;
+ nc.follow = 0;
+ }
+ return state.set('notificounters', Map(nc));
+ }
+ return state;
+ }
+ case SET_USER_PREFERENCES:
+ return state.set('user_preferences', Map(action.payload));
+ case TOGGLE_NIGHTMODE:
+ return state.setIn(
+ ['user_preferences', 'nightmode'],
+ !state.getIn(['user_preferences', 'nightmode'])
+ );
+ case TOGGLE_BLOGMODE:
+ return state.setIn(
+ ['user_preferences', 'blogmode'],
+ !state.getIn(['user_preferences', 'blogmode'])
+ );
+ case RECEIVE_FEATURE_FLAGS:
+ const newFlags = state.get('featureFlags')
+ ? state.get('featureFlags').merge(action.flags)
+ : Map(action.flags);
+ return state.set('featureFlags', newFlags);
+ default:
+ return state;
}
- return res;
}
+
+export const steemApiError = error => ({
+ type: STEEM_API_ERROR,
+ error,
+});
+
+export const fetchDataBegin = () => ({
+ type: FETCH_DATA_BEGIN,
+});
+
+export const fetchDataEnd = () => ({
+ type: FETCH_DATA_END,
+});
+
+export const addNotification = payload => ({
+ type: ADD_NOTIFICATION,
+ payload,
+});
+
+export const removeNotification = payload => ({
+ type: REMOVE_NOTIFICATION,
+ payload,
+});
+
+export const updateNotificounters = payload => ({
+ type: UPDATE_NOTIFICOUNTERS,
+ payload,
+});
+
+export const setUserPreferences = payload => ({
+ type: SET_USER_PREFERENCES,
+ payload,
+});
+
+export const toggleNightmode = () => ({
+ type: TOGGLE_NIGHTMODE,
+});
+
+export const toggleBlogmode = () => ({
+ type: TOGGLE_BLOGMODE,
+});
+
+export const receiveFeatureFlags = flags => ({
+ type: RECEIVE_FEATURE_FLAGS,
+ flags,
+});
+
+export const selectors = {
+ getFeatureFlag: (state, flagName) =>
+ state.getIn(['featureFlags', flagName], false),
+};
diff --git a/src/app/redux/AppReducer.test.js b/src/app/redux/AppReducer.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..a359abcb7c1da38013ab74d90339355384797e8d
--- /dev/null
+++ b/src/app/redux/AppReducer.test.js
@@ -0,0 +1,185 @@
+import { Map, OrderedMap, getIn } from 'immutable';
+
+import reducer, {
+ defaultState,
+ steemApiError,
+ fetchDataBegin,
+ fetchDataEnd,
+ addNotification,
+ removeNotification,
+ updateNotificounters,
+ setUserPreferences,
+ receiveFeatureFlags,
+ selectors,
+ toggleNightmode,
+ toggleBlogmode,
+} from './AppReducer';
+
+const mockPayloads = {
+ addNotification: {
+ key: 'testKey',
+ },
+ removeNotification: {
+ pathname: 'testPath',
+ },
+ updateNotificounters: {
+ follow: 1,
+ total: 2,
+ },
+ updateNotificountersNoFollow: {
+ follow: 0,
+ total: 2,
+ },
+ removeNotification: {
+ key: 'testKey',
+ },
+ setUserPreferences: {
+ cat: 'mymy',
+ dog: 'polly',
+ },
+};
+
+const mockActions = {
+ LOCATION_CHANGE: {
+ type: '@@router/LOCATION_CHANGE',
+ payload: {
+ pathname: 'testPath',
+ },
+ },
+};
+
+const key = mockPayloads.addNotification.key;
+const mockNotification = OrderedMap({
+ [key]: {
+ action: 'missing translation: en.g.dismiss',
+ dismissAfter: 10000,
+ key,
+ },
+});
+
+describe('App reducer', () => {
+ it('should provide a nice initial state', () => {
+ const initial = reducer();
+ expect(initial).toBe(defaultState);
+ });
+ it('should return correct state for a LOCATION_CHANGE action', () => {
+ const initial = reducer();
+ const actual = reducer(initial, mockActions['LOCATION_CHANGE']);
+ const out = actual.get('location');
+ expect(out.pathname).toEqual(
+ mockActions['LOCATION_CHANGE'].payload.pathname
+ );
+ });
+ it('should return correct state for a STEEM_API_ERROR action', () => {
+ const initial = reducer();
+ const out = reducer(initial, steemApiError());
+ expect(out).toEqual(initial);
+ });
+ it('should return correct state for a FETCH_DATA_BEGIN action', () => {
+ const initial = reducer();
+ const actual = reducer(initial, fetchDataBegin());
+ const out = actual.get('loading');
+ expect(out).toEqual(true);
+ });
+ it('should return correct state for a FETCH_DATA_END action', () => {
+ const initial = reducer();
+ const actual = reducer(initial, fetchDataEnd());
+ const out = actual.get('loading');
+ expect(out).toEqual(false);
+ });
+ it('should return correct state for a ADD_NOTIFICATION action', () => {
+ const initial = reducer();
+ const actual = reducer(
+ initial,
+ addNotification(mockPayloads.addNotification)
+ );
+ const out = actual.getIn(['notifications', key]);
+ expect(out).toEqual(mockNotification.get(key));
+ });
+ it('should return correct state for a REMOVE_NOTIFICATION action', () => {
+ const initial = reducer();
+ const initialWithNotification = initial.set(
+ 'notifications',
+ mockNotification
+ );
+ const actual = reducer(
+ initialWithNotification,
+ removeNotification(mockPayloads.removeNotification)
+ );
+ const out = actual.get('notifications');
+ const expected = OrderedMap();
+ expect(out).toEqual(expected);
+ });
+ it('should return correct state for a UPDATE_NOTIFICOUNTERS action with a follow in payload', () => {
+ const initial = reducer();
+ let actual = reducer(
+ initial,
+ updateNotificounters(mockPayloads.updateNotificounters)
+ );
+
+ let out = actual.get('notificounters');
+ let expected = Map({ follow: 0, total: 1 });
+ expect(out).toEqual(expected);
+ });
+ it('should return correct state for a UPDATE_NOTIFICOUNTERS action with no follow in payload', () => {
+ const initial = reducer();
+ const actual = reducer(
+ initial,
+ updateNotificounters(mockPayloads.updateNotificountersNoFollow)
+ );
+ const out = actual.get('notificounters');
+ const expected = Map({ follow: 0, total: 2 });
+ expect(out).toEqual(expected);
+ });
+ it('should return correct state for a SET_USER_PREFERENCES action', () => {
+ const initial = reducer();
+ let actual = reducer(
+ initial,
+ setUserPreferences(mockPayloads.setUserPreferences)
+ );
+ let out = actual.get('user_preferences');
+ let expected = Map({ cat: 'mymy', dog: 'polly' });
+ expect(out).toEqual(expected);
+ });
+ it('should return correct state for a TOGGLE_NIGHTMODE action', () => {
+ const initial = reducer();
+ const before = initial.getIn(['user_preferences', 'nightmode']);
+ let actual = reducer(initial, toggleNightmode());
+ const after = actual.getIn(['user_preferences', 'nightmode']);
+ expect(after).toEqual(!before);
+ });
+ it('should return correct state for a TOGGLE_BLOGMODE action', () => {
+ const initial = reducer();
+ const before = initial.getIn(['user_preferences', 'blogmode']);
+ let actual = reducer(initial, toggleBlogmode());
+ const after = actual.getIn(['user_preferences', 'blogmode']);
+ expect(after).toEqual(!before);
+ });
+ test('should merge in received feature flags', () => {
+ // Arrange
+ const initial = reducer();
+
+ // Act
+ const withFlags = reducer(
+ initial,
+ receiveFeatureFlags({
+ flying: true,
+ })
+ );
+ const withMoreFlags = reducer(
+ withFlags,
+ receiveFeatureFlags({
+ swimming: false,
+ })
+ );
+
+ // Assert
+ expect(selectors.getFeatureFlag(withMoreFlags, 'swimming')).toEqual(
+ false
+ );
+ expect(selectors.getFeatureFlag(withMoreFlags, 'flying')).toEqual(true);
+ expect(selectors.getFeatureFlag(withMoreFlags, 'dancing')).toEqual(
+ false
+ );
+ });
+});
diff --git a/src/app/redux/AuthSaga.js b/src/app/redux/AuthSaga.js
index 990303d071b31f4543b8bed811a34e2760ed7186..a2f6f10ceeefe769a4dec222f6acd7cae05a92cd 100644
--- a/src/app/redux/AuthSaga.js
+++ b/src/app/redux/AuthSaga.js
@@ -1,49 +1,66 @@
-import {takeEvery} from 'redux-saga';
-import {call, put, select} from 'redux-saga/effects';
-import {Set, Map, fromJS, List} from 'immutable'
-import user from 'app/redux/User'
-import {getAccount} from 'app/redux/SagaShared'
-import {PrivateKey} from 'steem/lib/auth/ecc';
-import {api} from 'steem';
+import { takeEvery } from 'redux-saga';
+import { call, put, select } from 'redux-saga/effects';
+import { Set, Map, fromJS, List } from 'immutable';
+import { api } from '@steemit/steem-js';
+import { PrivateKey } from '@steemit/steem-js/lib/auth/ecc';
+
+import { getAccount } from 'app/redux/SagaShared';
+import * as userActions from 'app/redux/UserReducer';
// operations that require only posting authority
-const postingOps = Set(`vote, comment, delete_comment, custom_json, claim_reward_balance`.trim().split(/,\s*/))
+const postingOps = Set(
+ `vote, comment, delete_comment, custom_json, claim_reward_balance`
+ .trim()
+ .split(/,\s*/)
+);
-export const authWatches = [
- watchForAuth
-]
+export const authWatches = [watchForAuth];
function* watchForAuth() {
yield* takeEvery('user/ACCOUNT_AUTH_LOOKUP', accountAuthLookup);
}
-export function* accountAuthLookup({payload: {account, private_keys, login_owner_pubkey}}) {
- account = fromJS(account)
- private_keys = fromJS(private_keys)
+export function* accountAuthLookup({
+ payload: { account, private_keys, login_owner_pubkey },
+}) {
+ account = fromJS(account);
+ private_keys = fromJS(private_keys);
// console.log('accountAuthLookup', account.name)
- const stateUser = yield select(state => state.user)
- let keys
- if (private_keys)
- keys = private_keys
- else
- keys = stateUser.getIn(['current', 'private_keys'])
-
- if (!keys || !keys.has('posting_private')) return
- const toPub = k => k ? k.toPublicKey().toString() : '-'
- const posting = keys.get('posting_private')
- const active = keys.get('active_private')
- const memo = keys.get('memo_private')
+ const stateUser = yield select(state => state.user);
+ let keys;
+ if (private_keys) keys = private_keys;
+ else keys = stateUser.getIn(['current', 'private_keys']);
+
+ if (!keys || !keys.has('posting_private')) return;
+ const toPub = k => (k ? k.toPublicKey().toString() : '-');
+ const posting = keys.get('posting_private');
+ const active = keys.get('active_private');
+ const memo = keys.get('memo_private');
const auth = {
- posting: posting ? yield authorityLookup(
- {pubkeys: Set([toPub(posting)]), authority: account.get('posting'), authType: 'posting'}) : 'none',
- active: active ? yield authorityLookup(
- {pubkeys: Set([toPub(active)]), authority: account.get('active'), authType: 'active'}) : 'none',
+ posting: posting
+ ? yield authorityLookup({
+ pubkeys: Set([toPub(posting)]),
+ authority: account.get('posting'),
+ authType: 'posting',
+ })
+ : 'none',
+ active: active
+ ? yield authorityLookup({
+ pubkeys: Set([toPub(active)]),
+ authority: account.get('active'),
+ authType: 'active',
+ })
+ : 'none',
owner: 'none',
- memo: account.get('memo_key') === toPub(memo) ? 'full' : 'none'
- }
- const accountName = account.get('name')
- const pub_keys_used = {posting: toPub(posting), active: toPub(active), owner: login_owner_pubkey};
- yield put(user.actions.setAuthority({accountName, auth, pub_keys_used}))
+ memo: account.get('memo_key') === toPub(memo) ? 'full' : 'none',
+ };
+ const accountName = account.get('name');
+ const pub_keys_used = {
+ posting: toPub(posting),
+ active: toPub(active),
+ owner: login_owner_pubkey,
+ };
+ yield put(userActions.setAuthority({ accountName, auth, pub_keys_used }));
}
/**
@@ -52,91 +69,102 @@ export function* accountAuthLookup({payload: {account, private_keys, login_owner
@arg {object} data.pubkeys Immutable Set public key strings
@return {string} full, partial, none
*/
-function* authorityLookup({pubkeys, authority, authType}) {
- return yield call(authStr, {pubkeys, authority, authType})
+function* authorityLookup({ pubkeys, authority, authType }) {
+ return yield call(authStr, { pubkeys, authority, authType });
}
-function* authStr({pubkeys, authority, authType, recurse = 1}) {
- const t = yield call(threshold, {pubkeys, authority, authType, recurse})
- const r = authority.get('weight_threshold')
- return t >= r ? 'full' : t > 0 ? 'partial' : 'none'
+function* authStr({ pubkeys, authority, authType, recurse = 1 }) {
+ const t = yield call(threshold, { pubkeys, authority, authType, recurse });
+ const r = authority.get('weight_threshold');
+ return t >= r ? 'full' : t > 0 ? 'partial' : 'none';
}
-export function* threshold({pubkeys, authority, authType, recurse = 1}) {
- if (!pubkeys.size) return 0
- let t = pubkeyThreshold({pubkeys, authority})
- const account_auths = authority.get('account_auths')
- const aaNames = account_auths.map(v => v.get(0), List())
+export function* threshold({ pubkeys, authority, authType, recurse = 1 }) {
+ if (!pubkeys.size) return 0;
+ let t = pubkeyThreshold({ pubkeys, authority });
+ const account_auths = authority.get('account_auths');
+ const aaNames = account_auths.map(v => v.get(0), List());
if (aaNames.size) {
- const aaAccounts = yield api.getAccountsAsync(aaNames)
- const aaThreshes = account_auths.map(v => v.get(1), List())
+ const aaAccounts = yield api.getAccountsAsync(aaNames);
+ const aaThreshes = account_auths.map(v => v.get(1), List());
for (let i = 0; i < aaAccounts.size; i++) {
- const aaAccount = aaAccounts.get(i)
- t += pubkeyThreshold({authority: aaAccount.get(authType), pubkeys})
+ const aaAccount = aaAccounts.get(i);
+ t += pubkeyThreshold({
+ authority: aaAccount.get(authType),
+ pubkeys,
+ });
if (recurse <= 2) {
- const auth = yield call(authStr,
- {authority: aaAccount, pubkeys, recurse: ++recurse})
+ const auth = yield call(authStr, {
+ authority: aaAccount,
+ pubkeys,
+ recurse: ++recurse,
+ });
if (auth === 'full') {
- const aaThresh = aaThreshes.get(i)
- t += aaThresh
+ const aaThresh = aaThreshes.get(i);
+ t += aaThresh;
}
}
}
}
- return t
+ return t;
}
-function pubkeyThreshold({pubkeys, authority}) {
- let available = 0
- const key_auths = authority.get('key_auths')
+function pubkeyThreshold({ pubkeys, authority }) {
+ let available = 0;
+ const key_auths = authority.get('key_auths');
key_auths.forEach(k => {
if (pubkeys.has(k.get(0))) {
- available += k.get(1)
+ available += k.get(1);
}
- })
- return available
+ });
+ return available;
}
-export function* findSigningKey({opType, username, password}) {
- let authTypes
- if (postingOps.has(opType))
- authTypes = 'posting, active'
- else
- authTypes = 'active, owner'
- authTypes = authTypes.split(', ')
+export function* findSigningKey({ opType, username, password }) {
+ let authTypes;
+ if (postingOps.has(opType)) authTypes = 'posting, active';
+ else authTypes = 'active, owner';
+ authTypes = authTypes.split(', ');
- const currentUser = yield select(state => state.user.get('current'))
- const currentUsername = currentUser && currentUser.get('username')
+ const currentUser = yield select(state => state.user.get('current'));
+ const currentUsername = currentUser && currentUser.get('username');
- username = username || currentUsername
- if (!username) return null
+ username = username || currentUsername;
+ if (!username) return null;
- const private_keys = currentUsername === username ? currentUser.get('private_keys') : Map()
+ const private_keys =
+ currentUsername === username ? currentUser.get('private_keys') : Map();
const account = yield call(getAccount, username);
- if (!account) throw new Error('Account not found')
+ if (!account) throw new Error('Account not found');
for (const authType of authTypes) {
- let private_key
+ let private_key;
if (password) {
try {
- private_key = PrivateKey.fromWif(password)
+ private_key = PrivateKey.fromWif(password);
} catch (e) {
- private_key = PrivateKey.fromSeed(username + authType + password)
+ private_key = PrivateKey.fromSeed(
+ username + authType + password
+ );
}
} else {
- if(private_keys)
- private_key = private_keys.get(authType + '_private')
+ if (private_keys)
+ private_key = private_keys.get(authType + '_private');
}
if (private_key) {
- const pubkey = private_key.toPublicKey().toString()
- const pubkeys = Set([pubkey])
- const authority = account.get(authType)
- const auth = yield call(authorityLookup, {pubkeys, authority, authType})
- if (auth === 'full') return private_key
+ const pubkey = private_key.toPublicKey().toString();
+ const pubkeys = Set([pubkey]);
+ const authority = account.get(authType);
+ const auth = yield call(authorityLookup, {
+ pubkeys,
+ authority,
+ authType,
+ });
+ if (auth === 'full') return private_key;
}
}
- return null
+ return null;
}
// function isPostingOnlyKey(pubkey, account) {
diff --git a/src/app/redux/DemoState.js b/src/app/redux/DemoState.js
index 86aaac51c47bd32f3c24f7958cd79581aa96c02a..547e19299d37400f855321ccfd3d79dbaca84cfb 100644
--- a/src/app/redux/DemoState.js
+++ b/src/app/redux/DemoState.js
@@ -9,9 +9,9 @@ module.exports = {
server_response: null,
error: null,
confirmed: {
- blocknum: 1234
- }
- }
+ blocknum: 1234,
+ },
+ },
},
wallet: {
locked: false,
@@ -20,12 +20,12 @@ module.exports = {
$pubkey: 'privkey',
$pubkey1: 'privkey1',
$pubkey2: 'privkey2',
- $pubkey3: 'privkey3'
+ $pubkey3: 'privkey3',
},
encrypted_keys: {
- $pubkey: 'encryptedprivkey'
- }
- }
+ $pubkey: 'encryptedprivkey',
+ },
+ },
},
users: {
alice: {
@@ -36,90 +36,63 @@ module.exports = {
transfer: [],
vote: [],
post: [],
- reward: []
+ reward: [],
},
posts: {
recent: ['slug', 'slug1'],
expiring: ['slug', 'slug'],
- best: ['slug', 'slug']
+ best: ['slug', 'slug'],
},
proxy: null,
- witness_votes: []
- }
- }
+ witness_votes: [],
+ },
+ },
},
discussions: {
- update_status: { /// used to track async state of fetching
+ update_status: {
+ /// used to track async state of fetching
trending: {
last_update: new Date(),
fetching: false,
timeout: new Date(),
- fetch_cursor: null /// fetching from start, else author/slug
+ fetch_cursor: null, /// fetching from start, else author/slug
},
recent: {},
expiring: {},
best: {},
active: {},
category: {
- general: { /// the category name
- trending: { /// ~trending within category
+ general: {
+ /// the category name
+ trending: {
+ /// ~trending within category
last_update: new Date(),
fetching: false,
timeout: new Date(),
- fetch_cursor: null /// fetching from start, else author/slug
+ fetch_cursor: null, /// fetching from start, else author/slug
},
recent: {},
expiring: {},
- best: {}
- }
- }
+ best: {},
+ },
+ },
},
- trending: [
- 'author/slug',
- 'author3/slug'
- ],
- recent: [
- 'author3/slug',
- 'author/slug'
- ],
- expiring: [
- 'author3/slug',
- 'author/slug'
- ],
- best: [
- 'author2/slug',
- 'author/slug'
- ],
- active: [
- 'author1/slug',
- 'author/slug'
- ],
+ trending: ['author/slug', 'author3/slug'],
+ recent: ['author3/slug', 'author/slug'],
+ expiring: ['author3/slug', 'author/slug'],
+ best: ['author2/slug', 'author/slug'],
+ active: ['author1/slug', 'author/slug'],
category: {
'~trending': ['cat1', 'cat2'], /// used to track trending categories
'~best': ['bestcat1', 'bestcat2'], /// used to track all time best categories
'~active': [],
general: {
- trending: [
- 'author/slug',
- 'author3/slug'
- ],
- recent: [
- 'author2/slug',
- 'author3/slug'
- ],
- expiring: [
- 'author1/slug',
- 'author/slug'
- ],
- best: [
- 'author2/slug',
- 'author3/slug'
- ],
- active: [
- 'author2/slug',
- 'author3/slug'
- ]
- }
+ trending: ['author/slug', 'author3/slug'],
+ recent: ['author2/slug', 'author3/slug'],
+ expiring: ['author1/slug', 'author/slug'],
+ best: ['author2/slug', 'author3/slug'],
+ active: ['author2/slug', 'author3/slug'],
+ },
},
'author/slug': {
fetched: new Date(), /// the date at which this data was requested from the server
@@ -146,49 +119,50 @@ module.exports = {
total_pending_payout_value: '0.000 CLOUT',
replies: [], /// there is data to be fetched if 'children' is not 0
fetched_replies: new Date(),
- fetching_replies: false
- }
+ fetching_replies: false,
+ },
},
market: {
- current_feed: 1.00,
+ current_feed: 1.0,
feed_history: [
/// last week of feed data with 1 hr sampling of median feed
],
order_history: [
- ['time', 'buy', 1000, 1.000], /// time, type, quantity, price
- ['time', 'sell', 100, 0.99]
+ ['time', 'buy', 1000, 1.0], /// time, type, quantity, price
+ ['time', 'sell', 100, 0.99],
],
available_candlesticks: [5, 15, 30, 120, 240, 1440],
- available_zoom: [6, 24, 48, 96, 168/* 1 week*/, 540, 1000000/*all*/], /// hours
+ available_zoom: [6, 24, 48, 96, 168 /* 1 week*/, 540, 1000000 /*all*/], /// hours
current_candlestick: 5, /// min
current_zoom: 24, /// hours
price_history: [
{
time: '2016-02-29T22:08:00',
- open: 1.000,
- close: 1.000,
- high: 1.000,
- low: 1.000,
- volume: 10
+ open: 1.0,
+ close: 1.0,
+ high: 1.0,
+ low: 1.0,
+ volume: 10,
},
{
time: '2016-02-29T22:09:00',
- open: 1.000,
- close: 1.000,
- high: 1.000,
- low: 1.000,
- volume: 10
- }
- ]
+ open: 1.0,
+ close: 1.0,
+ high: 1.0,
+ low: 1.0,
+ volume: 10,
+ },
+ ],
},
- bids: [ /// sorted by price from highest to lowest
+ bids: [
+ /// sorted by price from highest to lowest
{
id: '...',
owner: 'alice',
price: 1.0,
quantity: 100,
cum_quantity: 100,
- expiration: null
+ expiration: null,
},
{
id: '...',
@@ -196,17 +170,18 @@ module.exports = {
price: 0.9,
quantity: 100,
cum_quantity: 200,
- expiration: null
- }
+ expiration: null,
+ },
],
- asks: [ /// sorted by price from lowest to highest
+ asks: [
+ /// sorted by price from lowest to highest
{
id: '...',
owner: 'alice',
price: 1.1,
bid_quantity: 100,
cum_quantity: 100,
- expiration: null
+ expiration: null,
},
{
id: '...',
@@ -214,7 +189,7 @@ module.exports = {
price: 1.2,
bid_quantity: 100,
cum_quantity: 200,
- expiration: null
- }
- ]
+ expiration: null,
+ },
+ ],
};
diff --git a/src/app/redux/EmptyState.js b/src/app/redux/EmptyState.js
index ad22649ebe9c54b2bf6bbfce4163b084383ee8ed..56f6b693a5986ddd0ccbe4675dd5c81bff4f5f77 100644
--- a/src/app/redux/EmptyState.js
+++ b/src/app/redux/EmptyState.js
@@ -1,7 +1,7 @@
/* Stub content (or objects) that may be inserted into the UI before being accepted by the blockchain. */
//TODO!
-import { LIQUID_TICKER, DEBT_TICKER } from 'app/client_config'
+import { LIQUID_TICKER, DEBT_TICKER } from 'app/client_config';
export const emptyContent = {
fetched: new Date(), /// the date at which this data was requested from the server
id: '2.8.0',
@@ -23,9 +23,9 @@ export const emptyContent = {
abs_rshares: 0,
cashout_time: new Date().toISOString(),
total_vote_weight: '0',
- total_payout_value: ['0.000', DEBT_TICKER].join(" "),
- pending_payout_value: ['0.000', LIQUID_TICKER].join(" "),
- total_pending_payout_value: ['0.000', LIQUID_TICKER].join(" "),
+ total_payout_value: ['0.000', DEBT_TICKER].join(' '),
+ pending_payout_value: ['0.000', LIQUID_TICKER].join(' '),
+ total_pending_payout_value: ['0.000', LIQUID_TICKER].join(' '),
active_votes: [],
replies: [],
stats: {
@@ -35,4 +35,4 @@ export const emptyContent = {
allowDelete: true,
hide: false,
},
-}
+};
diff --git a/src/app/redux/FetchDataSaga.js b/src/app/redux/FetchDataSaga.js
index c6a9000b8b359b045adcede8850619997c3ec44a..bfc69cdc182388dd446d7dd907bd6eda893441ba 100644
--- a/src/app/redux/FetchDataSaga.js
+++ b/src/app/redux/FetchDataSaga.js
@@ -1,20 +1,31 @@
-import {takeLatest, takeEvery} from 'redux-saga';
-import {call, put, select, fork} from 'redux-saga/effects';
-import {loadFollows, fetchFollowCount} from 'app/redux/FollowSaga';
-import {getContent} from 'app/redux/SagaShared';
-import GlobalReducer from './GlobalReducer';
+import { takeLatest, takeEvery } from 'redux-saga';
+import { call, put, select, fork } from 'redux-saga/effects';
+import { loadFollows, fetchFollowCount } from 'app/redux/FollowSaga';
+import { getContent } from 'app/redux/SagaShared';
+import * as globalActions from './GlobalReducer';
+import * as appActions from './AppReducer';
import constants from './constants';
-import {fromJS, Map} from 'immutable'
-import {api} from 'steem';
+import { fromJS, Map, Set } from 'immutable';
+import { api } from '@steemit/steem-js';
-export const fetchDataWatches = [watchLocationChange, watchDataRequests, watchFetchJsonRequests, watchFetchState, watchGetContent];
+const REQUEST_DATA = 'fetchDataSaga/REQUEST_DATA';
+const GET_CONTENT = 'fetchDataSaga/GET_CONTENT';
+const FETCH_STATE = 'fetchDataSaga/FETCH_STATE';
+
+export const fetchDataWatches = [
+ watchLocationChange,
+ watchDataRequests,
+ watchFetchJsonRequests,
+ watchFetchState,
+ watchGetContent,
+];
export function* watchDataRequests() {
- yield* takeLatest('REQUEST_DATA', fetchData);
+ yield* takeLatest(REQUEST_DATA, fetchData);
}
export function* watchGetContent() {
- yield* takeEvery('GET_CONTENT', getContentCaller);
+ yield* takeEvery(GET_CONTENT, getContentCaller);
}
export function* getContentCaller(action) {
@@ -23,38 +34,90 @@ export function* getContentCaller(action) {
let is_initial_state = true;
export function* fetchState(location_change_action) {
- const {pathname} = location_change_action.payload;
- const m = pathname.match(/^\/@([a-z0-9\.-]+)/)
- if(m && m.length === 2) {
- const username = m[1]
- yield fork(fetchFollowCount, username)
- yield fork(loadFollows, "getFollowersAsync", username, 'blog')
- yield fork(loadFollows, "getFollowingAsync", username, 'blog')
+ const { pathname } = location_change_action.payload;
+ const m = pathname.match(/^\/@([a-z0-9\.-]+)/);
+ if (m && m.length === 2) {
+ const username = m[1];
+ yield fork(fetchFollowCount, username);
+ yield fork(loadFollows, 'getFollowersAsync', username, 'blog');
+ yield fork(loadFollows, 'getFollowingAsync', username, 'blog');
}
// `ignore_fetch` case should only trigger on initial page load. No need to call
// fetchState immediately after loading fresh state from the server. Details: #593
- const server_location = yield select(state => state.offchain.get('server_location'));
- const ignore_fetch = (pathname === server_location && is_initial_state)
+ const server_location = yield select(state =>
+ state.offchain.get('server_location')
+ );
+ const ignore_fetch = pathname === server_location && is_initial_state;
is_initial_state = false;
- if(ignore_fetch) return;
+ if (ignore_fetch) {
+ // If a user's transfer page is being loaded, fetch related account data.
+ yield call(getTransferUsers, pathname);
+
+ return;
+ }
let url = `${pathname}`;
if (url === '/') url = 'trending';
// Replace /curation-rewards and /author-rewards with /transfers for UserProfile
// to resolve data correctly
- if (url.indexOf("/curation-rewards") !== -1) url = url.replace("/curation-rewards", "/transfers");
- if (url.indexOf("/author-rewards") !== -1) url = url.replace("/author-rewards", "/transfers");
+ if (url.indexOf('/curation-rewards') !== -1)
+ url = url.replace('/curation-rewards', '/transfers');
+ if (url.indexOf('/author-rewards') !== -1)
+ url = url.replace('/author-rewards', '/transfers');
- yield put({type: 'FETCH_DATA_BEGIN'});
+ yield put(appActions.fetchDataBegin());
try {
- const state = yield call([api, api.getStateAsync], url)
- yield put(GlobalReducer.actions.receiveState(state));
+ const state = yield call([api, api.getStateAsync], url);
+ yield put(globalActions.receiveState(state));
+ // If a user's transfer page is being loaded, fetch related account data.
+ yield call(getTransferUsers, pathname);
} catch (error) {
console.error('~~ Saga fetchState error ~~>', url, error);
- yield put({type: 'global/STEEM_API_ERROR', error: error.message});
+ yield put(appActions.steemApiError(error.message));
+ }
+
+ yield put(appActions.fetchDataEnd());
+}
+
+/**
+ * Get transfer-related usernames from history and fetch their account data.
+ *
+ * @param {String} pathname
+ */
+function* getTransferUsers(pathname) {
+ if (pathname.match(/^\/@([a-z0-9\.-]+)\/transfers/)) {
+ const username = pathname.match(/^\/@([a-z0-9\.-]+)/)[1];
+
+ const transferHistory = yield select(state =>
+ state.global.getIn(['accounts', username, 'transfer_history'])
+ );
+
+ // Find users in the transfer history to consider sending users' reputations.
+ const transferUsers = transferHistory.reduce((acc, cur) => {
+ if (cur.getIn([1, 'op', 0]) === 'transfer') {
+ const { from, to } = cur.getIn([1, 'op', 1]).toJS();
+ return acc.add(from);
+ }
+ return acc;
+ // Ensure current user is included in this list, even if they don't have transfer history.
+ // This ensures their reputation is updated - fixes #2306
+ }, new Set([username]));
+
+ yield call(getAccounts, transferUsers);
}
- yield put({type: 'FETCH_DATA_END'});
+}
+
+/**
+ * Request account data for a set of usernames.
+ *
+ * @todo batch the put()s
+ *
+ * @param {Iterable} usernames
+ */
+function* getAccounts(usernames) {
+ const accounts = yield call([api, api.getAccountsAsync], usernames);
+ yield put(globalActions.receiveAccounts({ accounts }));
}
export function* watchLocationChange() {
@@ -62,167 +125,228 @@ export function* watchLocationChange() {
}
export function* watchFetchState() {
- yield* takeLatest('FETCH_STATE', fetchState);
+ yield* takeLatest(FETCH_STATE, fetchState);
}
export function* fetchData(action) {
- const {order, author, permlink, accountname} = action.payload;
- let {category} = action.payload;
- if( !category ) category = "";
+ const { order, author, permlink, accountname } = action.payload;
+ let { category } = action.payload;
+ if (!category) category = '';
category = category.toLowerCase();
- yield put({type: 'global/FETCHING_DATA', payload: {order, category}});
+ yield put(globalActions.fetchingData({ order, category }));
let call_name, args;
if (order === 'trending') {
call_name = 'getDiscussionsByTrendingAsync';
args = [
- { tag: category,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
+ {
+ tag: category,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
} else if (order === 'trending30') {
call_name = 'getDiscussionsByTrending30Async';
args = [
- { tag: category,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
+ {
+ tag: category,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
} else if (order === 'promoted') {
call_name = 'getDiscussionsByPromotedAsync';
args = [
- { tag: category,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
- } else if( order === 'active' ) {
+ {
+ tag: category,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
+ } else if (order === 'active') {
call_name = 'getDiscussionsByActiveAsync';
args = [
- { tag: category,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
- } else if( order === 'cashout' ) {
+ {
+ tag: category,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
+ } else if (order === 'cashout') {
call_name = 'getDiscussionsByCashoutAsync';
args = [
- { tag: category,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
- } else if( order === 'payout' ) {
+ {
+ tag: category,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
+ } else if (order === 'payout') {
call_name = 'getPostDiscussionsByPayout';
args = [
- { tag: category,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
- } else if( order === 'payout_comments' ) {
+ {
+ tag: category,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
+ } else if (order === 'payout_comments') {
call_name = 'getCommentDiscussionsByPayout';
args = [
- { tag: category,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
- } else if( order === 'updated' ) {
+ {
+ tag: category,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
+ } else if (order === 'updated') {
call_name = 'getDiscussionsByActiveAsync';
args = [
- { tag: category,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
- } else if( order === 'created' || order === 'recent' ) {
+ {
+ tag: category,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
+ } else if (order === 'created' || order === 'recent') {
call_name = 'getDiscussionsByCreatedAsync';
args = [
- { tag: category,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
- } else if( order === 'by_replies' ) {
+ {
+ tag: category,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
+ } else if (order === 'by_replies') {
call_name = 'getRepliesByLastUpdateAsync';
args = [author, permlink, constants.FETCH_DATA_BATCH_SIZE];
- } else if( order === 'responses' ) {
+ } else if (order === 'responses') {
call_name = 'getDiscussionsByChildrenAsync';
args = [
- { tag: category,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
- } else if( order === 'votes' ) {
+ {
+ tag: category,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
+ } else if (order === 'votes') {
call_name = 'getDiscussionsByVotesAsync';
args = [
- { tag: category,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
- } else if( order === 'hot' ) {
+ {
+ tag: category,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
+ } else if (order === 'hot') {
call_name = 'getDiscussionsByHotAsync';
args = [
- { tag: category,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
- } else if( order === 'by_feed' ) { // https://github.com/steemit/steem/issues/249
+ {
+ tag: category,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
+ } else if (order === 'by_feed') {
+ // https://github.com/steemit/steem/issues/249
call_name = 'getDiscussionsByFeedAsync';
args = [
- { tag: accountname,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
- } else if( order === 'by_author' ) {
+ {
+ tag: accountname,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
+ } else if (order === 'by_author') {
call_name = 'getDiscussionsByBlogAsync';
args = [
- { tag: accountname,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
- } else if( order === 'by_comments' ) {
+ {
+ tag: accountname,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
+ } else if (order === 'by_comments') {
call_name = 'getDiscussionsByCommentsAsync';
args = [
- { limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
+ {
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
} else {
call_name = 'getDiscussionsByActiveAsync';
- args = [{
- tag: category,
- limit: constants.FETCH_DATA_BATCH_SIZE,
- start_author: author,
- start_permlink: permlink}];
+ args = [
+ {
+ tag: category,
+ limit: constants.FETCH_DATA_BATCH_SIZE,
+ start_author: author,
+ start_permlink: permlink,
+ },
+ ];
}
- yield put({type: 'FETCH_DATA_BEGIN'});
+ yield put(appActions.fetchDataBegin());
try {
const data = yield call([api, api[call_name]], ...args);
- yield put(GlobalReducer.actions.receiveData({data, order, category, author, permlink, accountname}));
+ yield put(
+ globalActions.receiveData({
+ data,
+ order,
+ category,
+ author,
+ permlink,
+ accountname,
+ })
+ );
} catch (error) {
console.error('~~ Saga fetchData error ~~>', call_name, args, error);
- yield put({type: 'global/STEEM_API_ERROR', error: error.message});
+ yield put(appActions.steemApiError(error.message));
}
- yield put({type: 'FETCH_DATA_END'});
+ yield put(appActions.fetchDataEnd());
}
// export function* watchMetaRequests() {
// yield* takeLatest('global/REQUEST_META', fetchMeta);
// }
-export function* fetchMeta({payload: {id, link}}) {
+export function* fetchMeta({ payload: { id, link } }) {
try {
- const metaArray = yield call(() => new Promise((resolve, reject) => {
- function reqListener() {
- const resp = JSON.parse(this.responseText)
- if (resp.error) {
- reject(resp.error)
- return
- }
- resolve(resp)
- }
- const oReq = new XMLHttpRequest()
- oReq.addEventListener('load', reqListener)
- oReq.open('GET', '/http_metadata/' + link)
- oReq.send()
- }))
- const {title, metaTags} = metaArray
- let meta = {title}
+ const metaArray = yield call(
+ () =>
+ new Promise((resolve, reject) => {
+ function reqListener() {
+ const resp = JSON.parse(this.responseText);
+ if (resp.error) {
+ reject(resp.error);
+ return;
+ }
+ resolve(resp);
+ }
+ const oReq = new XMLHttpRequest();
+ oReq.addEventListener('load', reqListener);
+ oReq.open('GET', '/http_metadata/' + link);
+ oReq.send();
+ })
+ );
+ const { title, metaTags } = metaArray;
+ let meta = { title };
for (let i = 0; i < metaTags.length; i++) {
- const [name, content] = metaTags[i]
- meta[name] = content
+ const [name, content] = metaTags[i];
+ meta[name] = content;
}
// http://postimg.org/image/kbefrpbe9/
meta = {
@@ -233,13 +357,13 @@ export function* fetchMeta({payload: {id, link}}) {
description: meta['twitter:description'],
image: meta['twitter:image'],
alt: meta['twitter:alt'],
+ };
+ if (!meta.image) {
+ meta.image = meta['twitter:image:src'];
}
- if(!meta.image) {
- meta.image = meta['twitter:image:src']
- }
- yield put(GlobalReducer.actions.receiveMeta({id, meta}))
- } catch(error) {
- yield put(GlobalReducer.actions.receiveMeta({id, meta: {error}}))
+ yield put(globalActions.receiveMeta({ id, meta }));
+ } catch (error) {
+ yield put(globalActions.receiveMeta({ id, meta: { error } }));
}
}
@@ -252,22 +376,44 @@ export function* watchFetchJsonRequests() {
@arg {string} url
@arg {object} body (for JSON.stringify)
*/
-function* fetchJson({payload: {id, url, body, successCallback, skipLoading = false}}) {
+function* fetchJson({
+ payload: { id, url, body, successCallback, skipLoading = false },
+}) {
try {
const payload = {
method: body ? 'POST' : 'GET',
headers: {
Accept: 'application/json',
- 'Content-Type': 'application/json'
+ 'Content-Type': 'application/json',
},
- body: body ? JSON.stringify(body) : undefined
- }
- let result = yield skipLoading ? fetch(url, payload) : call(fetch, url, payload)
- result = yield result.json()
- if(successCallback) result = successCallback(result)
- yield put(GlobalReducer.actions.fetchJsonResult({id, result}))
- } catch(error) {
- console.error('fetchJson', error)
- yield put(GlobalReducer.actions.fetchJsonResult({id, error}))
+ body: body ? JSON.stringify(body) : undefined,
+ };
+ let result = yield skipLoading
+ ? fetch(url, payload)
+ : call(fetch, url, payload);
+ result = yield result.json();
+ if (successCallback) result = successCallback(result);
+ yield put(globalActions.fetchJsonResult({ id, result }));
+ } catch (error) {
+ console.error('fetchJson', error);
+ yield put(globalActions.fetchJsonResult({ id, error }));
}
}
+
+// Action creators
+export const actions = {
+ requestData: payload => ({
+ type: REQUEST_DATA,
+ payload,
+ }),
+
+ getContent: payload => ({
+ type: GET_CONTENT,
+ payload,
+ }),
+
+ fetchState: payload => ({
+ type: FETCH_STATE,
+ payload,
+ }),
+};
diff --git a/src/app/redux/FetchDataSaga.test.js b/src/app/redux/FetchDataSaga.test.js
deleted file mode 100644
index 5c82c75351cfc88b0b92f2f1601d5bfeff4b3d54..0000000000000000000000000000000000000000
--- a/src/app/redux/FetchDataSaga.test.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/*global describe, it, before, beforeEach, after, afterEach */
-
-import chai, {expect} from 'chai';
-import dirtyChai from 'dirty-chai';
-import sinon from 'sinon';
-import {call, put} from 'redux-saga/effects';
-import {fetchState} from './FetchDataSaga';
-chai.use(dirtyChai);
-
-const action = {
- payload: {
- pathname: '/recent',
- search: '',
- action: 'PUSH'
- }
-};
-
-describe('sagas', () => {
- // not maintained
- // it('should fetch state and submit RECEIVE_STATE action', () => {
- // const url = '/recent';
- // const db_api = Apis.instance().db_api;
- // const expectedCallResult = call([db_api, db_api.exec], 'get_state', [url]);
- // const generator = fetchState(action);
- // const callResult = generator.next().value;
- // expect(
- // callResult.CALL.args
- // ).to.be.eql(expectedCallResult.CALL.args);
- //
- // const expectedPutResult = put({type: 'global/RECEIVE_STATE', payload: undefined});
- // const putResult = generator.next().value;
- // expect(
- // putResult
- // ).to.be.eql(expectedPutResult);
- // });
- //
- // it('should try to fetch state and submit STEEM_API_ERROR if failed', () => {
- // const generator = fetchState(action);
- // expect(generator.next().value).to.be.ok();
- // const result = generator.throw({message: 'test error'}).value;
- // const expectedPutResult = put({type: 'global/STEEM_API_ERROR', error: 'test error'});
- // expect(
- // result
- // ).to.be.eql(expectedPutResult);
- // });
- //
- // it('should try to fetch state and submit STEEM_API_ERROR if failed', () => {
- // const pop_action = {payload: {...action.payload, action: 'POP'}};
- // const generator = fetchState(pop_action);
- // const result = generator.next().value;
- // expect(result).to.be.null();
- // });
-});
diff --git a/src/app/redux/FollowSaga.js b/src/app/redux/FollowSaga.js
index 2219cc28b02f2b59ed124a7ae9e0d0e121e3238b..6c5e2963fa1ad1e2aa12acf4eafe1bd3fc6c274d 100644
--- a/src/app/redux/FollowSaga.js
+++ b/src/app/redux/FollowSaga.js
@@ -1,6 +1,8 @@
-import {fromJS, Map, Set} from 'immutable'
-import {call, put, select} from 'redux-saga/effects';
-import {api} from 'steem';
+import { fromJS, Map, Set } from 'immutable';
+import { call, put, select } from 'redux-saga/effects';
+import { api } from '@steemit/steem-js';
+
+import * as globalActions from 'app/redux/GlobalReducer';
/**
This loadFollows both 'blog' and 'ignore'
@@ -8,92 +10,114 @@ import {api} from 'steem';
//fetch for follow/following count
export function* fetchFollowCount(account) {
- const counts = yield call([api, api.getFollowCountAsync], account)
- yield put({
- type: 'global/UPDATE',
- payload: {
+ const counts = yield call([api, api.getFollowCountAsync], account);
+ yield put(
+ globalActions.update({
key: ['follow_count', account],
- updater: m => m.mergeDeep({
- follower_count: counts.follower_count,
- following_count: counts.following_count})
- }})
+ updater: m =>
+ m.mergeDeep({
+ follower_count: counts.follower_count,
+ following_count: counts.following_count,
+ }),
+ })
+ );
}
// Test limit with 2 (not 1, infinate looping)
export function* loadFollows(method, account, type, force = false) {
- if(yield select(state => state.global.getIn(['follow', method, account, type + '_loading']))) {
+ if (
+ yield select(state =>
+ state.global.getIn(['follow', method, account, type + '_loading'])
+ )
+ ) {
// console.log('Already loading', method, account, type)
- return
+ return;
}
- if(!force) {
- const hasResult = yield select(state => state.global.hasIn(['follow', method, account, type + '_result']))
- if(hasResult) {
+ if (!force) {
+ const hasResult = yield select(state =>
+ state.global.hasIn(['follow', method, account, type + '_result'])
+ );
+ if (hasResult) {
// console.log('Already loaded', method, account, type)
- return
+ return;
}
}
- yield put({
- type: 'global/UPDATE',
- payload: {
+ yield put(
+ globalActions.update({
key: ['follow', method, account],
notSet: Map(),
updater: m => m.set(type + '_loading', true),
- }})
+ })
+ );
- yield loadFollowsLoop(method, account, type)
+ yield loadFollowsLoop(method, account, type);
}
function* loadFollowsLoop(method, account, type, start = '', limit = 100) {
- if(method === "getFollowersAsync") limit = 1000;
+ if (method === 'getFollowersAsync') limit = 1000;
const res = fromJS(yield api[method](account, start, type, limit));
// console.log('res.toJS()', res.toJS())
- let cnt = 0
- let lastAccountName = null
+ let cnt = 0;
+ let lastAccountName = null;
- yield put({type: 'global/UPDATE', payload: {
- key: ['follow_inprogress', method, account],
- notSet: Map(),
- updater: (m) => {
- m = m.asMutable()
- res.forEach((value) => {
- cnt += 1;
+ yield put(
+ globalActions.update({
+ key: ['follow_inprogress', method, account],
+ notSet: Map(),
+ updater: m => {
+ m = m.asMutable();
+ res.forEach(value => {
+ cnt += 1;
- const whatList = value.get('what')
- const accountNameKey = method === "getFollowingAsync" ? "following" : "follower";
- const accountName = lastAccountName = value.get(accountNameKey)
- whatList.forEach((what) => {
- //currently this is always true: what === type
- m.update(what, Set(), s => s.add(accountName))
- })
- })
- return m.asImmutable()
- }
- }})
+ const whatList = value.get('what');
+ const accountNameKey =
+ method === 'getFollowingAsync'
+ ? 'following'
+ : 'follower';
+ const accountName = (lastAccountName = value.get(
+ accountNameKey
+ ));
+ whatList.forEach(what => {
+ //currently this is always true: what === type
+ m.update(what, Set(), s => s.add(accountName));
+ });
+ });
+ return m.asImmutable();
+ },
+ })
+ );
- if(cnt === limit) {
+ if (cnt === limit) {
// This is paging each block of up to limit results
- yield call(loadFollowsLoop, method, account, type, lastAccountName)
+ yield call(loadFollowsLoop, method, account, type, lastAccountName);
} else {
// This condition happens only once at the very end of the list.
// Every account has a different followers and following list for: blog, ignore
- yield put({type: 'global/UPDATE', payload: {
- key: [],
- updater: (m) => {
- m = m.asMutable()
+ yield put(
+ globalActions.update({
+ key: [],
+ updater: m => {
+ m = m.asMutable();
- const result = m.getIn(['follow_inprogress', method, account, type], Set())
- m.deleteIn(['follow_inprogress', method, account, type])
- m.updateIn(['follow', method, account], Map(), mm => mm.merge({
- // Count may be set separately without loading the full xxx_result set
- [type + '_count']: result.size,
- [type + '_result']: result.sort().reverse(),
- [type + '_loading']: false,
- }))
- return m.asImmutable()
- }
- }})
+ const result = m.getIn(
+ ['follow_inprogress', method, account, type],
+ Set()
+ );
+ m.deleteIn(['follow_inprogress', method, account, type]);
+ m.updateIn(['follow', method, account], Map(), mm =>
+ mm.merge({
+ // Count may be set separately without loading the full xxx_result set
+ [type + '_count']: result.size,
+ [type + '_result']: result.sort().reverse(),
+ [type + '_loading']: false,
+ })
+ );
+ return m.asImmutable();
+ },
+ })
+ );
}
}
diff --git a/src/app/redux/GlobalReducer.js b/src/app/redux/GlobalReducer.js
index 9d91a4cf2095bd63cb621f28a86f2d23e67ac3b6..334a20512c10381d74388b81e7f7c2c1aaf72ba7 100644
--- a/src/app/redux/GlobalReducer.js
+++ b/src/app/redux/GlobalReducer.js
@@ -1,214 +1,321 @@
-import {Map, Set, List, fromJS, Iterable} from 'immutable';
-import createModule from 'redux-modules';
-import {emptyContent} from 'app/redux/EmptyState';
+import { Map, Set, List, fromJS, Iterable } from 'immutable';
+import { emptyContent } from 'app/redux/EmptyState';
+import { contentStats } from 'app/utils/StateFunctions';
import constants from './constants';
-import {contentStats} from 'app/utils/StateFunctions'
-
-const emptyContentMap = Map(emptyContent)
-
-export default createModule({
- name: 'global',
- initialState: Map({status: {}}),
- transformations: [
- {
- action: 'SET_COLLAPSED',
- reducer: (state, action) => {
- return state.withMutations(map => {
- map.updateIn(['content', action.payload.post], value => {
- value.merge(Map({collapsed: action.payload.collapsed}));
+
+export const emptyContentMap = Map(emptyContent);
+
+export const defaultState = Map({
+ status: {},
+});
+
+// Action constants
+const SET_COLLAPSED = 'global/SET_COLLAPSED';
+const RECEIVE_STATE = 'global/RECEIVE_STATE';
+const RECEIVE_ACCOUNT = 'global/RECEIVE_ACCOUNT';
+const RECEIVE_ACCOUNTS = 'global/RECEIVE_ACCOUNTS';
+const RECEIVE_COMMENT = 'global/RECEIVE_COMMENT';
+const RECEIVE_CONTENT = 'global/RECEIVE_CONTENT';
+const LINK_REPLY = 'global/LINK_REPLY';
+const UPDATE_ACCOUNT_WITNESS_VOTE = 'global/UPDATE_ACCOUNT_WITNESS_VOTE';
+const UPDATE_ACCOUNT_WITNESS_PROXY = 'global/UPDATE_ACCOUNT_WITNESS_PROXY';
+const DELETE_CONTENT = 'global/DELETE_CONTENT';
+const VOTED = 'global/VOTED';
+const FETCHING_DATA = 'global/FETCHING_DATA';
+const RECEIVE_DATA = 'global/RECEIVE_DATA';
+const RECEIVE_RECENT_POSTS = 'global/RECEIVE_RECENT_POSTS';
+const REQUEST_META = 'global/REQUEST_META';
+const RECEIVE_META = 'global/RECEIVE_META';
+const SET = 'global/SET';
+const REMOVE = 'global/REMOVE';
+const UPDATE = 'global/UPDATE';
+const SET_META_DATA = 'global/SET_META_DATA';
+const CLEAR_META = 'global/CLEAR_META';
+const CLEAR_META_ELEMENT = 'global/CLEAR_META_ELEMENT';
+const FETCH_JSON = 'global/FETCH_JSON';
+const FETCH_JSON_RESULT = 'global/FETCH_JSON_RESULT';
+const SHOW_DIALOG = 'global/SHOW_DIALOG';
+const HIDE_DIALOG = 'global/HIDE_DIALOG';
+// Saga-related:
+export const GET_STATE = 'global/GET_STATE';
+
+/**
+ * Transfrom nested JS object to appropriate immutable collection.
+ *
+ * @param {Object} account
+ */
+
+const transformAccount = account =>
+ fromJS(account, (key, value) => {
+ if (key === 'witness_votes') return value.toSet();
+ const isIndexed = Iterable.isIndexed(value);
+ return isIndexed ? value.toList() : value.toOrderedMap();
+ });
+
+/**
+ * Merging accounts: A get_state will provide a very full account but a get_accounts will provide a smaller version this makes sure we don't overwrite
+ *
+ * @param {Immutable.Map} state
+ * @param {Immutable.Map} account
+ *
+ */
+
+const mergeAccounts = (state, account) => {
+ return state.updateIn(['accounts', account.get('name')], Map(), a =>
+ a.mergeDeep(account)
+ );
+};
+
+export default function reducer(state = defaultState, action = {}) {
+ const payload = action.payload;
+
+ switch (action.type) {
+ case SET_COLLAPSED: {
+ return state.withMutations(map => {
+ map.updateIn(['content', payload.post], value =>
+ value.merge(Map({ collapsed: payload.collapsed }))
+ );
+ });
+ }
+
+ case RECEIVE_STATE: {
+ let new_state = fromJS(payload);
+ if (new_state.has('content')) {
+ const content = new_state.get('content').withMutations(c => {
+ c.forEach((cc, key) => {
+ cc = emptyContentMap.mergeDeep(cc);
+ const stats = fromJS(contentStats(cc));
+ c.setIn([key, 'stats'], stats);
});
});
+ new_state = new_state.set('content', content);
}
- },
- {
- action: 'RECEIVE_STATE',
- reducer: (state, action) => {
- let payload = fromJS(action.payload)
- if(payload.has('content')) {
- const content = payload.get('content').withMutations(c => {
- c.forEach((cc, key) => {
- cc = emptyContentMap.mergeDeep(cc)
- const stats = fromJS(contentStats(cc))
- c.setIn([key, 'stats'], stats)
- })
+ return state.mergeDeep(new_state);
+ }
+
+ case RECEIVE_ACCOUNT: {
+ const account = transformAccount(payload.account);
+ return mergeAccounts(state, account);
+ }
+
+ case RECEIVE_ACCOUNTS: {
+ return payload.accounts.reduce((acc, curr) => {
+ const transformed = transformAccount(curr);
+ return mergeAccounts(acc, transformed);
+ }, state);
+ }
+
+ case RECEIVE_COMMENT: {
+ const {
+ author,
+ permlink,
+ parent_author = '',
+ parent_permlink = '',
+ title = '',
+ body,
+ } = payload.op;
+ const key = author + '/' + permlink;
+ let updatedState = state.updateIn(
+ ['content', key],
+ Map(emptyContent),
+ r =>
+ r.merge({
+ author,
+ permlink,
+ parent_author,
+ parent_permlink,
+ title: title.toString('utf-8'),
+ body: body.toString('utf-8'),
})
- payload = payload.set('content', content)
- }
- // console.log('state.mergeDeep(action.payload).toJS(), action.payload', state.mergeDeep(action.payload).toJS(), action.payload)
- return state.mergeDeep(payload);
- }
- },
- {
- action: 'RECEIVE_ACCOUNT',
- reducer: (state, {payload: {account}}) => {
- account = fromJS(account, (key, value) => {
- if (key === 'witness_votes') return value.toSet()
- const isIndexed = Iterable.isIndexed(value);
- return isIndexed ? value.toList() : value.toOrderedMap();
- })
- // Merging accounts: A get_state will provide a very full account but a get_accounts will provide a smaller version
- return state.updateIn(['accounts', account.get('name')], Map(), a => a.mergeDeep(account))
+ );
+ if (parent_author !== '' && parent_permlink !== '') {
+ const parent_key = parent_author + '/' + parent_permlink;
+ updatedState = updatedState.updateIn(
+ ['content', parent_key, 'replies'],
+ List(),
+ r => r.insert(0, key)
+ );
+ const children = updatedState.getIn(
+ ['content', parent_key, 'replies'],
+ List()
+ ).size;
+ updatedState = updatedState.updateIn(
+ ['content', parent_key, 'children'],
+ 0,
+ () => children
+ );
}
- },
- {
- action: 'RECEIVE_COMMENT',
- reducer: (state, {payload: op}) => {
- const {author, permlink, parent_author = '', parent_permlink = '', title = '', body} = op
- const key = author + '/' + permlink
-
- let updatedState = state.updateIn(['content', key], Map(emptyContent), r => r.merge({
- author, permlink, parent_author, parent_permlink,
- title: title.toString('utf-8'),
- body: body.toString('utf-8'),
- }))
- // console.log('updatedState content', updatedState.getIn(['content', key]).toJS())
-
- if (parent_author !== '' && parent_permlink !== '') {
- const parent_key = parent_author + '/' + parent_permlink
- updatedState = updatedState.updateIn(['content', parent_key, 'replies'], List(), r => r.insert(0, key))
- const children = updatedState.getIn(['content', parent_key, 'replies'], List()).size;
- updatedState = updatedState.updateIn(['content', parent_key, 'children'], 0, r => children)
- // console.log('updatedState parent', updatedState.toJS())
- }
- return updatedState
- }
- },
- {
- action: 'RECEIVE_CONTENT',
- reducer: (state, {payload: {content}}) => {
- // console.log('GlobalReducer -- RECEIVE_CONTENT content', content)
- content = fromJS(content)
- const key = content.get('author') + '/' + content.get('permlink')
- return state.updateIn(['content', key], Map(), c => {
- c = emptyContentMap.mergeDeep(c)
- c = c.delete('active_votes')
- c = c.mergeDeep(content)
- c = c.set('stats', fromJS(contentStats(c)))
- return c
- })
- }
- },
- { // works...
- action: 'LINK_REPLY',
- reducer: (state, {payload: op}) => {
- const {author, permlink, parent_author = '', parent_permlink = ''} = op
- if (parent_author === '' || parent_permlink === '') return state
- const key = author + '/' + permlink
- const parent_key = parent_author + '/' + parent_permlink
- // Add key if not exist
- let updatedState = state.updateIn(['content', parent_key, 'replies'], List(),
- l => (l.findIndex(i => i === key) === -1 ? l.push(key) : l))
- const children = updatedState.getIn(['content', parent_key, 'replies'], List()).size;
- updatedState = updatedState.updateIn(['content', parent_key, 'children'], 0, r => children)
- return updatedState;
+ return updatedState;
+ }
+
+ case RECEIVE_CONTENT: {
+ const content = fromJS(payload.content);
+ const key = content.get('author') + '/' + content.get('permlink');
+ return state.updateIn(['content', key], Map(), c => {
+ c = emptyContentMap.mergeDeep(c);
+ c = c.delete('active_votes');
+ c = c.mergeDeep(content);
+ c = c.set('stats', fromJS(contentStats(c)));
+ return c;
+ });
+ }
+
+ case LINK_REPLY: {
+ const {
+ author,
+ permlink,
+ parent_author = '',
+ parent_permlink = '',
+ } = payload;
+ if (parent_author === '' || parent_permlink === '') return state;
+ const key = author + '/' + permlink;
+ const parent_key = parent_author + '/' + parent_permlink;
+ // Add key if not exist
+ let updatedState = state.updateIn(
+ ['content', parent_key, 'replies'],
+ List(),
+ l => (l.findIndex(i => i === key) === -1 ? l.push(key) : l)
+ );
+ const children = updatedState.getIn(
+ ['content', parent_key, 'replies'],
+ List()
+ ).size;
+ updatedState = updatedState.updateIn(
+ ['content', parent_key, 'children'],
+ 0,
+ () => children
+ );
+ return updatedState;
+ }
+
+ case UPDATE_ACCOUNT_WITNESS_VOTE: {
+ const { account, witness, approve } = payload;
+ return state.updateIn(
+ ['accounts', account, 'witness_votes'],
+ Set(),
+ votes =>
+ approve
+ ? Set(votes).add(witness)
+ : Set(votes).remove(witness)
+ );
+ }
+
+ case UPDATE_ACCOUNT_WITNESS_PROXY: {
+ const { account, proxy } = payload;
+ return state.setIn(['accounts', account, 'proxy'], proxy);
+ }
+
+ case DELETE_CONTENT: {
+ const { author, permlink } = payload;
+ const key = author + '/' + permlink;
+ const content = state.getIn(['content', key]);
+ const parent_author = content.get('parent_author') || '';
+ const parent_permlink = content.get('parent_permlink') || '';
+ let updatedState = state.deleteIn(['content', key]);
+ if (parent_author !== '' && parent_permlink !== '') {
+ const parent_key = parent_author + '/' + parent_permlink;
+ updatedState = updatedState.updateIn(
+ ['content', parent_key, 'replies'],
+ List(),
+ r => r.filter(i => i !== key)
+ );
}
- },
- { // works...
- action: 'UPDATE_ACCOUNT_WITNESS_VOTE',
- reducer: (state, {payload: {account, witness, approve}}) =>
- state.updateIn(['accounts', account, 'witness_votes'], Set(),
- votes => (approve ? Set(votes).add(witness) : Set(votes).remove(witness)))
- },
- { // works...
- action: 'UPDATE_ACCOUNT_WITNESS_PROXY',
- reducer: (state, {payload: {account, proxy}}) =>
- state.setIn(['accounts', account, 'proxy'], proxy)
- },
- {
- action: 'DELETE_CONTENT',
- reducer: (state, {payload: {author, permlink}}) => {
- const key = author + '/' + permlink
- const content = state.getIn(['content', key])
- const parent_author = content.get('parent_author') || ''
- const parent_permlink = content.get('parent_permlink') || ''
- let updatedState = state.deleteIn(['content', key])
- if (parent_author !== '' && parent_permlink !== '') {
- const parent_key = parent_author + '/' + parent_permlink
- updatedState = updatedState.updateIn(['content', parent_key, 'replies'],
- List(), r => r.filter(i => i !== key))
- }
- return updatedState
+ return updatedState;
+ }
+
+ case VOTED: {
+ const { username, author, permlink, weight } = payload;
+ const key = ['content', author + '/' + permlink, 'active_votes'];
+ let active_votes = state.getIn(key, List());
+ const idx = active_votes.findIndex(
+ v => v.get('voter') === username
+ );
+ // steemd flips weight into percent
+ if (idx === -1) {
+ active_votes = active_votes.push(
+ Map({ voter: username, percent: weight })
+ );
+ } else {
+ active_votes = active_votes.set(
+ idx,
+ Map({ voter: username, percent: weight })
+ );
}
- },
- {
- action: 'VOTED',
- reducer: (state, {payload: {username, author, permlink, weight}}) => {
- const key = ['content', author + '/' + permlink, 'active_votes']
- let active_votes = state.getIn(key, List())
- const idx = active_votes.findIndex(v => v.get('voter') === username)
- // steemd flips weight into percent
- if(idx === -1)
- active_votes = active_votes.push(Map({voter: username, percent: weight}));
- else {
- active_votes = active_votes.set(idx, Map({voter: username, percent: weight}));
+ state.setIn(key, active_votes);
+ return state;
+ }
+
+ case FETCHING_DATA: {
+ const { order, category } = payload;
+ const new_state = state.updateIn(
+ ['status', category || '', order],
+ () => {
+ return { fetching: true };
}
- state.setIn(key, active_votes);
- return state;
- }
- },
- {
- action: 'FETCHING_DATA',
- reducer: (state, {payload: {order, category}}) => {
- const new_state = state.updateIn(['status', category || '', order], () => {
- return {fetching: true};
- });
- return new_state;
- }
- },
- {
- action: 'RECEIVE_DATA',
- reducer: (state, {payload: {data, order, category, author, accountname, /*permlink*/}}) => {
- // console.log('-- RECEIVE_DATA reducer -->', order, category, author, permlink, data);
- // console.log('-- RECEIVE_DATA state -->', state.toJS());
- let new_state;
- if (order === 'by_author' || order === 'by_feed' || order === 'by_comments' || order === 'by_replies') {
- // category is either "blog", "feed", "comments", or "recent_replies" (respectively) -- and all posts are keyed under current profile
- const key = ['accounts', accountname, category]
- new_state = state.updateIn(key, List(), list => {
- return list.withMutations(posts => {
- data.forEach(value => {
- const key2 = `${value.author}/${value.permlink}`
- if (!posts.includes(key2)) posts.push(key2);
- });
+ );
+ return new_state;
+ }
+
+ case RECEIVE_DATA: {
+ const { data, order, category, accountname } = payload;
+ let new_state;
+ if (
+ order === 'by_author' ||
+ order === 'by_feed' ||
+ order === 'by_comments' ||
+ order === 'by_replies'
+ ) {
+ // category is either "blog", "feed", "comments", or "recent_replies" (respectively) -- and all posts are keyed under current profile
+ const key = ['accounts', accountname, category];
+ new_state = state.updateIn(key, List(), list => {
+ return list.withMutations(posts => {
+ data.forEach(value => {
+ const key2 = `${value.author}/${value.permlink}`;
+ if (!posts.includes(key2)) posts.push(key2);
});
});
- } else {
- new_state = state.updateIn(['discussion_idx', category || '', order], list => {
+ });
+ } else {
+ new_state = state.updateIn(
+ ['discussion_idx', category || '', order],
+ list => {
return list.withMutations(posts => {
data.forEach(value => {
- const entry = `${value.author}/${value.permlink}`;
+ const entry = `${value.author}/${
+ value.permlink
+ }`;
if (!posts.includes(entry)) posts.push(entry);
});
});
- });
- }
- new_state = new_state.updateIn(['content'], content => {
- return content.withMutations(map => {
- data.forEach(value => {
- // console.log('GlobalReducer -- RECEIVE_DATA', value)
- const key = `${value.author}/${value.permlink}`;
- value = fromJS(value)
- value = value.set('stats', fromJS(contentStats(value)))
- map.set(key, value);
- });
+ }
+ );
+ }
+ new_state = new_state.updateIn(['content'], content => {
+ return content.withMutations(map => {
+ data.forEach(value => {
+ const key = `${value.author}/${value.permlink}`;
+ value = fromJS(value);
+ value = value.set('stats', fromJS(contentStats(value)));
+ map.set(key, value);
});
});
- new_state = new_state.updateIn(['status', category || '', order], () => {
+ });
+ new_state = new_state.updateIn(
+ ['status', category || '', order],
+ () => {
if (data.length < constants.FETCH_DATA_BATCH_SIZE) {
- return {fetching: false, last_fetch: new Date()};
+ return { fetching: false, last_fetch: new Date() };
}
- return {fetching: false};
- });
- // console.log('-- new_state -->', new_state.toJS());
- return new_state;
- }
- },
- {
- action: 'RECEIVE_RECENT_POSTS',
- reducer: (state, {payload: {data}}) => {
- // console.log('-- RECEIVE_RECENT_POSTS state -->', state.toJS());
- // console.log('-- RECEIVE_RECENT_POSTS reducer -->', data);
- let new_state = state.updateIn(['discussion_idx', '', 'created'], list => {
+ return { fetching: false };
+ }
+ );
+ return new_state;
+ }
+ case RECEIVE_RECENT_POSTS: {
+ const { data } = payload;
+ let new_state = state.updateIn(
+ ['discussion_idx', '', 'created'],
+ list => {
if (!list) list = List();
return list.withMutations(posts => {
data.forEach(value => {
@@ -216,87 +323,232 @@ export default createModule({
if (!posts.includes(entry)) posts.unshift(entry);
});
});
- });
- new_state = new_state.updateIn(['content'], content => {
- return content.withMutations(map => {
- data.forEach(value => {
- const key = `${value.author}/${value.permlink}`;
- if (!map.has(key)) {
- value = fromJS(value)
- value = value.set('stats', fromJS(contentStats(value)))
- map.set(key, value);
- }
- });
+ }
+ );
+ new_state = new_state.updateIn(['content'], content => {
+ return content.withMutations(map => {
+ data.forEach(value => {
+ const key = `${value.author}/${value.permlink}`;
+ if (!map.has(key)) {
+ value = fromJS(value);
+ value = value.set(
+ 'stats',
+ fromJS(contentStats(value))
+ );
+
+ map.set(key, value);
+ }
});
});
- // console.log('-- new_state -->', new_state.toJS());
- return new_state;
- }
- },
- {
- action: 'REQUEST_META', // browser console debug
- reducer: (state, {payload: {id, link}}) =>
- state.setIn(['metaLinkData', id], Map({link}))
- },
- {
- action: 'RECEIVE_META', // browser console debug
- reducer: (state, {payload: {id, meta}}) =>
- state.updateIn(['metaLinkData', id], data => data.merge(meta))
- },
- {
- action: 'SET',
- reducer: (state, {payload: {key, value}}) => {
- key = Array.isArray(key) ? key : [key]
- return state.setIn(key, fromJS(value))
- }
- },
- {
- action: 'REMOVE',
- reducer: (state, {payload: {key}}) => {
- key = Array.isArray(key) ? key : [key]
- return state.removeIn(key)
- }
- },
- {
- action: 'UPDATE',
- reducer: (state, {payload: {key, notSet = Map(), updater}}) =>
- // key = Array.isArray(key) ? key : [key] // TODO enable and test
- state.updateIn(key, notSet, updater)
- },
- {
- action: 'SET_META_DATA', // browser console debug
- reducer: (state, {payload: {id, meta}}) =>
- state.setIn(['metaLinkData', id], fromJS(meta))
- },
- {
- action: 'CLEAR_META', // browser console debug
- reducer: (state, {payload: {id}}) =>
- state.deleteIn(['metaLinkData', id])
- },
- {
- action: 'CLEAR_META_ELEMENT', // browser console debug
- reducer: (state, {payload: {formId, element}}) =>
- state.updateIn(['metaLinkData', formId], data => data.remove(element))
- },
- {
- action: 'FETCH_JSON',
- reducer: state => state // saga
- },
- {
- action: 'FETCH_JSON_RESULT',
- reducer: (state, {payload: {id, result, error}}) =>
- state.set(id, fromJS({result, error}))
- },
- {
- action: 'SHOW_DIALOG',
- reducer: (state, {payload: {name, params = {}}}) =>
- state.update('active_dialogs', Map(), d => d.set(name, fromJS({params})))
- },
- {
- action: 'HIDE_DIALOG',
- reducer: (state, {payload: {name}}) =>
- state.update('active_dialogs', d => d.delete(name))
- },
-
- ]
+ });
+ return new_state;
+ }
+
+ case REQUEST_META: {
+ const { id, link } = payload;
+ return state.setIn(['metaLinkData', id], Map({ link }));
+ }
+
+ case RECEIVE_META: {
+ const { id, meta } = payload;
+ return state.updateIn(['metaLinkData', id], data =>
+ data.merge(meta)
+ );
+ }
+
+ case SET: {
+ const { key, value } = payload;
+ const key_array = Array.isArray(key) ? key : [key];
+ return state.setIn(key_array, fromJS(value));
+ }
+
+ case REMOVE: {
+ const key = Array.isArray(payload.key)
+ ? payload.key
+ : [payload.key];
+ return state.removeIn(key);
+ }
+
+ case UPDATE: {
+ const { key, notSet = Map(), updater } = payload;
+ return state.updateIn(key, notSet, updater);
+ }
+
+ case SET_META_DATA: {
+ const { id, meta } = payload;
+ return state.setIn(['metaLinkData', id], fromJS(meta));
+ }
+
+ case CLEAR_META: {
+ return state.deleteIn(['metaLinkData', payload.id]);
+ }
+
+ case CLEAR_META_ELEMENT: {
+ const { formId, element } = payload;
+ return state.updateIn(['metaLinkData', formId], data =>
+ data.remove(element)
+ );
+ }
+
+ case FETCH_JSON: {
+ return state;
+ }
+
+ case FETCH_JSON_RESULT: {
+ const { id, result, error } = payload;
+ return state.set(id, fromJS({ result, error }));
+ }
+
+ case SHOW_DIALOG: {
+ const { name, params = {} } = payload;
+ return state.update('active_dialogs', Map(), d =>
+ d.set(name, fromJS({ params }))
+ );
+ }
+
+ case HIDE_DIALOG: {
+ return state.update('active_dialogs', d => d.delete(payload.name));
+ }
+
+ default:
+ return state;
+ }
+}
+
+// Action creators
+
+export const setCollapsed = payload => ({
+ type: SET_COLLAPSED,
+ payload,
+});
+
+export const receiveState = payload => ({
+ type: RECEIVE_STATE,
+ payload,
+});
+
+export const receiveAccount = payload => ({
+ type: RECEIVE_ACCOUNT,
+ payload,
+});
+
+export const receiveAccounts = payload => ({
+ type: RECEIVE_ACCOUNTS,
+ payload,
+});
+
+export const receiveComment = payload => ({
+ type: RECEIVE_COMMENT,
+ payload,
+});
+
+export const receiveContent = payload => ({
+ type: RECEIVE_CONTENT,
+ payload,
+});
+
+export const linkReply = payload => ({
+ type: LINK_REPLY,
+ payload,
+});
+
+export const updateAccountWitnessVote = payload => ({
+ type: UPDATE_ACCOUNT_WITNESS_VOTE,
+ payload,
+});
+
+export const updateAccountWitnessProxy = payload => ({
+ type: UPDATE_ACCOUNT_WITNESS_PROXY,
+ payload,
+});
+
+export const deleteContent = payload => ({
+ type: DELETE_CONTENT,
+ payload,
+});
+
+export const voted = payload => ({
+ type: VOTED,
+ payload,
+});
+
+export const fetchingData = payload => ({
+ type: FETCHING_DATA,
+ payload,
+});
+
+export const receiveData = payload => ({
+ type: RECEIVE_DATA,
+ payload,
+});
+
+export const receiveRecentPosts = payload => ({
+ type: RECEIVE_RECENT_POSTS,
+ payload,
+});
+
+export const requestMeta = payload => ({
+ type: REQUEST_META,
+ payload,
+});
+
+export const receiveMeta = payload => ({
+ type: RECEIVE_META,
+ payload,
+});
+
+// TODO: Find a better name for this
+export const set = payload => ({
+ type: SET,
+ payload,
+});
+
+export const remove = payload => ({
+ type: REMOVE,
+ payload,
+});
+
+export const update = payload => ({
+ type: UPDATE,
+ payload,
+});
+
+export const setMetaData = payload => ({
+ type: SET_META_DATA,
+ payload,
+});
+
+export const clearMeta = payload => ({
+ type: CLEAR_META,
+ payload,
+});
+
+export const clearMetaElement = payload => ({
+ type: CLEAR_META_ELEMENT,
+ payload,
+});
+
+export const fetchJson = payload => ({
+ type: FETCH_JSON,
+ payload,
+});
+
+export const fetchJsonResult = payload => ({
+ type: FETCH_JSON_RESULT,
+ payload,
+});
+
+export const showDialog = payload => ({
+ type: SHOW_DIALOG,
+ payload,
+});
+
+export const hideDialog = payload => ({
+ type: HIDE_DIALOG,
+ payload,
+});
+
+export const getState = payload => ({
+ type: GET_STATE,
+ payload,
});
diff --git a/src/app/redux/GlobalReducer.test.js b/src/app/redux/GlobalReducer.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..1464fc4a909ff32d1dd0234868ee578146e7921a
--- /dev/null
+++ b/src/app/redux/GlobalReducer.test.js
@@ -0,0 +1,766 @@
+import { Map, OrderedMap, getIn, List, fromJS, Set, merge } from 'immutable';
+import { emptyContent } from 'app/redux/EmptyState';
+import * as globalActions from './GlobalReducer';
+import reducer, { defaultState } from './GlobalReducer';
+
+const expectedStats = Map({
+ isNsfw: false,
+ hide: false,
+ hasPendingPayout: false,
+ gray: false,
+ flagWeight: 0,
+ up_votes: 0,
+ total_votes: 0,
+ authorRepLog10: undefined,
+ allowDelete: true,
+});
+
+describe('Global reducer', () => {
+ it('should provide a nice initial state', () => {
+ const initial = reducer();
+ expect(initial).toEqual(defaultState);
+ });
+ it('should return correct state for a SET_COLLAPSED action', () => {
+ // Arrange
+ const payload = {
+ post: 'the city',
+ collapsed: 'is now collapsed',
+ };
+ const initial = reducer().set(
+ 'content',
+ Map({
+ [payload.post]: Map({}),
+ })
+ );
+ // Act
+ const actual = reducer(initial, globalActions.setCollapsed(payload));
+ // Assert
+ expect(actual.getIn(['content', payload.post, 'collapsed'])).toEqual(
+ payload.collapsed
+ );
+ });
+ it('should return correct state for a RECEIVE_STATE action', () => {
+ // Arrange
+ const payload = {
+ content: Map({ barman: Map({ foo: 'choo', stats: '' }) }),
+ };
+ const initial = reducer();
+ // Act
+ const actual = reducer(initial, globalActions.receiveState(payload));
+ // Assert
+ expect(actual.getIn(['content', 'barman', 'foo'])).toEqual('choo');
+ expect(actual.getIn(['content', 'barman', 'stats'])).toEqual(
+ expectedStats
+ );
+ });
+
+ it('should return correct state for a RECEIVE_ACCOUNT action', () => {
+ // Arrange
+ const payload = {
+ account: {
+ name: 'foo',
+ witness_votes: 99,
+ beList: ['alice', 'bob', 'claire'],
+ beOrderedMap: { foo: 'barman' },
+ },
+ };
+ const initial = reducer();
+ const expected = Map({
+ status: {},
+ accounts: Map({
+ foo: Map({
+ name: 'foo',
+ witness_votes: 99,
+ be_List: List(['alice', 'bob', 'claire']),
+ be_orderedMap: OrderedMap({ foo: 'barman' }),
+ }),
+ }),
+ });
+ // Act
+ const actual = reducer(initial, globalActions.receiveAccount(payload));
+ // Assert
+ expect(
+ actual.getIn(['accounts', payload.account.name, 'name'])
+ ).toEqual(payload.account.name);
+ expect(
+ actual.getIn(['accounts', payload.account.name, 'beList'])
+ ).toEqual(List(payload.account.beList));
+ expect(
+ actual.getIn(['accounts', payload.account.name, 'beOrderedMap'])
+ ).toEqual(OrderedMap(payload.account.beOrderedMap));
+ });
+
+ it('should return correct state for a RECEIVE_ACCOUNTS action', () => {
+ // Arrange
+ const payload = {
+ accounts: [
+ {
+ name: 'foo',
+ witness_votes: 99,
+ beList: ['alice', 'bob', 'claire'],
+ beorderedMap: { foo: 'barman' },
+ },
+ {
+ name: 'bar',
+ witness_votes: 12,
+ beList: ['james', 'billy', 'samantha'],
+ beOrderedMap: { kewl: 'snoop' },
+ },
+ ],
+ };
+
+ const initState = Map({
+ status: {},
+ seagull: Map({ result: 'fulmar', error: 'stuka' }),
+ accounts: Map({
+ sergei: Map({
+ name: 'sergei',
+ witness_votes: 666,
+ beList: List(['foo', 'carl', 'hanna']),
+ beorderedMap: OrderedMap({ foo: 'cramps' }),
+ }),
+ }),
+ });
+
+ const initial = reducer(initState);
+
+ const expected = Map({
+ status: {},
+ accounts: Map({
+ sergei: Map({
+ name: 'sergei',
+ witness_votes: 666,
+ beList: List(['foo', 'carl', 'hanna']),
+ beorderedMap: OrderedMap({
+ foo: 'cramps',
+ }),
+ }),
+ foo: Map({
+ name: 'foo',
+ witness_votes: 99,
+ beList: List(['alice', 'bob', 'claire']),
+ beorderedMap: OrderedMap({ foo: 'barman' }),
+ }),
+ bar: Map({
+ name: 'bar',
+ witness_votes: 12,
+ beList: List(['james', 'billy', 'samantha']),
+ beOrderedMap: OrderedMap({ kewl: 'snoop' }),
+ }),
+ }),
+ });
+ // Act
+ const actual = reducer(initial, globalActions.receiveAccounts(payload));
+ // Assert
+ expect(actual.get('accounts')).toEqual(expected.get('accounts'));
+ });
+
+ it('should return correct state for a RECEIVE_COMMENT action', () => {
+ // Arrange
+ const payload = {
+ op: {
+ author: 'critic',
+ permlink: 'critical-comment',
+ parent_author: 'Yerofeyev',
+ parent_permlink: 'moscow-stations',
+ title: 'moscow to the end of the line',
+ body: 'corpus of the text',
+ },
+ };
+ const {
+ author,
+ permlink,
+ parent_author,
+ parent_permlink,
+ title,
+ body,
+ } = payload.op;
+ //Act
+ const actual = reducer(
+ reducer(),
+ globalActions.receiveComment(payload)
+ );
+ // Assert
+ expect(
+ actual.getIn(['content', `${author}/${permlink}`, 'author'])
+ ).toEqual(author);
+ expect(
+ actual.getIn(['content', `${author}/${permlink}`, 'title'])
+ ).toEqual(title);
+ expect(
+ actual.getIn(['content', `${parent_author}/${parent_permlink}`])
+ ).toEqual(
+ Map({ replies: List(['critic/critical-comment']), children: 1 })
+ );
+ // Arrange
+ payload.op.parent_author = '';
+ // Act
+ const actual2 = reducer(
+ reducer(),
+ globalActions.receiveComment(payload)
+ );
+ // Assert
+ expect(
+ actual2.getIn(['content', `${parent_author}/${parent_permlink}`])
+ ).toEqual(undefined);
+ });
+ it('should return correct state for a RECEIVE_CONTENT action', () => {
+ // Arrange
+ const payload = {
+ content: {
+ author: 'sebald',
+ permlink: 'rings-of-saturn',
+ active_votes: { one: { percent: 30 }, two: { percent: 70 } },
+ },
+ };
+ const { author, permlink, active_votes } = payload.content;
+ // Act
+ const actual = reducer(
+ reducer(),
+ globalActions.receiveContent(payload)
+ );
+ // Assert
+ expect(
+ actual.getIn(['content', `${author}/${permlink}`, 'author'])
+ ).toEqual(payload.content.author);
+ expect(
+ actual.getIn(['content', `${author}/${permlink}`, 'permlink'])
+ ).toEqual(payload.content.permlink);
+ expect(
+ actual.getIn(['content', `${author}/${permlink}`, 'active_votes'])
+ ).toEqual(fromJS(active_votes));
+ });
+
+ it('should return correct state for a LINK_REPLY action', () => {
+ // Arrange
+ let payload = {
+ author: 'critic',
+ permlink: 'critical-comment',
+ parent_author: 'Yerofeyev',
+ parent_permlink: 'moscow-stations',
+ title: 'moscow to the end of the line',
+ body: 'corpus of the text',
+ };
+ const initial = reducer();
+ const expected = Map({
+ [payload.parent_author + '/' + payload.parent_permlink]: Map({
+ replies: List([`${payload.author}/${payload.permlink}`]),
+ children: 1,
+ }),
+ });
+ // Act
+ let actual = reducer(initial, globalActions.linkReply(payload));
+ // Assert
+ expect(actual.get('content')).toEqual(expected);
+ // Arrange
+ // Remove parent
+ payload.parent_author = '';
+ // Act
+ actual = reducer(initial, globalActions.linkReply(payload));
+ // Assert
+ expect(actual).toEqual(initial);
+ });
+ it('should return correct state for a UPDATE_ACCOUNT_WITNESS_VOTE action', () => {
+ // Arrange
+ let payload = {
+ account: 'Smee',
+ witness: 'Greech',
+ approve: true,
+ };
+ const initial = reducer();
+ // Act
+ let actual = reducer(
+ initial,
+ globalActions.updateAccountWitnessVote(payload)
+ );
+ // Assert
+ expect(
+ actual.getIn(['accounts', payload.account, 'witness_votes'])
+ ).toEqual(Set([payload.witness]));
+ // Arrange
+ payload.approve = false;
+ // Act
+ actual = reducer(
+ initial,
+ globalActions.updateAccountWitnessVote(payload)
+ );
+ // Assert
+ expect(actual).toEqual(initial);
+ });
+ it('should return correct state for a UPDATE_ACCOUNT_WITNESS_PROXY action', () => {
+ // Arrange
+ let payload = {
+ account: 'Alice',
+ proxy: 'Jane',
+ };
+ const initial = reducer();
+ const expected = Map({ proxy: payload.proxy });
+ // Act
+ const actual = reducer(
+ initial,
+ globalActions.updateAccountWitnessProxy(payload)
+ );
+ // Assert
+ expect(actual.getIn(['accounts', payload.account])).toEqual(expected);
+ });
+ it('should return correct state for a DELETE_CONTENT action', () => {
+ // Arrange
+ let payload = {
+ author: 'sebald',
+ permlink: 'rings-of-saturn',
+ };
+ let initial = reducer();
+ // Act
+ // add content
+ const initWithContent = initial.setIn(
+ ['content', `${payload.author}/${payload.permlink}`],
+ Map({
+ author: 'sebald',
+ permlink: 'rings-of-saturn',
+ parent_author: '',
+ active_votes: { one: { percent: 30 }, two: { percent: 70 } },
+ replies: List(['cool', 'mule']),
+ })
+ );
+ let expected = Map({});
+ // Act
+ let actual = reducer(
+ initWithContent,
+ globalActions.deleteContent(payload)
+ );
+ // Assert
+ expect(actual.get('content')).toEqual(expected);
+ // Arrange
+ const initWithContentAndParent = initial.setIn(
+ ['content', `${payload.author}/${payload.permlink}`],
+ Map({
+ author: 'sebald',
+ permlink: 'rings-of-saturn',
+ parent_author: 'alice',
+ parent_permlink: 'bob',
+ active_votes: { one: { percent: 30 }, two: { percent: 70 } },
+ })
+ );
+ const initWithParentKeyContent = initWithContentAndParent.setIn(
+ ['content', 'alice/bob'],
+ Map({
+ replies: [
+ `${payload.author}/${payload.permlink}`,
+ 'dorothy-hughes/in-a-lonely-place',
+ 'artichoke/hearts',
+ ],
+ })
+ );
+ expected = Map({
+ replies: ['dorothy-hughes/in-a-lonely-place', 'artichoke/hearts'],
+ });
+ // Act
+ actual = reducer(
+ initWithParentKeyContent,
+ globalActions.deleteContent(payload)
+ );
+ // Assert
+ expect(actual.getIn(['content', 'alice/bob', 'replies'])).toHaveLength(
+ 2
+ );
+ expect(actual.getIn(['content', 'alice/bob', 'replies'])).toEqual([
+ 'dorothy-hughes/in-a-lonely-place',
+ 'artichoke/hearts',
+ ]);
+ });
+ it('should return correct state for a FETCHING_DATA action', () => {
+ // Arrange
+ const payload = {
+ order: 'cheeseburger',
+ category: 'life',
+ };
+ const initWithCategory = reducer().set(
+ 'status',
+ Map({
+ [payload.category]: Map({
+ [payload.order]: { fetching: false },
+ }),
+ })
+ );
+ // Act
+ const actual = reducer(
+ initWithCategory,
+ globalActions.fetchingData(payload)
+ );
+ // Assert
+ expect(
+ actual.getIn(['status', payload.category, payload.order])
+ ).toEqual({ fetching: true });
+ });
+ it('should return correct state for a RECEIVE_DATA action', () => {
+ //Arrange
+ let payload = {
+ data: [
+ {
+ author: 'smudge',
+ permlink: 'klop',
+ active_votes: {
+ one: { percent: 30 },
+ two: { percent: 70 },
+ },
+ },
+ ],
+ order: 'by_author',
+ category: 'blog',
+ accountname: 'alice',
+ };
+ const initWithData = reducer().merge({
+ accounts: Map({
+ [payload.accountname]: Map({
+ [payload.category]: List([
+ { data: { author: 'farm', permlink: 'barn' } },
+ ]),
+ }),
+ }),
+ content: Map({}),
+ status: Map({
+ [payload.category]: Map({
+ [payload.order]: {},
+ }),
+ }),
+ discussion_idx: Map({
+ [payload.category]: Map({
+ UnusualOrder: List([
+ { data: { author: 'ship', permlink: 'bridge' } },
+ ]),
+ }),
+ '': Map({
+ FebrileFriday: List([]),
+ }),
+ }),
+ });
+
+ //Act
+ const actual1 = reducer(
+ initWithData,
+ globalActions.receiveData(payload)
+ );
+
+ //Assert
+ expect(actual1.getIn(['content', 'author'])).toEqual(payload.author);
+ expect(actual1.getIn(['content', 'permlink'])).toEqual(
+ payload.permlink
+ );
+ expect(actual1.getIn(['content', 'active_vites'])).toEqual(
+ payload.active_votes
+ );
+ expect(
+ actual1.getIn([
+ 'content',
+ `${payload.data[0].author}/${payload.data[0].permlink}`,
+ 'stats',
+ 'allowDelete',
+ ])
+ ).toEqual(false);
+
+ // Push new key to posts list, If order meets the condition.
+ expect(
+ actual1.getIn(['accounts', payload.accountname, payload.category])
+ ).toEqual(
+ List([
+ { data: { author: 'farm', permlink: 'barn' } },
+ 'smudge/klop',
+ ])
+ );
+
+ // Arrange
+ payload.order = 'UnusualOrder';
+ //Act.
+ // Push new key to discussion_idx list, If order does not meet the condition.
+ const actual2 = reducer(
+ initWithData,
+ globalActions.receiveData(payload)
+ );
+
+ // Assert
+ expect(
+ actual2.getIn(['discussion_idx', payload.category, payload.order])
+ ).toEqual(
+ List([
+ { data: { author: 'ship', permlink: 'bridge' } },
+ 'smudge/klop',
+ ])
+ );
+ // Arrange
+ // handle falsey payload category by setting empty string at keypath location typically occupied by category.
+ payload.order = 'FebrileFriday';
+ payload.category = '';
+ // Act
+ const actual3 = reducer(
+ initWithData,
+ globalActions.receiveData(payload)
+ );
+ // Assert.
+ expect(actual3.getIn(['discussion_idx', '', payload.order])).toEqual(
+ List(['smudge/klop'])
+ );
+ });
+ it('should return correct state for a RECEIVE_RECENT_POSTS action', () => {
+ // Arrange
+ const payload = {
+ data: [
+ {
+ author: 'pidge',
+ permlink: 'wolf',
+ active_votes: {
+ one: { percent: 60 },
+ two: { percent: 30 },
+ },
+ stats: {},
+ },
+ {
+ author: 'ding',
+ permlink: 'bat',
+ active_votes: {
+ one: { percent: 60 },
+ two: { percent: 30 },
+ },
+ stats: {},
+ },
+ ],
+ };
+ const initial = reducer();
+ const initWithData = reducer()
+ .setIn(['discussion_idx', '', 'created'], List([]))
+ .set('content', Map({}));
+ // Act
+ const actual = reducer(
+ initWithData,
+ globalActions.receiveRecentPosts(payload)
+ );
+ // Assert
+ // It adds recent posts to discussion_idx
+ expect(actual.getIn(['discussion_idx', '', 'created'])).toEqual(
+ List([
+ `${payload.data[1].author}/${payload.data[1].permlink}`,
+ `${payload.data[0].author}/${payload.data[0].permlink}`,
+ ])
+ );
+ // It adds recent posts to content
+ expect(
+ actual.getIn([
+ 'content',
+ `${payload.data[0].author}/${payload.data[0].permlink}`,
+ 'author',
+ ])
+ ).toEqual(payload.data[0].author);
+ expect(
+ actual.getIn([
+ 'content',
+ `${payload.data[0].author}/${payload.data[0].permlink}`,
+ 'stats',
+ ])
+ ).toEqual(
+ Map({
+ isNsfw: false,
+ hide: false,
+ hasPendingPayout: false,
+ gray: false,
+ flagWeight: 0,
+ up_votes: 2,
+ total_votes: 2,
+ authorRepLog10: undefined,
+ allowDelete: false,
+ })
+ );
+
+ // Act
+ // If the recent post is already in the list do not add it again.
+ const actual2 = reducer(
+ actual,
+ globalActions.receiveRecentPosts(payload)
+ );
+ // Assert
+ expect(actual.getIn(['discussion_idx', '', 'created'])).toEqual(
+ List(['ding/bat', 'pidge/wolf'])
+ );
+ });
+ it('should return correct state for a REQUEST_META action', () => {
+ // Arrange
+ const payload = {
+ id: 'Hello',
+ link: 'World',
+ };
+ // Act
+ const actual = reducer(reducer(), globalActions.requestMeta(payload));
+ // Assert
+ expect(actual.getIn(['metaLinkData', `${payload.id}`])).toEqual(
+ Map({ link: 'World' })
+ );
+ });
+ it('should return correct state for a RECEIVE_META action', () => {
+ // Arrange
+ const payload = {
+ id: 'Hello',
+ meta: { link: 'spalunking' },
+ };
+ const initial = reducer();
+ const initialWithData = initial.setIn(
+ ['metaLinkData', payload.id],
+ Map({})
+ );
+ // Act
+ const actual = reducer(
+ initialWithData,
+ globalActions.receiveMeta(payload)
+ );
+ // Assert
+ expect(actual.getIn(['metaLinkData', payload.id])).toEqual(
+ Map({ link: 'spalunking' })
+ );
+ });
+
+ it('should return correct state for a SET action', () => {
+ // Arrange
+ let payload = {
+ key: ['europe', 'east', 'soup'],
+ value: 'borscht',
+ };
+ const initial = reducer();
+ // Act
+ const actual = reducer(initial, globalActions.set(payload));
+ // Assert
+ expect(actual.getIn(payload.key)).toEqual(payload.value);
+ // Arrange
+ // Make the key a non-array.
+ payload = {
+ key: 'hello',
+ value: 'world',
+ };
+ // Assert
+ const actual2 = reducer(initial, globalActions.set(payload));
+ expect(actual2.getIn([payload.key])).toEqual(payload.value);
+ });
+ it('should return correct state for a REMOVE action', () => {
+ // Arrange
+ const payload = {
+ key: ['europe', 'east', 'soup'],
+ };
+ const initial = reducer();
+ initial.setIn(payload.key, 'potato');
+ // Act
+ const actual = reducer(initial, globalActions.remove(payload));
+ // Assert
+ expect(actual.getIn(payload.key)).toEqual(undefined);
+ });
+
+ it('should return correct state for a UPDATE action', () => {
+ // Arrange
+ const payload = {
+ key: ['oak'],
+ updater: () => 'acorn',
+ };
+ const initial = reducer();
+ initial.setIn(payload.key, 'acorn');
+ // Act
+ const actual = reducer(initial, globalActions.update(payload));
+ // Assert
+ expect(actual.getIn(payload.key)).toEqual(payload.updater());
+ });
+
+ it('should return correct state for a SET_META_DATA action', () => {
+ // Arrange
+ const payload = {
+ id: 'pear',
+ meta: { flip: 'flop' },
+ };
+ const initial = reducer();
+ // Act
+ const actual = reducer(initial, globalActions.setMetaData(payload));
+ // Assert
+ expect(actual.getIn(['metaLinkData', payload.id])).toEqual(
+ fromJS(payload.meta)
+ );
+ });
+
+ it('should return correct state for a CLEAR_META action', () => {
+ // Arrange
+ const initial = reducer().set(
+ 'metaLinkData',
+ Map({ deleteMe: { erase: 'me' } })
+ );
+ // Act
+ const actual = reducer(
+ initial,
+ globalActions.clearMeta({ id: 'deleteMe' })
+ );
+ // Assert
+ expect(actual.get('metaLinkData')).toEqual(Map({}));
+ });
+
+ it('should return correct state for a CLEAR_META_ELEMENT action', () => {
+ // Arrange
+ const payload = {
+ id: 'pear',
+ meta: { flip: 'flop' },
+ };
+
+ const clearPayload = {
+ formId: 'pear',
+ element: 'flip',
+ };
+ const initial = reducer(initial, globalActions.setMetaData(payload));
+ // Act
+ const actual = reducer(
+ initial,
+ globalActions.clearMetaElement(clearPayload)
+ );
+ // Assert
+ expect(actual.get('metaLinkData')).toEqual(Map({ pear: Map({}) }));
+ });
+
+ it('should return correct state for a FETCH_JSON action', () => {
+ const initial = reducer();
+ const actual = reducer(initial, globalActions.fetchJson(defaultState));
+ expect(initial).toEqual(actual);
+ });
+
+ it('should return correct state for a FETCH_JSON_RESULT action', () => {
+ const payload = {
+ id: 'seagull',
+ result: 'fulmar',
+ error: 'stuka',
+ };
+ const initial = reducer();
+ const actual = reducer(initial, globalActions.fetchJsonResult(payload));
+ expect(actual).toEqual(
+ Map({
+ status: {},
+ seagull: Map({ result: 'fulmar', error: 'stuka' }),
+ })
+ );
+ });
+
+ it('should return correct state for a SHOW_DIALOG action', () => {
+ const payload = {
+ name: 'Iris',
+ params: { cheap: 'seats' },
+ };
+ const initial = reducer().set(
+ 'active_dialogs',
+ Map({ chimney: 'smoke' })
+ );
+ const actual = reducer(initial, globalActions.showDialog(payload));
+ expect(actual.get('active_dialogs')).toEqual(
+ Map({
+ chimney: 'smoke',
+ Iris: Map({ params: Map({ cheap: 'seats' }) }),
+ })
+ );
+ });
+
+ it('should return correct state for a HIDE_DIALOG action', () => {
+ const payload = { name: 'dolphin' };
+ const initial = reducer().set(
+ 'active_dialogs',
+ Map({ [payload.name]: 'flipper' })
+ );
+ const actual = reducer(initial, globalActions.hideDialog(payload));
+ expect(actual.get('active_dialogs')).toEqual(Map({}));
+ });
+});
diff --git a/src/app/redux/MarketReducer.js b/src/app/redux/MarketReducer.js
index 719acd810944baa7ec70f1a91929ba684cab2e7e..d769ad269caac772a55dd5c69c692265794a69aa 100644
--- a/src/app/redux/MarketReducer.js
+++ b/src/app/redux/MarketReducer.js
@@ -1,40 +1,145 @@
-import {Map} from 'immutable';
-import createModule from 'redux-modules';
-
-
-export default createModule({
- name: 'market',
- initialState: Map({status: {}}),
- transformations: [
- {
- action: 'RECEIVE_ORDERBOOK',
- reducer: (state, action) => {
- return state.set('orderbook', action.payload);
- }
- },
- {
- action: 'RECEIVE_TICKER',
- reducer: (state, action) => {
- return state.set('ticker', action.payload);
- }
- },
- {
- action: 'RECEIVE_OPEN_ORDERS',
- reducer: (state, action) => {
- return state.set('open_orders', action.payload);
- }
- },
- {
- action: 'RECEIVE_TRADE_HISTORY',
- reducer: (state, action) => {
- return state.set('history', action.payload);
- }
- },
- {
- action: 'APPEND_TRADE_HISTORY',
- reducer: (state, action) => {
- return state.set('history', [...action.payload, ...state.get('history')]);
- }
- }
- ]
+import { Map } from 'immutable';
+
+import { createOrderSorter } from 'app/utils/MarketUtils';
+import { LIQUID_TICKER } from 'app/client_config';
+
+// Action constants
+const RECEIVE_ORDERBOOK = 'market/RECEIVE_ORDERBOOK';
+const RECEIVE_TICKER = 'market/RECEIVE_TICKER';
+const RECEIVE_OPEN_ORDERS = 'market/RECEIVE_OPEN_ORDERS';
+const RECEIVE_TRADE_HISTORY = 'market/RECEIVE_TRADE_HISTORY';
+const APPEND_TRADE_HISTORY = 'market/APPEND_TRADE_HISTORY';
+const TOGGLE_OPEN_ORDERS_SORT = 'market/TOGGLE_OPEN_ORDERS_SORT';
+// Saga-related
+export const UPDATE_MARKET = 'market/UPDATE_MARKET';
+
+const defaultState = Map({
+ status: {},
+ open_orders_sort: Map({
+ column: 'created',
+ dataType: 'string',
+ dir: 1,
+ }),
+});
+
+export default function reducer(state = defaultState, action = {}) {
+ const payload =
+ typeof action.payload !== 'undefined' ? action.payload : null;
+
+ switch (action.type) {
+ case RECEIVE_ORDERBOOK:
+ return state.set('orderbook', payload);
+
+ case RECEIVE_TICKER:
+ return state.set('ticker', payload);
+
+ case RECEIVE_OPEN_ORDERS:
+ // Store normalized data right in redux, and apply current sort.
+ const { dir, column, dataType } = state
+ .get('open_orders_sort')
+ .toJS();
+ const getValue = dataType === 'string' ? v => v : parseFloat;
+
+ const open_orders = action.payload
+ .map(o => {
+ const type =
+ o.sell_price.base.indexOf(LIQUID_TICKER) > 0
+ ? 'ask'
+ : 'bid';
+ return {
+ ...o,
+ type: type,
+ price: parseFloat(
+ type == 'ask' ? o.real_price : o.real_price
+ ),
+ steem:
+ type == 'ask'
+ ? o.sell_price.base
+ : o.sell_price.quote,
+ sbd:
+ type == 'bid'
+ ? o.sell_price.base
+ : o.sell_price.quote,
+ };
+ })
+ .sort(createOrderSorter(getValue, column, dir));
+
+ return state.set('open_orders', open_orders);
+
+ case RECEIVE_TRADE_HISTORY:
+ return state.set('history', payload);
+
+ case APPEND_TRADE_HISTORY:
+ return state.set('history', [...payload, ...state.get('history')]);
+
+ case TOGGLE_OPEN_ORDERS_SORT:
+ const toggledColumn = action.payload.column || 'created';
+ const toggledDataType = action.payload.dataType || 'float';
+
+ const toggledDir = -state.get('open_orders_sort').get('dir');
+
+ const toggledGetValue =
+ toggledDataType === 'string' ? v => v : parseFloat;
+
+ const sortedState = state.set(
+ 'open_orders',
+ state
+ .get('open_orders')
+ .sort(
+ createOrderSorter(
+ toggledGetValue,
+ toggledColumn,
+ toggledDir
+ )
+ )
+ );
+
+ return sortedState.set(
+ 'open_orders_sort',
+ Map({
+ column: toggledColumn,
+ dataType: toggledDir,
+ dir: toggledDir,
+ })
+ );
+
+ default:
+ return state;
+ }
+}
+
+// Action creators
+export const receiveOrderbook = payload => ({
+ type: RECEIVE_ORDERBOOK,
+ payload,
+});
+
+export const receiveTicker = payload => ({
+ type: RECEIVE_TICKER,
+ payload,
+});
+
+export const receiveOpenOrders = payload => ({
+ type: RECEIVE_OPEN_ORDERS,
+ payload,
+});
+
+export const receiveTradeHistory = payload => ({
+ type: RECEIVE_TRADE_HISTORY,
+ payload,
+});
+
+export const appendTradeHistory = payload => ({
+ type: APPEND_TRADE_HISTORY,
+ payload,
+});
+
+export const updateMarket = payload => ({
+ type: UPDATE_MARKET,
+ payload,
+});
+
+export const toggleOpenOrdersSort = payload => ({
+ type: TOGGLE_OPEN_ORDERS_SORT,
+ payload,
});
diff --git a/src/app/redux/MarketReducer.test.js b/src/app/redux/MarketReducer.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..16df8757baf60083eb738b44df849ca6718d5100
--- /dev/null
+++ b/src/app/redux/MarketReducer.test.js
@@ -0,0 +1,137 @@
+import { Map } from 'immutable';
+
+import reducer, {
+ receiveOpenOrders,
+ toggleOpenOrdersSort,
+} from './MarketReducer';
+
+const someOpenOrders = [
+ {
+ id: 1127826,
+ created: '2017-12-04T23:54:09',
+ expiration: '1969-12-31T23:59:59',
+ seller: 'bnchdrff',
+ orderid: 1512431634,
+ for_sale: 3000,
+ sell_price: {
+ base: '3.000 STEEM',
+ quote: '1.998 SBD',
+ },
+ real_price: '0.66600000000000004',
+ rewarded: false,
+ },
+ {
+ id: 1127827,
+ created: '2017-12-04T23:54:54',
+ expiration: '1969-12-31T23:59:59',
+ seller: 'bnchdrff',
+ orderid: 1512431689,
+ for_sale: 7000,
+ sell_price: {
+ base: '7.000 STEEM',
+ quote: '4.578 SBD',
+ },
+ real_price: '0.65400000000000003',
+ rewarded: false,
+ },
+ {
+ id: 1127832,
+ created: '2017-12-04T23:57:18',
+ expiration: '1969-12-31T23:59:59',
+ seller: 'bnchdrff',
+ orderid: 1512431835,
+ for_sale: 3000,
+ sell_price: {
+ base: '3.000 STEEM',
+ quote: '1.953 SBD',
+ },
+ real_price: '0.65100000000000002',
+ rewarded: false,
+ },
+ {
+ id: 1131478,
+ created: '2017-12-05T16:42:00',
+ expiration: '1969-12-31T23:59:59',
+ seller: 'bnchdrff',
+ orderid: 1512492109,
+ for_sale: 507,
+ sell_price: {
+ base: '0.507 SBD',
+ quote: '1.000 STEEM',
+ },
+ real_price: '0.50700000000000001',
+ rewarded: false,
+ },
+ {
+ id: 1131479,
+ created: '2017-12-05T16:42:27',
+ expiration: '1969-12-31T23:59:59',
+ seller: 'bnchdrff',
+ orderid: 1512492144,
+ for_sale: 507,
+ sell_price: {
+ base: '0.507 SBD',
+ quote: '1.000 STEEM',
+ },
+ real_price: '0.50700000000000001',
+ rewarded: false,
+ },
+];
+
+const toggleSortByPrice = {
+ column: 'real_price',
+ dataType: 'float',
+};
+
+describe('market reducer', () => {
+ it('should provide a nice initial state', () => {
+ const initial = reducer();
+
+ expect(initial.get('open_orders_sort')).toEqual(
+ Map({
+ column: 'created',
+ dataType: 'string',
+ dir: 1,
+ })
+ );
+
+ expect(initial.get('status')).toEqual({});
+ });
+
+ it('should receive open orders', () => {
+ const initial = reducer();
+
+ const withOrders = reducer(initial, receiveOpenOrders(someOpenOrders));
+
+ const orders = withOrders.get('open_orders');
+
+ expect(orders[0].price).toBe(0.666);
+ expect(orders[0].sbd).toBe('1.998 SBD');
+ expect(orders[1].type).toBe('ask');
+ expect(orders[2].price).toBe(0.651);
+ expect(orders[2].sbd).toBe('1.953 SBD');
+ expect(orders[3].type).toBe('bid');
+ expect(orders[3].type).toBe('bid');
+ });
+
+ it('should sort open orders', () => {
+ const withOrders = reducer(
+ undefined,
+ receiveOpenOrders(someOpenOrders)
+ );
+
+ const byPriceDesc = reducer(
+ withOrders,
+ toggleOpenOrdersSort(toggleSortByPrice)
+ );
+ const byPriceAsc = reducer(
+ byPriceDesc,
+ toggleOpenOrdersSort(toggleSortByPrice)
+ );
+
+ const orders = byPriceAsc.get('open_orders');
+
+ expect(orders[0].price).toBe(0.507);
+ expect(orders[4].price).toBe(0.666);
+ });
+});
diff --git a/src/app/redux/MarketSaga.js b/src/app/redux/MarketSaga.js
index b51b5ce10ff3a3f0ee9e9dbab235ddba2c97e783..99adaedf5f2bf9b42d4899d701dde5c261f9d09b 100644
--- a/src/app/redux/MarketSaga.js
+++ b/src/app/redux/MarketSaga.js
@@ -1,55 +1,68 @@
-import {takeLatest} from 'redux-saga';
-import {call, put} from 'redux-saga/effects';
-import MarketReducer from './MarketReducer';
-import {getAccount} from './SagaShared';
-import {api} from 'steem';
-
-export const marketWatches = [watchLocationChange, watchUserLogin, watchMarketUpdate];
-
-const wait = ms => (
+import { takeLatest } from 'redux-saga';
+import { call, put } from 'redux-saga/effects';
+import { api } from '@steemit/steem-js';
+
+import * as marketActions from './MarketReducer';
+import * as appActions from './AppReducer';
+import * as userActions from './UserReducer';
+import { getAccount } from './SagaShared';
+
+export const marketWatches = [
+ watchLocationChange,
+ watchUserLogin,
+ watchMarketUpdate,
+];
+
+const wait = ms =>
new Promise(resolve => {
- setTimeout(() => resolve(), ms)
- }))
+ setTimeout(() => resolve(), ms);
+ });
-let polling = false
-let active_user = null
-let last_trade = null
+let polling = false;
+let active_user = null;
+let last_trade = null;
export function* fetchMarket(location_change_action) {
- const {pathname} = location_change_action.payload;
- if (pathname && pathname != "/market") {
- polling = false
- return
+ const { pathname } = location_change_action.payload;
+ if (pathname && pathname != '/market') {
+ polling = false;
+ return;
}
- if(polling == true) return
- polling = true
-
- while(polling) {
+ if (polling == true) return;
+ polling = true;
+ while (polling) {
try {
const state = yield call([api, api.getOrderBookAsync], 500);
- yield put(MarketReducer.actions.receiveOrderbook(state));
+ yield put(marketActions.receiveOrderbook(state));
let trades;
- if(last_trade == null ) {
+ if (last_trade == null) {
trades = yield call([api, api.getRecentTradesAsync], 25);
- yield put(MarketReducer.actions.receiveTradeHistory(trades));
+ yield put(marketActions.receiveTradeHistory(trades));
} else {
- let start = last_trade.toISOString().slice(0, -5)
- trades = yield call([api, api.getTradeHistoryAsync], start, "1969-12-31T23:59:59", 1000);
- trades = trades.reverse()
- yield put(MarketReducer.actions.appendTradeHistory(trades));
+ let start = last_trade.toISOString().slice(0, -5);
+ trades = yield call(
+ [api, api.getTradeHistoryAsync],
+ start,
+ '1969-12-31T23:59:59',
+ 1000
+ );
+ trades = trades.reverse();
+ yield put(marketActions.appendTradeHistory(trades));
}
- if(trades.length > 0) {
- last_trade = new Date((new Date(Date.parse(trades[0]['date']))).getTime() + 1000)
+ if (trades.length > 0) {
+ last_trade = new Date(
+ new Date(Date.parse(trades[0]['date'])).getTime() + 1000
+ );
}
const state3 = yield call([api, api.getTickerAsync]);
- yield put(MarketReducer.actions.receiveTicker(state3));
+ yield put(marketActions.receiveTicker(state3));
} catch (error) {
console.error('~~ Saga fetchMarket error ~~>', error);
- yield put({type: 'global/STEEM_API_ERROR', error: error.message});
+ yield put(appActions.steemApiError(error.message));
}
yield call(wait, 3000);
@@ -57,15 +70,15 @@ export function* fetchMarket(location_change_action) {
}
export function* fetchOpenOrders(set_user_action) {
- const {username} = set_user_action.payload
+ const { username } = set_user_action.payload;
try {
const state = yield call([api, api.getOpenOrdersAsync], username);
- yield put(MarketReducer.actions.receiveOpenOrders(state));
+ yield put(marketActions.receiveOpenOrders(state));
yield call(getAccount, username, true);
} catch (error) {
console.error('~~ Saga fetchOpenOrders error ~~>', error);
- yield put({type: 'global/STEEM_API_ERROR', error: error.message});
+ yield put(appActions.steemApiError(error.message));
}
}
@@ -75,7 +88,7 @@ export function* reloadMarket(reload_action) {
}
export function* watchUserLogin() {
- yield* takeLatest('user/SET_USER', fetchOpenOrders);
+ yield* takeLatest(userActions.SET_USER, fetchOpenOrders);
}
export function* watchLocationChange() {
@@ -83,5 +96,5 @@ export function* watchLocationChange() {
}
export function* watchMarketUpdate() {
- yield* takeLatest('market/UPDATE_MARKET', reloadMarket);
+ yield* takeLatest(marketActions.UPDATE_MARKET, reloadMarket);
}
diff --git a/src/app/redux/Offchain.jsx b/src/app/redux/OffchainReducer.js
similarity index 56%
rename from src/app/redux/Offchain.jsx
rename to src/app/redux/OffchainReducer.js
index 08fa018f22ffbcc708f27de2a847d55f87958b67..3a0188a88f7e6cf57982dcc164b9081125313336 100644
--- a/src/app/redux/Offchain.jsx
+++ b/src/app/redux/OffchainReducer.js
@@ -1,9 +1,9 @@
import Immutable from 'immutable';
-import {PropTypes} from 'react';
+import { PropTypes } from 'react';
-const defaultState = Immutable.fromJS({user: {}});
+const defaultState = Immutable.fromJS({ user: {} });
-export default function reducer(state = defaultState, action) {
+export default function reducer(state = defaultState, action = {}) {
if (action.type === 'user/SAVE_LOGIN_CONFIRM') {
if (!action.payload) {
state = state.set('account', null);
diff --git a/src/app/redux/OffchainReducer.test.js b/src/app/redux/OffchainReducer.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..9f81ccba3646d938a2aeb4e4bbe6941434b34450
--- /dev/null
+++ b/src/app/redux/OffchainReducer.test.js
@@ -0,0 +1,23 @@
+import { Map } from 'immutable';
+import reducer from './OffchainReducer';
+
+const mockAction = {
+ type: 'user/SAVE_LOGIN_CONFIRM',
+};
+
+const mockActionWithPayload = { ...mockAction, payload: 'Foo Barman' };
+
+describe('offchain reducer', () => {
+ it('should provide a nice initial state, with any payload', () => {
+ const initial = reducer();
+ const expected = Map({ user: Map({}) });
+ expect(initial).toEqual(expected);
+ const withPayload = reducer(initial, mockActionWithPayload);
+ expect(withPayload).toEqual(expected);
+ });
+ it('should return an account of null when action has no payload', () => {
+ const initial = reducer();
+ const account = reducer(initial, mockAction);
+ expect(account).toEqual(Map({ user: Map({}), account: null }));
+ });
+});
diff --git a/src/app/redux/PollDataSaga.js b/src/app/redux/PollDataSaga.js
deleted file mode 100644
index 5f676d122cad6fd753e8663ad455cbffe02b78d9..0000000000000000000000000000000000000000
--- a/src/app/redux/PollDataSaga.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import { call, put, select } from 'redux-saga/effects';
-import GlobalReducer from './GlobalReducer';
-import {getNotifications, webPushRegister} from 'app/utils/ServerApiClient';
-import registerServiceWorker from 'app/utils/RegisterServiceWorker';
-import {api} from 'steem';
-
-const wait = ms => (
- new Promise(resolve => {
- setTimeout(() => resolve(), ms)
- })
-)
-
-let webpush_params = null;
-
-function* pollData() {
- while(true) {
- yield call(wait, 20000);
-
- const username = yield select(state => state.user.getIn(['current', 'username']));
- if (username) {
- if (webpush_params === null) {
- try {
- webpush_params = yield call(registerServiceWorker);
- if (webpush_params) yield call(webPushRegister, username, webpush_params);
- } catch (error) {
- console.error(error);
- webpush_params = {error};
- }
- }
- const nc = yield call(getNotifications, username, webpush_params);
- yield put({type: 'UPDATE_NOTIFICOUNTERS', payload: nc});
- }
-
- try {
- const data = yield call([api, api.getDynamicGlobalPropertiesAsync]);
- // console.log('-- pollData.pollData -->', data);
- // const data = yield call([api, api.getDiscussionsByCreatedAsync], {limit: 10});
- // yield put(GlobalReducer.actions.receiveRecentPosts({data}));
- } catch (error) {
- console.error('~~ pollData saga error ~~>', error);
- }
- }
-}
-
-export default pollData;
diff --git a/src/app/redux/RootReducer.js b/src/app/redux/RootReducer.js
index 5743bdd55b431a9c0027ad276f061ff7c56af98f..19a70ea6500b5ae51d6179150540e610028c9dc5 100644
--- a/src/app/redux/RootReducer.js
+++ b/src/app/redux/RootReducer.js
@@ -1,67 +1,58 @@
-import {Map, fromJS} from 'immutable';
-import {combineReducers} from 'redux';
-import {routerReducer} from 'react-router-redux';
+import { Map, fromJS } from 'immutable';
+import { routerReducer } from 'react-router-redux';
+import { combineReducers } from 'redux';
+import { reducer as formReducer } from 'redux-form'; // @deprecated, instead use: app/utils/ReactForm.js
+
import appReducer from './AppReducer';
-//import discussionReducer from './DiscussionReducer';
-import globalReducerModule from './GlobalReducer';
-import marketReducerModule from './MarketReducer';
-import user from './User';
-// import auth from './AuthSaga';
-import transaction from './Transaction';
-import offchain from './Offchain';
-import {reducer as formReducer} from 'redux-form'; // @deprecated, instead use: app/utils/ReactForm.js
-import {contentStats} from 'app/utils/StateFunctions'
+import globalReducer from './GlobalReducer';
+import marketReducer from './MarketReducer';
+import userReducer from './UserReducer';
+import transactionReducer from './TransactionReducer';
+import offchainReducer from './OffchainReducer';
+import { contentStats } from 'app/utils/StateFunctions';
function initReducer(reducer, type) {
return (state, action) => {
- if(!state) return reducer(state, action);
+ if (!state) return reducer(state, action);
// @@redux/INIT server and client init
if (action.type === '@@redux/INIT' || action.type === '@@INIT') {
- if(!(state instanceof Map)) {
+ if (!(state instanceof Map)) {
state = fromJS(state);
}
- if(type === 'global') {
+ if (type === 'global') {
const content = state.get('content').withMutations(c => {
c.forEach((cc, key) => {
- if(!c.getIn([key, 'stats'])) {
+ if (!c.getIn([key, 'stats'])) {
// This may have already been set in UniversalRender; if so, then
// active_votes were cleared from server response. In this case it
// is important to not try to recalculate the stats. (#1040)
- c.setIn([key, 'stats'], fromJS(contentStats(cc)))
+ c.setIn([key, 'stats'], fromJS(contentStats(cc)));
}
- })
- })
- state = state.set('content', content)
+ });
+ });
+ state = state.set('content', content);
}
- return state
+ return state;
}
if (action.type === '@@router/LOCATION_CHANGE' && type === 'global') {
- state = state.set('pathname', action.payload.pathname)
+ state = state.set('pathname', action.payload.pathname);
// console.log(action.type, type, action, state.toJS())
}
return reducer(state, action);
- }
+ };
}
export default combineReducers({
- global: initReducer(globalReducerModule.reducer, 'global'),
- market: initReducer(marketReducerModule.reducer),
- offchain: initReducer(offchain),
- user: initReducer(user.reducer),
- // auth: initReducer(auth.reducer),
- transaction: initReducer(transaction.reducer),
- //discussion: initReducer(discussionReducer),
+ global: initReducer(globalReducer, 'global'),
+ market: initReducer(marketReducer),
+ offchain: initReducer(offchainReducer),
+ user: initReducer(userReducer),
+ transaction: initReducer(transactionReducer),
discussion: initReducer((state = {}) => state),
routing: initReducer(routerReducer),
app: initReducer(appReducer),
form: formReducer,
});
-
-/*
-let now
- benchStart: initReducer((state = {}, action) => {console.log('>> action.type', action.type); now = Date.now(); return state}),
- benchEnd: initReducer((state = {}, action) => {console.log('<< action.type', action.type, (Date.now() - now), 'ms'); return state}),
-*/
diff --git a/src/app/redux/SagaShared.js b/src/app/redux/SagaShared.js
index 7d99ce9350329645dcaa094198999eae5cf80c16..6af797d6935f5405948b23e5e3529e3936449776 100644
--- a/src/app/redux/SagaShared.js
+++ b/src/app/redux/SagaShared.js
@@ -1,42 +1,49 @@
-import {fromJS} from 'immutable'
-import {call, put, select} from 'redux-saga/effects';
-import g from 'app/redux/GlobalReducer'
-import {takeEvery, takeLatest} from 'redux-saga';
+import { fromJS } from 'immutable';
+import { call, put, select } from 'redux-saga/effects';
+import { takeEvery, takeLatest } from 'redux-saga';
import tt from 'counterpart';
-import {api} from 'steem';
-import {setUserPreferences} from 'app/utils/ServerApiClient';
+import { api } from '@steemit/steem-js';
+import * as globalActions from './GlobalReducer';
+import * as appActions from './AppReducer';
+import * as transactionActions from './TransactionReducer';
+import { setUserPreferences } from 'app/utils/ServerApiClient';
-const wait = ms => (
+const wait = ms =>
new Promise(resolve => {
- setTimeout(() => resolve(), ms)
- })
-);
+ setTimeout(() => resolve(), ms);
+ });
-export const sharedWatches = [watchGetState, watchTransactionErrors, watchUserSettingsUpdates]
+export const sharedWatches = [
+ watchGetState,
+ watchTransactionErrors,
+ watchUserSettingsUpdates,
+];
export function* getAccount(username, force = false) {
- let account = yield select(state => state.global.get('accounts').get(username))
+ let account = yield select(state =>
+ state.global.get('accounts').get(username)
+ );
if (force || !account) {
- [account] = yield call([api, api.getAccountsAsync], [username])
- if(account) {
- account = fromJS(account)
- yield put(g.actions.receiveAccount({account}))
+ [account] = yield call([api, api.getAccountsAsync], [username]);
+ if (account) {
+ account = fromJS(account);
+ yield put(globalActions.receiveAccount({ account }));
}
}
- return account
+ return account;
}
export function* watchGetState() {
- yield* takeEvery('global/GET_STATE', getState);
+ yield* takeEvery(globalActions.GET_STATE, getState);
}
/** Manual refreshes. The router is in FetchDataSaga. */
-export function* getState({payload: {url}}) {
+export function* getState({ payload: { url } }) {
try {
- const state = yield call([api, api.getStateAsync], url)
- yield put(g.actions.receiveState(state));
+ const state = yield call([api, api.getStateAsync], url);
+ yield put(globalActions.receiveState(state));
} catch (error) {
console.error('~~ Saga getState error ~~>', url, error);
- yield put({type: 'global/STEEM_API_ERROR', error: error.message});
+ yield put(appActions.steemApiError(error.message));
}
}
@@ -47,22 +54,23 @@ export function* watchTransactionErrors() {
function* showTransactionErrorNotification() {
const errors = yield select(state => state.transaction.get('errors'));
for (const [key, message] of errors) {
- yield put({type: 'ADD_NOTIFICATION', payload: {key, message}});
- yield put({type: 'transaction/DELETE_ERROR', payload: {key}});
+ yield put(appActions.addNotification({ key, message }));
+ yield put(transactionActions.deleteError({ key }));
}
}
-export function* getContent({author, permlink, resolve, reject}) {
+export function* getContent({ author, permlink, resolve, reject }) {
let content;
- while(!content) {
+ while (!content) {
content = yield call([api, api.getContentAsync], author, permlink);
- if(content["author"] == "") { // retry if content not found. #1870
+ if (content['author'] == '') {
+ // retry if content not found. #1870
content = null;
yield call(wait, 3000);
}
}
- yield put(g.actions.receiveContent({content}))
+ yield put(globalActions.receiveContent({ content }));
if (resolve && content) {
resolve(content);
} else if (reject && !content) {
@@ -75,7 +83,7 @@ export function* getContent({author, permlink, resolve, reject}) {
*
* @param {Object?} params.payload
*/
-function* saveUserPreferences({payload}) {
+function* saveUserPreferences({ payload }) {
if (payload) {
yield setUserPreferences(payload);
}
@@ -85,5 +93,12 @@ function* saveUserPreferences({payload}) {
}
function* watchUserSettingsUpdates() {
- yield* takeLatest(['SET_USER_PREFERENCES', 'TOGGLE_NIGHTMODE', 'TOGGLE_BLOGMODE'], saveUserPreferences);
+ yield* takeLatest(
+ [
+ appActions.SET_USER_PREFERENCES,
+ appActions.TOGGLE_NIGHTMODE,
+ appActions.TOGGLE_BLOGMODE,
+ ],
+ saveUserPreferences
+ );
}
diff --git a/src/app/redux/Transaction.js b/src/app/redux/Transaction.js
deleted file mode 100644
index 435e1a0b7988025031b9377d9022fda662a1c0f6..0000000000000000000000000000000000000000
--- a/src/app/redux/Transaction.js
+++ /dev/null
@@ -1,140 +0,0 @@
-import {fromJS, Map} from 'immutable';
-import createModule from 'redux-modules';
-
-export default createModule({
- name: 'transaction',
- initialState: fromJS({
- operations: [],
- status: { key: '', error: false, busy: false, },
- errors: null
- }),
- transformations: [
- {
- action: 'CONFIRM_OPERATION',
- reducer: (state, {payload}) => {
- const operation = fromJS(payload.operation)
- const confirm = payload.confirm
- const warning = payload.warning
- const checkbox = payload.checkbox
- return state.merge({
- show_confirm_modal: true,
- confirmBroadcastOperation: operation,
- confirmErrorCallback: payload.errorCallback,
- confirm,
- warning,
- checkbox
- })
- }
- },
- { action: 'HIDE_CONFIRM', reducer: state =>
- state.merge({show_confirm_modal: false, confirmBroadcastOperation: undefined, confirm: undefined})
- },
- {
- // An error will end up in QUEUE
- action: 'BROADCAST_OPERATION',
- reducer: (state) => {//, {payload: {type, operation, keys}}
- // See TransactionSaga.js
- return state
- },
- },
- {
- // An error will end up in QUEUE
- action: 'UPDATE_AUTHORITIES',
- reducer: (state) => state,
- },
- {
- // An error will end up in QUEUE
- action: 'UPDATE_META',
- reducer: (state) => state,
- },
- {
- action: 'ERROR',
- reducer: (state, {payload: {operations, error, errorCallback}}) => {
- let errorStr = error.toString();
- let errorKey = 'Transaction broadcast error.';
- for (const [type/*, operation*/] of operations) {
- switch (type) {
- case 'vote':
- if (/uniqueness constraint/.test(errorStr)) {
- errorKey = 'You already voted for this post';
- console.error('You already voted for this post.')
- }
- break;
- case 'comment':
- if (/You may only post once per minute/.test(errorStr)) {
- errorKey = 'You may only post once per minute.'
- } else if (errorStr === 'Testing, fake error')
- errorKey = 'Testing, fake error';
- break;
- case 'transfer':
- if (/get_balance/.test(errorStr)) {
- errorKey = 'Insufficient balance.'
- }
- break;
- case 'withdraw_vesting':
- if(/Account registered by another account requires 10x account creation fee worth of Steem Power/.test(errorStr))
- errorKey = 'Account requires 10x the account creation fee in Steem Power (approximately 300 SP) before it can power down.'
- break;
- default:
- break;
- }
- if (state.hasIn(['TransactionError', type + '_listener'])) {
- state = state.setIn(['TransactionError', type], fromJS({key: errorKey, exception: errorStr}))
- } else {
- if (error.message) {
- // Depends on FC_ASSERT formatting
- // https://github.com/steemit/steemit.com/issues/222
- const err_lines = error.message.split('\n');
- if (err_lines.length > 2) {
- errorKey = err_lines[1];
- const txt = errorKey.split(': ');
- if(txt.length && txt[txt.length - 1].trim() !== '') {
- errorKey = errorStr = txt[txt.length - 1]
- } else
- errorStr = `Transaction failed: ${err_lines[1]}`;
- }
- }
- if (errorStr.length > 200) errorStr = errorStr.substring(0, 200);
- // Catch for unknown key better error handling
- if (/unknown key: /.test(errorKey)) {
- errorKey = "Steem account doesn't exist.";
- errorStr = "Transaction failed: Steem account doesn't exist.";
- }
- // Catch for invalid active authority
- if (/Missing Active Authority /.test(errorKey)) {
- errorKey = "Not your valid active key.";
- errorStr = "Transaction failed: Not your valid active key.";
- }
- state = state.update('errors', errors => {
- return errors ? errors.set(errorKey, errorStr) : Map({[errorKey]: errorStr});
- });
- }
- }
- if (errorCallback) try { errorCallback(errorKey) } catch (error2) { console.error(error2) }
- return state
- },
- },
- {
- action: 'DELETE_ERROR',
- reducer: (state, {payload: {key}}) => {
- return state.deleteIn(['errors', key]);
- }
- },
- {
- action: 'SET',
- reducer: (state, {payload: {key, value}}) => {
- key = Array.isArray(key) ? key : [key]
- return state.setIn(key, fromJS(value))
- }
- },
- {
- action: 'REMOVE',
- reducer: (state, {payload: {key}}) => {
- key = Array.isArray(key) ? key : [key]
- return state.removeIn(key)
- }
- },
- ]
-});
-
-// const log = v => {console.log('l', v); return v}
diff --git a/src/app/redux/TransactionReducer.js b/src/app/redux/TransactionReducer.js
new file mode 100644
index 0000000000000000000000000000000000000000..9340850f36433bd38cc4953b3cef9a29de661bee
--- /dev/null
+++ b/src/app/redux/TransactionReducer.js
@@ -0,0 +1,218 @@
+import { fromJS, Map } from 'immutable';
+
+// Action constants
+const CONFIRM_OPERATION = 'transaction/CONFIRM_OPERATION';
+const HIDE_CONFIRM = 'transaction/HIDE_CONFIRM';
+export const BROADCAST_OPERATION = 'transaction/BROADCAST_OPERATION';
+export const UPDATE_AUTHORITIES = 'transaction/UPDATE_AUTHORITIES';
+export const UPDATE_META = 'transaction/UPDATE_META';
+const ERROR = 'transaction/ERROR';
+const DELETE_ERROR = 'transaction/DELETE_ERROR';
+const SET = 'transaction/SET';
+const REMOVE = 'transaction/REMOVE';
+// Saga-related
+export const RECOVER_ACCOUNT = 'transaction/RECOVER_ACCOUNT';
+
+const defaultState = fromJS({
+ operations: [],
+ status: { key: '', error: false, busy: false },
+ errors: null,
+});
+
+export default function reducer(state = defaultState, action) {
+ const payload = action.payload;
+
+ switch (action.type) {
+ case CONFIRM_OPERATION: {
+ const operation = fromJS(payload.operation);
+ const confirm = payload.confirm;
+ const warning = payload.warning;
+ return state.merge({
+ show_confirm_modal: true,
+ confirmBroadcastOperation: operation,
+ confirmErrorCallback: payload.errorCallback,
+ confirm,
+ warning,
+ });
+ }
+
+ case HIDE_CONFIRM:
+ return state.merge({
+ show_confirm_modal: false,
+ confirmBroadcastOperation: undefined,
+ confirm: undefined,
+ });
+
+ case BROADCAST_OPERATION:
+ // See TransactionSaga.js
+ return state;
+
+ case UPDATE_AUTHORITIES:
+ return state;
+
+ case UPDATE_META:
+ return state;
+
+ case ERROR: {
+ const { operations, error, errorCallback } = payload;
+ let errorStr = error.toString();
+ let errorKey = 'Transaction broadcast error.';
+ for (const [type /*, operation*/] of operations) {
+ switch (type) {
+ case 'vote':
+ if (/uniqueness constraint/.test(errorStr)) {
+ errorKey = 'You already voted for this post';
+ console.error('You already voted for this post.');
+ }
+ break;
+ case 'comment':
+ if (
+ /You may only post once per minute/.test(errorStr)
+ ) {
+ errorKey = 'You may only post once per minute.';
+ } else if (errorStr === 'Testing, fake error')
+ errorKey = 'Testing, fake error';
+ break;
+ case 'transfer':
+ if (/get_balance/.test(errorStr)) {
+ errorKey = 'Insufficient balance.';
+ }
+ break;
+ case 'withdraw_vesting':
+ if (
+ /Account registered by another account requires 10x account creation fee worth of Steem Power/.test(
+ errorStr
+ )
+ )
+ errorKey =
+ 'Account requires 10x the account creation fee in Steem Power (approximately 30 SP) before it can power down.';
+ break;
+ default:
+ break;
+ }
+ if (state.hasIn(['TransactionError', type + '_listener'])) {
+ state = state.setIn(
+ ['TransactionError', type],
+ fromJS({ key: errorKey, exception: errorStr })
+ );
+ } else {
+ if (error.message) {
+ // Depends on FC_ASSERT formatting
+ // https://github.com/steemit/steemit.com/issues/222
+ const err_lines = error.message.split('\n');
+ if (err_lines.length > 2) {
+ errorKey = err_lines[1];
+ const txt = errorKey.split(': ');
+ if (
+ txt.length &&
+ txt[txt.length - 1].trim() !== ''
+ ) {
+ errorKey = errorStr = txt[txt.length - 1];
+ } else
+ errorStr = `Transaction failed: ${
+ err_lines[1]
+ }`;
+ }
+ }
+ if (errorStr.length > 200)
+ errorStr = errorStr.substring(0, 200);
+ // Catch for unknown key better error handling
+ if (/unknown key: /.test(errorKey)) {
+ errorKey = "Steem account doesn't exist.";
+ errorStr =
+ "Transaction failed: Steem account doesn't exist.";
+ }
+ // Catch for invalid active authority
+ if (/Missing Active Authority /.test(errorKey)) {
+ errorKey = 'Not your valid active key.';
+ errorStr =
+ 'Transaction failed: Not your valid active key.';
+ }
+ state = state.update('errors', errors => {
+ return errors
+ ? errors.set(errorKey, errorStr)
+ : Map({ [errorKey]: errorStr });
+ });
+ }
+ }
+
+ if (errorCallback) {
+ errorCallback(errorKey);
+ } else {
+ throw new Error(
+ 'PANIC: no callback registered to handle error ' + errorKey
+ );
+ }
+
+ return state;
+ }
+
+ case DELETE_ERROR:
+ return state.deleteIn(['errors', payload.key]);
+
+ case SET:
+ return state.setIn(
+ Array.isArray(payload.key) ? payload.key : [payload.key],
+ fromJS(payload.value)
+ );
+
+ case REMOVE:
+ return state.removeIn(
+ Array.isArray(payload.key) ? payload.key : [payload.key]
+ );
+
+ default:
+ return state;
+ }
+}
+
+// Action creators
+export const confirmOperation = payload => ({
+ type: CONFIRM_OPERATION,
+ payload,
+});
+
+export const hideConfirm = payload => ({
+ type: HIDE_CONFIRM,
+ payload,
+});
+
+export const broadcastOperation = payload => ({
+ type: BROADCAST_OPERATION,
+ payload,
+});
+
+export const updateAuthorities = payload => ({
+ type: UPDATE_AUTHORITIES,
+ payload,
+});
+
+export const updateMeta = payload => ({
+ type: UPDATE_META,
+ payload,
+});
+
+export const error = payload => ({
+ type: ERROR,
+ payload,
+});
+
+export const deleteError = payload => ({
+ type: DELETE_ERROR,
+ payload,
+});
+
+export const set = payload => ({
+ type: SET,
+ payload,
+});
+
+export const remove = payload => ({
+ type: REMOVE,
+ payload,
+});
+
+export const recoverAccount = payload => ({
+ type: RECOVER_ACCOUNT,
+ payload,
+});
diff --git a/src/app/redux/TransactionSaga.js b/src/app/redux/TransactionSaga.js
index 5d5246b7f1aacabcf561320e15d56e00d0c2f75b..f33535dafa0028ed5068105a53cff2d4eff5bdb4 100644
--- a/src/app/redux/TransactionSaga.js
+++ b/src/app/redux/TransactionSaga.js
@@ -1,36 +1,43 @@
-import {takeEvery} from 'redux-saga';
-import {call, put, select} from 'redux-saga/effects';
-import {fromJS, Set, Map} from 'immutable'
-import {getAccount, getContent} from 'app/redux/SagaShared'
-import {findSigningKey} from 'app/redux/AuthSaga'
-import g from 'app/redux/GlobalReducer'
-import user from 'app/redux/User'
-import tr from 'app/redux/Transaction'
-import tt from 'counterpart'
-import getSlug from 'speakingurl'
-import {DEBT_TICKER} from 'app/client_config'
-import {serverApiRecordEvent} from 'app/utils/ServerApiClient'
-import {PrivateKey, PublicKey} from 'steem/lib/auth/ecc';
-import {api, broadcast, auth, memo} from 'steem';
+import { takeEvery } from 'redux-saga';
+import { call, put, select } from 'redux-saga/effects';
+import { fromJS, Set, Map } from 'immutable';
+import tt from 'counterpart';
+import getSlug from 'speakingurl';
+import base58 from 'bs58';
+import secureRandom from 'secure-random';
+import { PrivateKey, PublicKey } from '@steemit/steem-js/lib/auth/ecc';
+import { api, broadcast, auth, memo } from '@steemit/steem-js';
+
+import { getAccount, getContent } from 'app/redux/SagaShared';
+import { findSigningKey } from 'app/redux/AuthSaga';
+import * as appActions from 'app/redux/AppReducer';
+import * as globalActions from 'app/redux/GlobalReducer';
+import * as transactionActions from 'app/redux/TransactionReducer';
+import * as userActions from 'app/redux/UserReducer';
+import { DEBT_TICKER } from 'app/client_config';
+import { serverApiRecordEvent } from 'app/utils/ServerApiClient';
export const transactionWatches = [
watchForBroadcast,
watchForUpdateAuthorities,
watchForUpdateMeta,
watchForRecoverAccount,
-]
+];
export function* watchForBroadcast() {
- yield* takeEvery('transaction/BROADCAST_OPERATION', broadcastOperation);
+ yield* takeEvery(
+ transactionActions.BROADCAST_OPERATION,
+ broadcastOperation
+ );
}
export function* watchForUpdateAuthorities() {
- yield* takeEvery('transaction/UPDATE_AUTHORITIES', updateAuthorities);
+ yield* takeEvery(transactionActions.UPDATE_AUTHORITIES, updateAuthorities);
}
export function* watchForUpdateMeta() {
- yield* takeEvery('transaction/UPDATE_META', updateMeta);
+ yield* takeEvery(transactionActions.UPDATE_META, updateMeta);
}
export function* watchForRecoverAccount() {
- yield* takeEvery('transaction/RECOVER_ACCOUNT', recoverAccount);
+ yield* takeEvery(transactionActions.RECOVER_ACCOUNT, recoverAccount);
}
const hook = {
@@ -48,165 +55,275 @@ const hook = {
accepted_vote,
accepted_account_update,
accepted_withdraw_vesting,
-}
-
-function* preBroadcast_transfer({operation}) {
- let memoStr = operation.memo
- if(memoStr) {
- memoStr = toStringUtf8(memoStr)
- memoStr = memoStr.trim()
- if(/^#/.test(memoStr)) {
- const memo_private = yield select(
- state => state.user.getIn(['current', 'private_keys', 'memo_private'])
- )
- if(!memo_private) throw new Error('Unable to encrypt memo, missing memo private key')
- const account = yield call(getAccount, operation.to)
- if(!account) throw new Error(`Unknown to account ${operation.to}`)
- const memo_key = account.get('memo_key')
- memoStr = memo.encode(memo_private, memo_key, memoStr)
- operation.memo = memoStr
+};
+
+export function* preBroadcast_transfer({ operation }) {
+ let memoStr = operation.memo;
+ if (memoStr) {
+ memoStr = toStringUtf8(memoStr);
+ memoStr = memoStr.trim();
+ if (/^#/.test(memoStr)) {
+ const memo_private = yield select(state =>
+ state.user.getIn(['current', 'private_keys', 'memo_private'])
+ );
+ if (!memo_private)
+ throw new Error(
+ 'Unable to encrypt memo, missing memo private key'
+ );
+ const account = yield call(getAccount, operation.to);
+ if (!account) throw new Error(`Unknown to account ${operation.to}`);
+ const memo_key = account.get('memo_key');
+ memoStr = memo.encode(memo_private, memo_key, memoStr);
+ operation.memo = memoStr;
}
}
- return operation
+ return operation;
}
-const toStringUtf8 = o => (o ? Buffer.isBuffer(o) ? o.toString('utf-8') : o.toString() : o)
+const toStringUtf8 = o =>
+ o ? (Buffer.isBuffer(o) ? o.toString('utf-8') : o.toString()) : o;
-function* preBroadcast_vote({operation, username}) {
- if (!operation.voter) operation.voter = username
- const {voter, author, permlink, weight} = operation
+function* preBroadcast_vote({ operation, username }) {
+ if (!operation.voter) operation.voter = username;
+ const { voter, author, permlink, weight } = operation;
// give immediate feedback
- yield put(g.actions.set({key: `transaction_vote_active_${author}_${permlink}`, value: true}))
- yield put(g.actions.voted({username: voter, author, permlink, weight}))
- return operation
+ yield put(
+ globalActions.set({
+ key: `transaction_vote_active_${author}_${permlink}`,
+ value: true,
+ })
+ );
+ yield put(
+ globalActions.voted({ username: voter, author, permlink, weight })
+ );
+ return operation;
}
-function* preBroadcast_account_witness_vote({operation, username}) {
- if (!operation.account) operation.account = username
- const {account, witness, approve} = operation
- yield put(g.actions.updateAccountWitnessVote({account, witness, approve}))
- return operation
+function* preBroadcast_account_witness_vote({ operation, username }) {
+ if (!operation.account) operation.account = username;
+ const { account, witness, approve } = operation;
+ yield put(
+ globalActions.updateAccountWitnessVote({ account, witness, approve })
+ );
+ return operation;
}
-function* preBroadcast_custom_json({operation}) {
- const json = JSON.parse(operation.json)
- if(operation.id === 'follow') {
+function* preBroadcast_custom_json({ operation }) {
+ const json = JSON.parse(operation.json);
+ if (operation.id === 'follow') {
try {
- if(json[0] === 'follow') {
- const {follower, following, what: [action]} = json[1]
- yield put(g.actions.update({
- key: ['follow', 'getFollowingAsync', follower],
- notSet: Map(),
- updater: m => {
- //m = m.asMutable()
- if(action == null) {
- m = m.update('blog_result', Set(), r => r.delete(following))
- m = m.update('ignore_result', Set(), r => r.delete(following))
- } else if(action === 'blog') {
- m = m.update('blog_result', Set(), r => r.add(following))
- m = m.update('ignore_result', Set(), r => r.delete(following))
- } else if(action === 'ignore') {
- m = m.update('ignore_result', Set(), r => r.add(following))
- m = m.update('blog_result', Set(), r => r.delete(following))
- }
- m = m.set('blog_count', m.get('blog_result', Set()).size)
- m = m.set('ignore_count', m.get('ignore_result', Set()).size)
- return m//.asImmutable()
- }
- }))
+ if (json[0] === 'follow') {
+ const { follower, following, what: [action] } = json[1];
+ yield put(
+ globalActions.update({
+ key: ['follow', 'getFollowingAsync', follower],
+ notSet: Map(),
+ updater: m => {
+ //m = m.asMutable()
+ if (action == null) {
+ m = m.update('blog_result', Set(), r =>
+ r.delete(following)
+ );
+ m = m.update('ignore_result', Set(), r =>
+ r.delete(following)
+ );
+ } else if (action === 'blog') {
+ m = m.update('blog_result', Set(), r =>
+ r.add(following)
+ );
+ m = m.update('ignore_result', Set(), r =>
+ r.delete(following)
+ );
+ } else if (action === 'ignore') {
+ m = m.update('ignore_result', Set(), r =>
+ r.add(following)
+ );
+ m = m.update('blog_result', Set(), r =>
+ r.delete(following)
+ );
+ }
+ m = m.set(
+ 'blog_count',
+ m.get('blog_result', Set()).size
+ );
+ m = m.set(
+ 'ignore_count',
+ m.get('ignore_result', Set()).size
+ );
+ return m; //.asImmutable()
+ },
+ })
+ );
}
- } catch(e) {
- console.error('TransactionSaga unrecognized follow custom_json format', operation.json);
+ } catch (e) {
+ console.error(
+ 'TransactionSaga unrecognized follow custom_json format',
+ operation.json
+ );
}
}
- return operation
+ return operation;
}
-function* error_account_witness_vote({operation: {account, witness, approve}}) {
- yield put(g.actions.updateAccountWitnessVote({account, witness, approve: !approve}))
+function* error_account_witness_vote({
+ operation: { account, witness, approve },
+}) {
+ yield put(
+ globalActions.updateAccountWitnessVote({
+ account,
+ witness,
+ approve: !approve,
+ })
+ );
}
/** Keys, username, and password are not needed for the initial call. This will check the login and may trigger an action to prompt for the password / key. */
-function* broadcastOperation({payload:
- {type, operation, confirm, warning, keys, username, password, successCallback, errorCallback, allowPostUnsafe}
+function* broadcastOperation({
+ payload: {
+ type,
+ operation,
+ confirm,
+ warning,
+ keys,
+ username,
+ password,
+ successCallback,
+ errorCallback,
+ allowPostUnsafe,
+ },
}) {
- const operationParam = {type, operation, keys, username, password, successCallback, errorCallback, allowPostUnsafe}
-
- const conf = typeof confirm === 'function' ? confirm() : confirm
- if(conf) {
- yield put(tr.actions.confirmOperation({confirm, warning, operation: operationParam, errorCallback}))
- return
+ const operationParam = {
+ type,
+ operation,
+ keys,
+ username,
+ password,
+ successCallback,
+ errorCallback,
+ allowPostUnsafe,
+ };
+
+ const conf = typeof confirm === 'function' ? confirm() : confirm;
+ if (conf) {
+ yield put(
+ transactionActions.confirmOperation({
+ confirm,
+ warning,
+ operation: operationParam,
+ errorCallback,
+ })
+ );
+ return;
}
- const payload = {operations: [[type, operation]], keys, username, successCallback, errorCallback}
+ const payload = {
+ operations: [[type, operation]],
+ keys,
+ username,
+ successCallback,
+ errorCallback,
+ };
if (!allowPostUnsafe && hasPrivateKeys(payload)) {
- const confirm = tt('g.post_key_warning.confirm')
- const warning = tt('g.post_key_warning.warning')
- const checkbox = tt('g.post_key_warning.checkbox')
- operationParam.allowPostUnsafe = true
- yield put(tr.actions.confirmOperation({confirm, warning, checkbox, operation: operationParam, errorCallback}))
- return
+ const confirm = tt('g.post_key_warning.confirm');
+ const warning = tt('g.post_key_warning.warning');
+ const checkbox = tt('g.post_key_warning.checkbox');
+ operationParam.allowPostUnsafe = true;
+ yield put(
+ transactionActions.confirmOperation({
+ confirm,
+ warning,
+ checkbox,
+ operation: operationParam,
+ errorCallback,
+ })
+ );
+ return;
}
try {
if (!keys || keys.length === 0) {
- payload.keys = []
+ payload.keys = [];
// user may already be logged in, or just enterend a signing passowrd or wif
- const signingKey = yield call(findSigningKey, {opType: type, username, password})
- if (signingKey)
- payload.keys.push(signingKey)
+ const signingKey = yield call(findSigningKey, {
+ opType: type,
+ username,
+ password,
+ });
+ if (signingKey) payload.keys.push(signingKey);
else {
if (!password) {
- yield put(user.actions.showLogin({operation: {type, operation, username, successCallback, errorCallback, saveLogin: true}}))
- return
+ yield put(
+ userActions.showLogin({
+ operation: {
+ type,
+ operation,
+ username,
+ successCallback,
+ errorCallback,
+ saveLogin: true,
+ },
+ })
+ );
+ return;
}
}
}
- yield call(broadcastPayload, {payload})
- let eventType = type.replace(/^([a-z])/, g => g.toUpperCase()).replace(/_([a-z])/g, g => g[1].toUpperCase());
- if (eventType === 'Comment' && !operation.parent_author) eventType = 'Post';
- const page = eventType === 'Vote' ? `@${operation.author}/${operation.permlink}` : '';
+ yield call(broadcastPayload, { payload });
+ let eventType = type
+ .replace(/^([a-z])/, g => g.toUpperCase())
+ .replace(/_([a-z])/g, g => g[1].toUpperCase());
+ if (eventType === 'Comment' && !operation.parent_author)
+ eventType = 'Post';
+ const page =
+ eventType === 'Vote'
+ ? `@${operation.author}/${operation.permlink}`
+ : '';
serverApiRecordEvent(eventType, page);
- } catch(error) {
+ } catch (error) {
console.error('TransactionSage', error);
- if(errorCallback) errorCallback(error.toString())
+ if (errorCallback) errorCallback(error.toString());
}
}
function hasPrivateKeys(payload) {
- const blob = JSON.stringify(payload.operations)
- let m, re = /P?(5[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{50})/g
+ const blob = JSON.stringify(payload.operations);
+ let m,
+ re = /P?(5[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{50})/g;
while (true) {
- m = re.exec(blob)
+ m = re.exec(blob);
if (m) {
try {
- PrivateKey.fromWif(m[1]) // performs the base58check
- return true
+ PrivateKey.fromWif(m[1]); // performs the base58check
+ return true;
} catch (e) {}
} else {
- break
+ break;
}
}
- return false
+ return false;
}
-function* broadcastPayload({payload: {operations, keys, username, successCallback, errorCallback}}) {
+function* broadcastPayload({
+ payload: { operations, keys, username, successCallback, errorCallback },
+}) {
// console.log('broadcastPayload')
if ($STM_Config.read_only_mode) return;
for (const [type] of operations) // see also transaction/ERROR
- yield put(tr.actions.remove({key: ['TransactionError', type]}))
+ yield put(
+ transactionActions.remove({ key: ['TransactionError', type] })
+ );
{
- const newOps = []
+ const newOps = [];
for (const [type, operation] of operations) {
if (hook['preBroadcast_' + type]) {
- const op = yield call(hook['preBroadcast_' + type], {operation, username})
- if(Array.isArray(op))
- for(const o of op)
- newOps.push(o)
- else
- newOps.push([type, op])
+ const op = yield call(hook['preBroadcast_' + type], {
+ operation,
+ username,
+ });
+ if (Array.isArray(op)) for (const o of op) newOps.push(o);
+ else newOps.push([type, op]);
} else {
- newOps.push([type, operation])
+ newOps.push([type, operation]);
}
}
- operations = newOps
+ operations = newOps;
}
// status: broadcasting
@@ -214,103 +331,143 @@ function* broadcastPayload({payload: {operations, keys, username, successCallbac
for (const [type, operation] of operations) {
if (hook['broadcasted_' + type]) {
try {
- hook['broadcasted_' + type]({operation})
+ hook['broadcasted_' + type]({ operation });
} catch (error) {
- console.error(error)
+ console.error(error);
}
}
}
- }
+ };
try {
yield new Promise((resolve, reject) => {
// Bump transaction (for live UI testing).. Put 0 in now (no effect),
// to enable browser's autocomplete and help prevent typos.
const env = process.env;
- const bump = env.BROWSER ? parseInt(localStorage.getItem('bump') || 0) : 0;
- if (env.BROWSER && bump === 1) { // for testing
- console.log('TransactionSaga bump(no broadcast) and reject', JSON.stringify(operations, null, 2))
- setTimeout(() => {reject(new Error('Testing, fake error'))}, 2000)
- } else if (env.BROWSER && bump === 2) { // also for testing
- console.log('TransactionSaga bump(no broadcast) and resolve', JSON.stringify(operations, null, 2))
- setTimeout(() => {resolve(); broadcastedEvent()}, 2000)
+ const bump = env.BROWSER
+ ? parseInt(localStorage.getItem('bump') || 0)
+ : 0;
+ if (env.BROWSER && bump === 1) {
+ // for testing
+ console.log(
+ 'TransactionSaga bump(no broadcast) and reject',
+ JSON.stringify(operations, null, 2)
+ );
+ setTimeout(() => {
+ reject(new Error('Testing, fake error'));
+ }, 2000);
+ } else if (env.BROWSER && bump === 2) {
+ // also for testing
+ console.log(
+ 'TransactionSaga bump(no broadcast) and resolve',
+ JSON.stringify(operations, null, 2)
+ );
+ setTimeout(() => {
+ resolve();
+ broadcastedEvent();
+ }, 2000);
} else {
- broadcast.send({ extensions: [], operations }, keys, (err) => {
- if(err) {
+ broadcast.send({ extensions: [], operations }, keys, err => {
+ if (err) {
console.error(err);
- reject(err)
+ reject(err);
} else {
- broadcastedEvent()
- resolve()
+ broadcastedEvent();
+ resolve();
}
- })
+ });
}
- })
+ });
// status: accepted
for (const [type, operation] of operations) {
if (hook['accepted_' + type]) {
try {
- yield call(hook['accepted_' + type], {operation})
+ yield call(hook['accepted_' + type], { operation });
} catch (error) {
- console.error(error)
+ console.error(error);
}
}
- const config = operation.__config
+ const config = operation.__config;
if (config && config.successMessage) {
- yield put({type: 'ADD_NOTIFICATION', payload: {
- key: "trx_" + Date.now(),
- message: config.successMessage,
- dismissAfter: 5000
- }})
+ yield put(
+ appActions.addNotification({
+ key: 'trx_' + Date.now(),
+ message: config.successMessage,
+ dismissAfter: 5000,
+ })
+ );
}
}
- if (successCallback) try { successCallback() } catch (error) { console.error(error) }
+ if (successCallback)
+ try {
+ successCallback();
+ } catch (error) {
+ console.error(error);
+ }
} catch (error) {
console.error('TransactionSaga\tbroadcastPayload', error);
// status: error
- yield put(tr.actions.error({operations, error, errorCallback}));
+ yield put(
+ transactionActions.error({ operations, error, errorCallback })
+ );
for (const [type, operation] of operations) {
if (hook['error_' + type]) {
try {
- yield call(hook['error_' + type], {operation})
+ yield call(hook['error_' + type], { operation });
} catch (error2) {
- console.error(error2)
+ console.error(error2);
}
}
}
}
}
-function* accepted_comment({operation}) {
- const {author, permlink} = operation
+function* accepted_comment({ operation }) {
+ const { author, permlink } = operation;
// update again with new $$ amount from the steemd node
- yield call(getContent, {author, permlink})
+ yield call(getContent, { author, permlink });
// receiveComment did the linking already (but that is commented out)
- yield put(g.actions.linkReply(operation))
+ yield put(globalActions.linkReply(operation));
// mark the time (can only post 1 per min)
// yield put(user.actions.acceptedComment())
}
-function* accepted_delete_comment({operation}) {
- yield put(g.actions.deleteContent(operation))
+function* accepted_delete_comment({ operation }) {
+ yield put(globalActions.deleteContent(operation));
}
-function* accepted_vote({operation: {author, permlink, weight}}) {
- console.log('Vote accepted, weight', weight, 'on', author + '/' + permlink, 'weight');
+function* accepted_vote({ operation: { author, permlink, weight } }) {
+ console.log(
+ 'Vote accepted, weight',
+ weight,
+ 'on',
+ author + '/' + permlink,
+ 'weight'
+ );
// update again with new $$ amount from the steemd node
- yield put(g.actions.remove({key: `transaction_vote_active_${author}_${permlink}`}))
- yield call(getContent, {author, permlink})
+ yield put(
+ globalActions.remove({
+ key: `transaction_vote_active_${author}_${permlink}`,
+ })
+ );
+ yield call(getContent, { author, permlink });
}
-function* accepted_withdraw_vesting({operation}) {
- let [account] = yield call([api, api.getAccountsAsync], [operation.account])
- account = fromJS(account)
- yield put(g.actions.receiveAccount({account}))
+function* accepted_withdraw_vesting({ operation }) {
+ let [account] = yield call(
+ [api, api.getAccountsAsync],
+ [operation.account]
+ );
+ account = fromJS(account);
+ yield put(globalActions.receiveAccount({ account }));
}
-function* accepted_account_update({operation}) {
- let [account] = yield call([api, api.getAccountsAsync], [operation.account])
- account = fromJS(account)
- yield put(g.actions.receiveAccount({account}))
+function* accepted_account_update({ operation }) {
+ let [account] = yield call(
+ [api, api.getAccountsAsync],
+ [operation.account]
+ );
+ account = fromJS(account);
+ yield put(globalActions.receiveAccount({ account }));
// bug, fork, etc.. the folowing would be mis-leading
// const {account} = operation
@@ -339,130 +496,153 @@ function* accepted_account_update({operation}) {
// }
// }
-import base58 from 'bs58'
-import secureRandom from 'secure-random'
-
// function* preBroadcast_account_witness_vote({operation, username}) {
// }
-function* preBroadcast_comment({operation, username}) {
- if (!operation.author) operation.author = username
- let permlink = operation.permlink
- const {author, __config: {originalBody, autoVote, comment_options}} = operation
- const {parent_author = '', parent_permlink = operation.category } = operation
- const {title} = operation
- let {body} = operation
-
- body = body.trim()
+export function* preBroadcast_comment({ operation, username }) {
+ if (!operation.author) operation.author = username;
+ let permlink = operation.permlink;
+ const {
+ author,
+ __config: { originalBody, autoVote, comment_options },
+ } = operation;
+ const {
+ parent_author = '',
+ parent_permlink = operation.category,
+ } = operation;
+ const { title } = operation;
+ let { body } = operation;
+
+ body = body.trim();
// TODO Slightly smaller blockchain comments: if body === json_metadata.steem.link && Object.keys(steem).length > 1 remove steem.link ..This requires an adjust of get_state and the API refresh of the comment to put the steem.link back if Object.keys(steem).length >= 1
- let body2
+ let body2;
if (originalBody) {
- const patch = createPatch(originalBody, body)
+ const patch = createPatch(originalBody, body);
// Putting body into buffer will expand Unicode characters into their true length
if (patch && patch.length < new Buffer(body, 'utf-8').length)
- body2 = patch
+ body2 = patch;
}
- if (!body2) body2 = body
- if (!permlink) permlink = yield createPermlink(title, author, parent_author, parent_permlink)
-
- const md = operation.json_metadata
- const json_metadata = typeof md === 'string' ? md : JSON.stringify(md)
+ if (!body2) body2 = body;
+ if (!permlink)
+ permlink = yield createPermlink(
+ title,
+ author,
+ parent_author,
+ parent_permlink
+ );
+
+ const md = operation.json_metadata;
+ const json_metadata = typeof md === 'string' ? md : JSON.stringify(md);
const op = {
...operation,
permlink: permlink.toLowerCase(),
- parent_author, parent_permlink, json_metadata,
+ parent_author,
+ parent_permlink,
+ json_metadata,
title: new Buffer((operation.title || '').trim(), 'utf-8'),
body: new Buffer(body2, 'utf-8'),
- }
+ };
- const comment_op = [
- ['comment', op],
- ]
+ const comment_op = [['comment', op]];
// comment_options must come directly after comment
- if(comment_options) {
+ if (comment_options) {
const {
- max_accepted_payout = ["1000000.000", DEBT_TICKER].join(" "),
+ max_accepted_payout = ['1000000.000', DEBT_TICKER].join(' '),
percent_steem_dollars = 10000, // 10000 === 100%
allow_votes = true,
allow_curation_rewards = true,
- } = comment_options
- comment_op.push(
- ['comment_options', {
+ } = comment_options;
+ comment_op.push([
+ 'comment_options',
+ {
author,
permlink,
max_accepted_payout,
percent_steem_dollars,
allow_votes,
allow_curation_rewards,
- extensions: comment_options.extensions ? comment_options.extensions : []
- }]
- )
+ extensions: comment_options.extensions
+ ? comment_options.extensions
+ : [],
+ },
+ ]);
}
- if(autoVote) {
- const vote = {voter: op.author, author: op.author, permlink: op.permlink, weight: 10000}
- comment_op.push(['vote', vote])
+ if (autoVote) {
+ const vote = {
+ voter: op.author,
+ author: op.author,
+ permlink: op.permlink,
+ weight: 10000,
+ };
+ comment_op.push(['vote', vote]);
}
- return comment_op
+ return comment_op;
}
-function* createPermlink(title, author, parent_author, parent_permlink) {
- let permlink
+export function* createPermlink(title, author, parent_author, parent_permlink) {
+ let permlink;
if (title && title.trim() !== '') {
- let s = slug(title)
- if(s === '') {
- s = base58.encode(secureRandom.randomBuffer(4))
+ let s = slug(title);
+ if (s === '') {
+ s = base58.encode(secureRandom.randomBuffer(4));
}
// ensure the permlink(slug) is unique
- const slugState = yield call([api, api.getContentAsync], author, s)
- let prefix
+ const slugState = yield call([api, api.getContentAsync], author, s);
+ let prefix;
if (slugState.body !== '') {
// make sure slug is unique
- prefix = base58.encode(secureRandom.randomBuffer(4)) + '-'
+ prefix = base58.encode(secureRandom.randomBuffer(4)) + '-';
} else {
- prefix = ''
+ prefix = '';
}
- permlink = prefix + s
+ permlink = prefix + s;
} else {
// comments: re-parentauthor-parentpermlink-time
- const timeStr = new Date().toISOString().replace(/[^a-zA-Z0-9]+/g, '')
- parent_permlink = parent_permlink.replace(/(-\d{8}t\d{9}z)/g, '')
- permlink = `re-${parent_author}-${parent_permlink}-${timeStr}`
+ const timeStr = new Date().toISOString().replace(/[^a-zA-Z0-9]+/g, '');
+ parent_permlink = parent_permlink.replace(/(-\d{8}t\d{9}z)/g, '');
+ permlink = `re-${parent_author}-${parent_permlink}-${timeStr}`;
}
- if(permlink.length > 255) {
+ if (permlink.length > 255) {
// STEEMIT_MAX_PERMLINK_LENGTH
- permlink = permlink.substring(permlink.length - 255, permlink.length)
+ permlink = permlink.substring(permlink.length - 255, permlink.length);
}
// only letters numbers and dashes shall survive
- permlink = permlink.toLowerCase().replace(/[^a-z0-9-]+/g, '')
- return permlink
+ permlink = permlink.toLowerCase().replace(/[^a-z0-9-]+/g, '');
+ return permlink;
}
-import diff_match_patch from 'diff-match-patch'
-const dmp = new diff_match_patch()
+import diff_match_patch from 'diff-match-patch';
+const dmp = new diff_match_patch();
-function createPatch(text1, text2) {
- if (!text1 && text1 === '') return undefined
- const patches = dmp.patch_make(text1, text2)
- const patch = dmp.patch_toText(patches)
- return patch
+export function createPatch(text1, text2) {
+ if (!text1 && text1 === '') return undefined;
+ const patches = dmp.patch_make(text1, text2);
+ const patch = dmp.patch_toText(patches);
+ return patch;
}
-function* error_custom_json({operation: {id, required_posting_auths}}) {
- if(id === 'follow') {
- const follower = required_posting_auths[0]
- yield put(g.actions.update({
- key: ['follow', 'getFollowingAsync', follower, 'loading'],
- updater: () => null
- }))
+function* error_custom_json({ operation: { id, required_posting_auths } }) {
+ if (id === 'follow') {
+ const follower = required_posting_auths[0];
+ yield put(
+ globalActions.update({
+ key: ['follow', 'getFollowingAsync', follower, 'loading'],
+ updater: () => null,
+ })
+ );
}
}
-function* error_vote({operation: {author, permlink}}) {
- yield put(g.actions.remove({key: `transaction_vote_active_${author}_${permlink}`}));
- yield call(getContent, {author, permlink}); // unvote
+function* error_vote({ operation: { author, permlink } }) {
+ yield put(
+ globalActions.remove({
+ key: `transaction_vote_active_${author}_${permlink}`,
+ })
+ );
+ yield call(getContent, { author, permlink }); // unvote
}
// function* error_comment({operation}) {
@@ -476,7 +656,7 @@ function* error_vote({operation: {author, permlink}}) {
// }
function slug(text) {
- return getSlug(text.replace(/[<>]/g, ''), {truncate: 128})
+ return getSlug(text.replace(/[<>]/g, ''), { truncate: 128 });
//const shorten = txt => {
// let t = ''
// let words = 0
@@ -507,127 +687,190 @@ function slug(text) {
// .toLowerCase()
}
-const pwPubkey = (name, pw, role) => auth.wifToPublic(auth.toWif(name, pw.trim(), role))
-
-function* recoverAccount({payload: {account_to_recover, old_password, new_password, onError, onSuccess}}) {
- const [account] = yield call([api, api.getAccountsAsync], [account_to_recover])
- if(!account) {
- onError('Unknown account ' + account)
- return
+const pwPubkey = (name, pw, role) =>
+ auth.wifToPublic(auth.toWif(name, pw.trim(), role));
+
+function* recoverAccount({
+ payload: {
+ account_to_recover,
+ old_password,
+ new_password,
+ onError,
+ onSuccess,
+ },
+}) {
+ const [account] = yield call(
+ [api, api.getAccountsAsync],
+ [account_to_recover]
+ );
+ if (!account) {
+ onError('Unknown account ' + account);
+ return;
}
- if(auth.isWif(new_password)) {
- onError('Your new password should not be a WIF')
- return
+ if (auth.isWif(new_password)) {
+ onError('Your new password should not be a WIF');
+ return;
}
- if(auth.isPubkey(new_password)) {
- onError('Your new password should not be a Public Key')
- return
+ if (auth.isPubkey(new_password)) {
+ onError('Your new password should not be a Public Key');
+ return;
}
- const oldOwnerPrivate = auth.isWif(old_password) ? old_password :
- auth.toWif(account_to_recover, old_password, 'owner')
-
- const oldOwner = auth.wifToPublic(oldOwnerPrivate)
-
- const newOwnerPrivate = auth.toWif(account_to_recover, new_password.trim(), 'owner')
- const newOwner = auth.wifToPublic(newOwnerPrivate)
- const newActive = pwPubkey(account_to_recover, new_password.trim(), 'active')
- const newPosting = pwPubkey(account_to_recover, new_password.trim(), 'posting')
- const newMemo = pwPubkey(account_to_recover, new_password.trim(), 'memo')
-
- const new_owner_authority = {weight_threshold: 1, account_auths: [],
- key_auths: [[newOwner, 1]]}
-
- const recent_owner_authority = {weight_threshold: 1, account_auths: [],
- key_auths: [[oldOwner, 1]]}
+ const oldOwnerPrivate = auth.isWif(old_password)
+ ? old_password
+ : auth.toWif(account_to_recover, old_password, 'owner');
+
+ const oldOwner = auth.wifToPublic(oldOwnerPrivate);
+
+ const newOwnerPrivate = auth.toWif(
+ account_to_recover,
+ new_password.trim(),
+ 'owner'
+ );
+ const newOwner = auth.wifToPublic(newOwnerPrivate);
+ const newActive = pwPubkey(
+ account_to_recover,
+ new_password.trim(),
+ 'active'
+ );
+ const newPosting = pwPubkey(
+ account_to_recover,
+ new_password.trim(),
+ 'posting'
+ );
+ const newMemo = pwPubkey(account_to_recover, new_password.trim(), 'memo');
+
+ const new_owner_authority = {
+ weight_threshold: 1,
+ account_auths: [],
+ key_auths: [[newOwner, 1]],
+ };
+
+ const recent_owner_authority = {
+ weight_threshold: 1,
+ account_auths: [],
+ key_auths: [[oldOwner, 1]],
+ };
try {
- yield broadcast.sendAsync({extensions: [], operations: [
- ['recover_account', {
- account_to_recover,
- new_owner_authority,
- recent_owner_authority,
- }]
- ]}, [oldOwnerPrivate, newOwnerPrivate])
+ yield broadcast.sendAsync(
+ {
+ extensions: [],
+ operations: [
+ [
+ 'recover_account',
+ {
+ account_to_recover,
+ new_owner_authority,
+ recent_owner_authority,
+ },
+ ],
+ ],
+ },
+ [oldOwnerPrivate, newOwnerPrivate]
+ );
// change password
// change password probably requires a separate transaction (single trx has not been tested)
- const {json_metadata} = account
- yield broadcast.sendAsync({extensions: [], operations: [
- ['account_update', {
- account: account.name,
- active: {weight_threshold: 1, account_auths: [], key_auths: [[newActive, 1]]},
- posting: {weight_threshold: 1, account_auths: [], key_auths: [[newPosting, 1]]},
- memo_key: newMemo,
- json_metadata,
- }]
- ]}, [newOwnerPrivate])
- if(onSuccess) onSuccess()
- } catch(error) {
- console.error('Recover account', error)
- if(onError) onError(error)
+ const { json_metadata } = account;
+ yield broadcast.sendAsync(
+ {
+ extensions: [],
+ operations: [
+ [
+ 'account_update',
+ {
+ account: account.name,
+ active: {
+ weight_threshold: 1,
+ account_auths: [],
+ key_auths: [[newActive, 1]],
+ },
+ posting: {
+ weight_threshold: 1,
+ account_auths: [],
+ key_auths: [[newPosting, 1]],
+ },
+ memo_key: newMemo,
+ json_metadata,
+ },
+ ],
+ ],
+ },
+ [newOwnerPrivate]
+ );
+ if (onSuccess) onSuccess();
+ } catch (error) {
+ console.error('Recover account', error);
+ if (onError) onError(error);
}
}
/** auths must start with most powerful key: owner for example */
// const twofaAccount = 'steem'
-function* updateAuthorities({payload: {accountName, signingKey, auths, twofa, onSuccess, onError}}) {
+function* updateAuthorities({
+ payload: { accountName, signingKey, auths, twofa, onSuccess, onError },
+}) {
// Be sure this account is up-to-date (other required fields are sent in the update)
- const [account] = yield call([api, api.getAccountsAsync], [accountName])
+ const [account] = yield call([api, api.getAccountsAsync], [accountName]);
if (!account) {
- onError('Account not found')
- return
+ onError('Account not found');
+ return;
}
// const signingPubkey = signingKey ? signingKey.toPublicKey() : null
- const ops2 = {}
- let oldPrivate
+ const ops2 = {};
+ let oldPrivate;
const addAuth = (authType, oldAuth, newAuth) => {
- let oldAuthPubkey, oldPrivateAuth
+ let oldAuthPubkey, oldPrivateAuth;
try {
- oldPrivateAuth = PrivateKey.fromWif(oldAuth)
- oldAuthPubkey = oldPrivateAuth.toPublic().toString()
- } catch(e) {
+ oldPrivateAuth = PrivateKey.fromWif(oldAuth);
+ oldAuthPubkey = oldPrivateAuth.toPublic().toString();
+ } catch (e) {
try {
- oldAuthPubkey = PublicKey.fromStringOrThrow(oldAuth).toString()
- } catch(e2) {
+ oldAuthPubkey = PublicKey.fromStringOrThrow(oldAuth).toString();
+ } catch (e2) {
//
}
}
- if(!oldAuthPubkey) {
- if(!oldAuth) {
- onError('Missing old key, not sure what to replace')
- console.error('Missing old key, not sure what to replace')
- return false
+ if (!oldAuthPubkey) {
+ if (!oldAuth) {
+ onError('Missing old key, not sure what to replace');
+ console.error('Missing old key, not sure what to replace');
+ return false;
}
- oldPrivateAuth = PrivateKey.fromSeed(accountName + authType + oldAuth)
- oldAuthPubkey = oldPrivateAuth.toPublicKey().toString()
+ oldPrivateAuth = PrivateKey.fromSeed(
+ accountName + authType + oldAuth
+ );
+ oldAuthPubkey = oldPrivateAuth.toPublicKey().toString();
}
- if(authType === 'owner' && !oldPrivate)
- oldPrivate = oldPrivateAuth
- else if(authType === 'active' && !oldPrivate)
- oldPrivate = oldPrivateAuth
- else if(authType === 'posting' && !oldPrivate)
- oldPrivate = oldPrivateAuth
-
- let newPrivate, newAuthPubkey
+ if (authType === 'owner' && !oldPrivate) oldPrivate = oldPrivateAuth;
+ else if (authType === 'active' && !oldPrivate)
+ oldPrivate = oldPrivateAuth;
+ else if (authType === 'posting' && !oldPrivate)
+ oldPrivate = oldPrivateAuth;
+
+ let newPrivate, newAuthPubkey;
try {
- newPrivate = PrivateKey.fromWif(newAuth)
- newAuthPubkey = newPrivate.toPublicKey().toString()
+ newPrivate = PrivateKey.fromWif(newAuth);
+ newAuthPubkey = newPrivate.toPublicKey().toString();
} catch (e) {
- newPrivate = PrivateKey.fromSeed(accountName + authType + newAuth)
- newAuthPubkey = newPrivate.toPublicKey().toString()
+ newPrivate = PrivateKey.fromSeed(accountName + authType + newAuth);
+ newAuthPubkey = newPrivate.toPublicKey().toString();
}
// if (oldAuthPubkey === newAuthPubkey) {
// onError('This is the same key')
// return false
// }
- let authority
+ let authority;
if (authType === 'memo') {
- account.memo_key = newAuthPubkey
+ account.memo_key = newAuthPubkey;
} else {
- authority = fromJS(account[authType]).toJS()
- authority.key_auths = []
- authority.key_auths.push([newAuthPubkey, authority.weight_threshold])
+ authority = fromJS(account[authType]).toJS();
+ authority.key_auths = [];
+ authority.key_auths.push([
+ newAuthPubkey,
+ authority.weight_threshold,
+ ]);
// const key_auths = authority.key_auths
// let found
// for (let i = 0; i < key_auths.length; i++) {
@@ -638,7 +881,7 @@ function* updateAuthorities({payload: {accountName, signingKey, auths, twofa, on
// }
// }
// if (!found) {
- // key_auths.push([newAuthPubkey, authority.weight_threshold])
+ // key_auths.push([newAuthPubkey, authority.weight_threshold])
// console.log(`Could not find an ${authType} key to update, adding instead`)
// }
@@ -651,83 +894,97 @@ function* updateAuthorities({payload: {accountName, signingKey, auths, twofa, on
// authority.account_auths = account_auths.toJS()
// }
}
- ops2[authType] = authority ? authority : account[authType]
- return true
- }
- for(const auth of auths)
- if(!addAuth(auth.authType, auth.oldAuth, auth.newAuth))
- return
+ ops2[authType] = authority ? authority : account[authType];
+ return true;
+ };
+ for (const auth of auths)
+ if (!addAuth(auth.authType, auth.oldAuth, auth.newAuth)) return;
- let key = oldPrivate
- if(!key) {
+ let key = oldPrivate;
+ if (!key) {
try {
- key = PrivateKey.fromWif(signingKey)
- } catch(e2) {
+ key = PrivateKey.fromWif(signingKey);
+ } catch (e2) {
// probably updating a memo .. see if we got an active or owner
- const auth = (authType) => {
- const priv = PrivateKey.fromSeed(accountName + authType + signingKey)
- const pubkey = priv.toPublicKey().toString()
- const authority = account[authType]
- const key_auths = authority.key_auths
+ const auth = authType => {
+ const priv = PrivateKey.fromSeed(
+ accountName + authType + signingKey
+ );
+ const pubkey = priv.toPublicKey().toString();
+ const authority = account[authType];
+ const key_auths = authority.key_auths;
for (let i = 0; i < key_auths.length; i++) {
if (key_auths[i][0] === pubkey) {
- return priv
+ return priv;
}
}
- return null
- }
- key = auth('active')
- if(!key) key = auth('owner')
+ return null;
+ };
+ key = auth('active');
+ if (!key) key = auth('owner');
}
}
if (!key) {
- onError(`Incorrect Password`)
- throw new Error('Trying to update a memo without a signing key?')
+ onError(`Incorrect Password`);
+ throw new Error('Trying to update a memo without a signing key?');
}
- const {memo_key, json_metadata} = account
+ const { memo_key, json_metadata } = account;
const payload = {
- type: 'account_update', operation: {
- account: account.name, ...ops2,
- memo_key, json_metadata,
- }, keys: [key],
+ type: 'account_update',
+ operation: {
+ account: account.name,
+ ...ops2,
+ memo_key,
+ json_metadata,
+ },
+ keys: [key],
successCallback: onSuccess,
errorCallback: onError,
- }
+ };
// console.log('sign key.toPublicKey().toString()', key.toPublicKey().toString())
// console.log('payload', payload)
- yield call(broadcastOperation, {payload})
+ yield call(broadcastOperation, { payload });
}
/** auths must start with most powerful key: owner for example */
// const twofaAccount = 'steem'
function* updateMeta(params) {
// console.log('params', params)
- const {meta, account_name, signingKey, onSuccess, onError} = params.payload.operation
- console.log('meta', meta)
- console.log('account_name', account_name)
+ const {
+ meta,
+ account_name,
+ signingKey,
+ onSuccess,
+ onError,
+ } = params.payload.operation;
+ console.log('meta', meta);
+ console.log('account_name', account_name);
// Be sure this account is up-to-date (other required fields are sent in the update)
- const [account] = yield call([api, api.getAccountsAsync], [account_name])
+ const [account] = yield call([api, api.getAccountsAsync], [account_name]);
if (!account) {
- onError('Account not found')
- return
+ onError('Account not found');
+ return;
}
if (!signingKey) {
- onError(`Incorrect Password`)
- throw new Error('Have to pass owner key in order to change meta')
+ onError(`Incorrect Password`);
+ throw new Error('Have to pass owner key in order to change meta');
}
try {
- console.log('account.name', account.name)
- const operations = ['update_account_meta', {
- account_name: account.name,
- json_meta: JSON.stringify(meta),
- }]
- yield broadcast.sendAsync({extensions: [], operations}, [signingKey])
- if(onSuccess) onSuccess()
- // console.log('sign key.toPublicKey().toString()', key.toPublicKey().toString())
- // console.log('payload', payload)
- } catch(e) {
- console.error('Update meta', e)
- if(onError) onError(e)
+ console.log('account.name', account.name);
+ const operations = [
+ 'update_account_meta',
+ {
+ account_name: account.name,
+ json_meta: JSON.stringify(meta),
+ },
+ ];
+ yield broadcast.sendAsync({ extensions: [], operations }, [signingKey]);
+ if (onSuccess) onSuccess();
+ // console.log('sign key.toPublicKey().toString()', key.toPublicKey().toString())
+ // console.log('payload', payload)
+ } catch (e) {
+ console.error('Update meta', e);
+ if (onError) onError(e);
}
}
diff --git a/src/app/redux/TransactionSaga.test.js b/src/app/redux/TransactionSaga.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..1886da163e13d7adb8128b0e7f6b5e2c1c9a0750
--- /dev/null
+++ b/src/app/redux/TransactionSaga.test.js
@@ -0,0 +1,267 @@
+/* global describe, it, before, beforeEach, after, afterEach */
+
+import { call, select } from 'redux-saga/effects';
+import { api } from '@steemit/steem-js';
+import {
+ preBroadcast_comment,
+ createPermlink,
+ createPatch,
+ watchForBroadcast,
+ watchForUpdateAuthorities,
+ watchForUpdateMeta,
+ watchForRecoverAccount,
+ preBroadcast_transfer,
+} from './TransactionSaga';
+import { DEBT_TICKER } from 'app/client_config';
+
+import { configure, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-15';
+
+configure({ adapter: new Adapter() });
+
+const operation = {
+ type: 'comment',
+ author: 'Alice',
+ body:
+ "The Body is a pretty long chunck of text that represents the user's voice, it seems they have much to say, and this is one place where they can do that.",
+ category: 'hi',
+ json_metadata: {
+ tags: ['hi'],
+ app: 'steemit/0.1',
+ format: 'markdown',
+ },
+ parent_author: 'candide',
+ parent_permlink: 'cool',
+ title: 'test',
+ __config: {},
+ errorCallback: () => '',
+ successCallback: () => '',
+ memo: '#testing',
+};
+
+const username = 'Beatrice';
+
+describe('TransactionSaga', () => {
+ describe('createPatch', () => {
+ it('should return undefined if empty arguments are passed', () => {
+ const actual = createPatch('', '');
+ expect(actual).toEqual(undefined);
+ });
+ it('should return the patch that reconciles two different strings', () => {
+ const testString =
+ 'there is something interesting going on here that I do not fully understand it is seemingly complex but it is actually quite simple';
+ const actual = createPatch(testString, testString + 'ILU');
+ expect(actual).toEqual(
+ '@@ -120,12 +120,15 @@\n quite simple\n+ILU\n'
+ );
+ });
+ });
+
+ describe('watchForBroadcast', () => {
+ const gen = watchForBroadcast();
+ it('should call takeEvery with BROADCAST_OPERATION', () => {
+ const actual = gen.next().value;
+ const expected = {
+ '@@redux-saga/IO': true,
+ TAKE: 'transaction/BROADCAST_OPERATION',
+ };
+ expect(actual).toEqual(expected);
+ });
+ });
+
+ describe('watchForUpdateAuthorities', () => {
+ const gen = watchForUpdateAuthorities();
+ it('should call takeEvery with UPDATE_AUTHORITIES', () => {
+ const actual = gen.next().value;
+ const expected = {
+ '@@redux-saga/IO': true,
+ TAKE: 'transaction/UPDATE_AUTHORITIES',
+ };
+ expect(actual).toEqual(expected);
+ });
+ });
+
+ describe('watchForUpdateMeta', () => {
+ const gen = watchForUpdateMeta();
+ it('should call takeEvery with UPDATE_META', () => {
+ const actual = gen.next().value;
+ const expected = {
+ '@@redux-saga/IO': true,
+ TAKE: 'transaction/UPDATE_META',
+ };
+ expect(actual).toEqual(expected);
+ });
+ });
+
+ describe('preBroadcast_transfer', () => {
+ const operationSansMemo = {
+ ...operation,
+ memo: undefined,
+ };
+ const arg = { operation: operationSansMemo };
+ it('should return select object if it has a memo attribute with string value starting with #', () => {
+ const genR = preBroadcast_transfer({ operation });
+ const actual = genR.next().value;
+ const expected = select(state =>
+ state.user.getIn(['current', 'private_keys', 'memo_private'])
+ );
+ expect(Object.keys(actual)).toEqual(['@@redux-saga/IO', 'SELECT']);
+ });
+ it('should return the operation unchanged if it has no memo attribute', () => {
+ let gen = preBroadcast_transfer(arg);
+ const actual = gen.next().value;
+ expect(actual).toEqual(operationSansMemo);
+ });
+ });
+
+ describe('createPermlink', () => {
+ const gen = createPermlink(
+ operation.title,
+ operation.author,
+ operation.parent_author,
+ operation.parent_permlink
+ );
+ it('should call the api to get a permlink if the title is valid', () => {
+ const actual = gen.next().value;
+ const mockCall = call(
+ [api, api.getContentAsync],
+ operation.author,
+ operation.title
+ );
+ expect(actual).toEqual(mockCall);
+ });
+ it('should return a string containing the transformed data from the api', () => {
+ const permlink = gen.next({ body: 'test' }).value;
+ expect(permlink.indexOf('test') > -1).toEqual(true); // TODO: cannot deep equal due to date stamp at runtime.
+ });
+ it('should generate own permlink, independent of api if title is empty', () => {
+ const gen2 = createPermlink(
+ '',
+ operation.author,
+ operation.parent_author,
+ operation.parent_permlink
+ );
+ const actual = gen2.next().value;
+ expect(
+ actual.indexOf(
+ `re-${operation.parent_author}-${
+ operation.parent_permlink
+ }-`
+ ) > -1
+ ).toEqual(true); // TODO: cannot deep equal due to random hash at runtime.
+ });
+ });
+
+ describe('preBroadcast_comment', () => {
+ let gen = preBroadcast_comment({ operation, username });
+
+ it('should call createPermlink', () => {
+ const permlink = gen.next(
+ operation.title,
+ operation.author,
+ operation.parent_author,
+ operation.parent_permlink
+ ).value;
+ const actual = permlink.next().value;
+ const expected = call(
+ [api, api.getContentAsync],
+ operation.author,
+ operation.title
+ );
+ expect(expected).toEqual(actual);
+ });
+ it('should return the comment options array.', () => {
+ let actual = gen.next('mock-permlink-123').value;
+ const expected = [
+ [
+ 'comment',
+ {
+ author: operation.author,
+ category: operation.category,
+ errorCallback: operation.errorCallback,
+ successCallback: operation.successCallback,
+ parent_author: operation.parent_author,
+ parent_permlink: operation.parent_permlink,
+ type: operation.type,
+ __config: operation.__config,
+ memo: operation.memo,
+ permlink: 'mock-permlink-123',
+ json_metadata: JSON.stringify(operation.json_metadata),
+ title: new Buffer(
+ (operation.title || '').trim(),
+ 'utf-8'
+ ),
+ body: new Buffer(operation.body, 'utf-8'), // TODO: new Buffer is deprecated, prefer Buffer.from()
+ },
+ ],
+ ];
+ expect(actual).toEqual(expected);
+ });
+ it('should return a patch as body value if patch is smaller than body.', () => {
+ const originalBod = operation.body + 'minor difference';
+ operation.__config.originalBody = originalBod;
+ gen = preBroadcast_comment({ operation, username });
+ gen.next(
+ operation.title,
+ operation.author,
+ operation.parent_author,
+ operation.parent_permlink
+ );
+ const actual = gen.next('mock-permlink-123').value;
+ const expected = Buffer.from(
+ createPatch(originalBod, operation.body),
+ 'utf-8'
+ );
+ expect(actual[0][1].body).toEqual(expected);
+ });
+ it('should return body as body value if patch is larger than body.', () => {
+ const originalBod = 'major difference';
+ operation.__config.originalBody = originalBod;
+ gen = preBroadcast_comment({ operation, username });
+ gen.next(
+ operation.title,
+ operation.author,
+ operation.parent_author,
+ operation.parent_permlink
+ );
+ const actual = gen.next('mock-permlink-123').value;
+ const expected = Buffer.from(operation.body, 'utf-8');
+ expect(actual[0][1].body).toEqual(expected, 'utf-8');
+ });
+ it('should include comment_options and autoVote if specified.', () => {
+ operation.__config.comment_options = true;
+ operation.__config.autoVote = true;
+ gen = preBroadcast_comment({ operation, username });
+ gen.next(
+ operation.title,
+ operation.author,
+ operation.parent_author,
+ operation.parent_permlink
+ );
+ const actual = gen.next('mock-permlink-123').value;
+ const expectedCommentOptions = [
+ 'comment_options',
+ {
+ author: operation.author,
+ permlink: 'mock-permlink-123',
+ max_accepted_payout: ['1000000.000', DEBT_TICKER].join(' '),
+ percent_steem_dollars: 10000,
+ allow_votes: true,
+ allow_curation_rewards: true,
+ extensions: [],
+ },
+ ];
+ const expectedAutoVoteOptions = [
+ 'vote',
+ {
+ voter: operation.author,
+ author: operation.author,
+ permlink: 'mock-permlink-123',
+ weight: 10000,
+ },
+ ];
+ expect(actual[1]).toEqual(expectedCommentOptions);
+ expect(actual[2]).toEqual(expectedAutoVoteOptions);
+ });
+ });
+});
diff --git a/src/app/redux/User.js b/src/app/redux/User.js
deleted file mode 100644
index 6e84ee16f1c4fbf4abc3395a234c15bd6762d441..0000000000000000000000000000000000000000
--- a/src/app/redux/User.js
+++ /dev/null
@@ -1,155 +0,0 @@
-import {fromJS} from 'immutable';
-import createModule from 'redux-modules';
-import { DEFAULT_LANGUAGE } from 'app/client_config';
-import store from 'store';
-
-const defaultState = fromJS({
- current: null,
- show_login_modal: false,
- show_transfer_modal: false,
- show_powerdown_modal: false,
- show_promote_post_modal: false,
- show_signup_modal: false,
- pub_keys_used: null,
- locale: DEFAULT_LANGUAGE,
-});
-
-if (process.env.BROWSER) {
- const locale = store.get('language');
- if (locale) defaultState.locale = locale;
-}
-
-export default createModule({
- name: 'user',
- initialState: defaultState,
- transformations: [
- {
- action: 'SHOW_LOGIN',
- reducer: (state, {payload}) => {
- // https://github.com/mboperator/redux-modules/issues/11
- if (typeof payload === 'function') payload = undefined;
- let operation, loginDefault
- if(payload) {
- operation = fromJS(payload.operation)
- loginDefault = fromJS(payload.loginDefault)
- }
- return state.merge({show_login_modal: true, loginBroadcastOperation: operation, loginDefault})
- }
- },
- {
- action: 'SHOW_TERMS',
- reducer: (state, {payload}) => {
- // https://github.com/mboperator/redux-modules/issues/11
- if (typeof payload === 'function') payload = undefined;
- let operation, termsDefault;
- if(payload) {
- operation = fromJS(payload.operation);
- termsDefault = fromJS(payload.termsDefault)
- }
- return state.merge({show_terms_modal: true, loginBroadcastOperation: operation, termsDefault})
- }
- },
- { action: 'HIDE_LOGIN', reducer: state =>
- state.merge({show_login_modal: false, loginBroadcastOperation: undefined, loginDefault: undefined}) },
- { action: 'SAVE_LOGIN_CONFIRM', reducer: (state, {payload}) => state.set('saveLoginConfirm', payload) },
- { action: 'SAVE_LOGIN', reducer: (state) => state }, // Use only for low security keys (like posting only keys)
- { action: 'REMOVE_HIGH_SECURITY_KEYS', reducer: (state) => {
- if(!state.hasIn(['current', 'private_keys'])) return state
- let empty = false
- state = state.updateIn(['current', 'private_keys'], private_keys => {
- if(!private_keys) return null
- if(private_keys.has('active_private'))
- console.log('removeHighSecurityKeys')
- private_keys = private_keys.delete('active_private')
- empty = private_keys.size === 0
- return private_keys
- })
- if(empty) {
- // User logged in with Active key then navigates away from the page
- // LOGOUT
- return defaultState.merge({logged_out: true})
- }
- const username = state.getIn(['current', 'username'])
- state = state.setIn(['authority', username, 'active'], 'none')
- state = state.setIn(['authority', username, 'owner'], 'none')
- return state
- }},
- { action: 'CHANGE_LANGUAGE', reducer: (state, {payload}) => {
- return state.set('locale', payload)}
- },
- { action: 'SHOW_TRANSFER', reducer: state => state.set('show_transfer_modal', true) },
- { action: 'HIDE_TRANSFER', reducer: state => state.set('show_transfer_modal', false) },
- { action: 'SHOW_POWERDOWN', reducer: state => state.set('show_powerdown_modal', true) },
- { action: 'HIDE_POWERDOWN', reducer: state => state.set('show_powerdown_modal', false) },
- { action: 'SHOW_PROMOTE_POST', reducer: state => state.set('show_promote_post_modal', true) },
- { action: 'HIDE_PROMOTE_POST', reducer: state => state.set('show_promote_post_modal', false) },
- { action: 'SET_TRANSFER_DEFAULTS', reducer: (state, {payload}) => state.set('transfer_defaults', fromJS(payload)) },
- { action: 'CLEAR_TRANSFER_DEFAULTS', reducer: (state) => state.remove('transfer_defaults') },
- { action: 'SET_POWERDOWN_DEFAULTS', reducer: (state, {payload}) => state.set('powerdown_defaults', fromJS(payload)) },
- { action: 'CLEAR_POWERDOWN_DEFAULTS', reducer: (state) => state.remove('powerdown_defaults') },
- {
- action: 'USERNAME_PASSWORD_LOGIN',
- reducer: state => state, // saga
- },
- {
- action: 'SET_USER',
- reducer: (state, {payload}) => {
- // console.log('SET_USER')
- if (payload.vesting_shares) payload.vesting_shares = parseFloat(payload.vesting_shares);
- if (payload.delegated_vesting_shares) payload.delegated_vesting_shares = parseFloat(payload.delegated_vesting_shares);
- if (payload.received_vesting_shares) payload.received_vesting_shares = parseFloat(payload.received_vesting_shares);
- return state.mergeDeep({ current: payload, show_login_modal: false, loginBroadcastOperation: undefined, loginDefault: undefined, logged_out: undefined })
- }
- },
- {
- action: 'CLOSE_LOGIN',
- reducer: (state) => state.merge({ login_error: undefined, show_login_modal: false, loginBroadcastOperation: undefined, loginDefault: undefined })
- },
- {
- action: 'LOGIN_ERROR',
- reducer: (state, {payload: {error}}) => state.merge({ login_error: error, logged_out: undefined })
- },
- {
- action: 'LOGOUT',
- reducer: () => {
- return defaultState.merge({logged_out: true})
- }
- },
- // {
- // action: 'ACCEPTED_COMMENT',
- // // User can only post 1 comment per minute
- // reducer: (state) => state.merge({ current: {lastComment: Date.now()} })
- // },
- { action: 'SHOW_SIGN_UP', reducer: state => state.set('show_signup_modal', true) },
- { action: 'HIDE_SIGN_UP', reducer: state => state.set('show_signup_modal', false) },
-
- {
- action: 'KEYS_ERROR',
- reducer: (state, {payload: {error}}) => state.merge({ keys_error: error })
- },
- // { action: 'UPDATE_PERMISSIONS', reducer: state => {
- // return state // saga
- // }},
- { // AuthSaga
- action: 'ACCOUNT_AUTH_LOOKUP',
- reducer: state => state
- },
- { // AuthSaga
- action: 'SET_AUTHORITY',
- reducer: (state, {payload: {accountName, auth, pub_keys_used}}) => {
- state = state.setIn(['authority', accountName], fromJS(auth))
- if(pub_keys_used)
- state = state.set('pub_keys_used', pub_keys_used)
- return state
- },
- },
- { action: 'HIDE_CONNECTION_ERROR_MODAL', reducer: state => state.set('hide_connection_error_modal', true) },
- {
- action: 'SET',
- reducer: (state, {payload: {key, value}}) => {
- key = Array.isArray(key) ? key : [key]
- return state.setIn(key, fromJS(value))
- }
- },
- ]
-});
diff --git a/src/app/redux/UserActions.js b/src/app/redux/UserActions.js
deleted file mode 100644
index bfae60e68a8f94ef5de6fa287a8fdf00ff56ee47..0000000000000000000000000000000000000000
--- a/src/app/redux/UserActions.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// export function setUser(user) {
-// return {
-// type: 'SET_USER',
-// username: user ? user.name : null
-// };
-// }
diff --git a/src/app/redux/UserReducer.js b/src/app/redux/UserReducer.js
new file mode 100644
index 0000000000000000000000000000000000000000..0db1f3246e957f75bd2e97d5f0ce085e307df063
--- /dev/null
+++ b/src/app/redux/UserReducer.js
@@ -0,0 +1,416 @@
+import { fromJS } from 'immutable';
+import { DEFAULT_LANGUAGE } from 'app/client_config';
+import store from 'store';
+
+// Action constants
+const SHOW_LOGIN = 'user/SHOW_LOGIN';
+const HIDE_LOGIN = 'user/HIDE_LOGIN';
+const SHOW_TERMS = 'user/SHOW_TERMS';
+const HIDE_TERMS = 'user/HIDE_TERMS';
+export const SAVE_LOGIN_CONFIRM = 'user/SAVE_LOGIN_CONFIRM';
+export const SAVE_LOGIN = 'user/SAVE_LOGIN';
+const REMOVE_HIGH_SECURITY_KEYS = 'user/REMOVE_HIGH_SECURITY_KEYS';
+const CHANGE_LANGUAGE = 'user/CHANGE_LANGUAGE';
+const SHOW_TRANSFER = 'user/SHOW_TRANSFER';
+const HIDE_TRANSFER = 'user/HIDE_TRANSFER';
+const SHOW_POWERDOWN = 'user/SHOW_POWERDOWN';
+const HIDE_POWERDOWN = 'user/HIDE_POWERDOWN';
+const SHOW_PROMOTE_POST = 'user/SHOW_PROMOTE_POST';
+const HIDE_PROMOTE_POST = 'user/HIDE_PROMOTE_POST';
+const SET_TRANSFER_DEFAULTS = 'user/SET_TRANSFER_DEFAULTS';
+const CLEAR_TRANSFER_DEFAULTS = 'user/CLEAR_TRANSFER_DEFAULTS';
+const SET_POWERDOWN_DEFAULTS = 'user/SET_POWERDOWN_DEFAULTS';
+const CLEAR_POWERDOWN_DEFAULTS = 'user/CLEAR_POWERDOWN_DEFAULTS';
+export const USERNAME_PASSWORD_LOGIN = 'user/USERNAME_PASSWORD_LOGIN';
+export const SET_USER = 'user/SET_USER';
+const CLOSE_LOGIN = 'user/CLOSE_LOGIN';
+export const LOGIN_ERROR = 'user/LOGIN_ERROR';
+export const LOGOUT = 'user/LOGOUT';
+const SHOW_SIGN_UP = 'user/SHOW_SIGN_UP';
+const HIDE_SIGN_UP = 'user/HIDE_SIGN_UP';
+const KEYS_ERROR = 'user/KEYS_ERROR';
+const ACCOUNT_AUTH_LOOKUP = 'user/ACCOUNT_AUTH_LOOKUP';
+const SET_AUTHORITY = 'user/SET_AUTHORITY';
+const HIDE_CONNECTION_ERROR_MODAL = 'user/HIDE_CONNECTION_ERROR_MODAL';
+const SET = 'user/SET';
+const SHOW_SIDE_PANEL = 'user/SHOW_SIDE_PANEL';
+const HIDE_SIDE_PANEL = 'user/HIDE_SIDE_PANEL';
+
+// Saga-related
+export const LOAD_SAVINGS_WITHDRAW = 'user/LOAD_SAVINGS_WITHDRAW';
+export const UPLOAD_IMAGE = 'user/UPLOAD_IMAGE';
+
+const defaultState = fromJS({
+ current: null,
+ show_login_modal: false,
+ show_transfer_modal: false,
+ show_promote_post_modal: false,
+ show_signup_modal: false,
+ pub_keys_used: null,
+ locale: DEFAULT_LANGUAGE,
+ show_side_panel: false,
+});
+
+if (process.env.BROWSER) {
+ const locale = store.get('language');
+ if (locale) defaultState.locale = locale;
+}
+
+export default function reducer(state = defaultState, action) {
+ const payload = action.payload;
+
+ switch (action.type) {
+ case SHOW_LOGIN: {
+ let operation, loginDefault;
+ if (payload) {
+ operation = fromJS(payload.operation);
+ loginDefault = fromJS(payload.loginDefault);
+ }
+ return state.merge({
+ show_login_modal: true,
+ loginBroadcastOperation: operation,
+ loginDefault,
+ });
+ }
+
+ case HIDE_LOGIN:
+ return state.merge({
+ show_login_modal: false,
+ loginBroadcastOperation: undefined,
+ loginDefault: undefined,
+ });
+
+ case SHOW_TERMS: {
+ let termsDefault;
+ if (payload) {
+ termsDefault = fromJS(payload.termsDefault);
+ }
+ return state.merge({
+ show_terms_modal: true,
+ termsDefault,
+ });
+ }
+
+ case HIDE_TERMS:
+ return state.merge({
+ show_terms_modal: false,
+ termsDefault: undefined,
+ });
+
+ case SAVE_LOGIN_CONFIRM:
+ return state.set('saveLoginConfirm', payload);
+
+ case SAVE_LOGIN:
+ // Use only for low security keys (like posting only keys)
+ return state;
+
+ case REMOVE_HIGH_SECURITY_KEYS: {
+ if (!state.hasIn(['current', 'private_keys'])) return state;
+ let empty = false;
+ state = state.updateIn(
+ ['current', 'private_keys'],
+ private_keys => {
+ if (!private_keys) return null;
+ if (private_keys.has('active_private'))
+ console.log('removeHighSecurityKeys');
+ private_keys = private_keys.delete('active_private');
+ empty = private_keys.size === 0;
+ return private_keys;
+ }
+ );
+ if (empty) {
+ // User logged in with Active key then navigates away from the page
+ // LOGOUT
+ return defaultState.merge({ logged_out: true });
+ }
+ const username = state.getIn(['current', 'username']);
+ state = state.setIn(['authority', username, 'active'], 'none');
+ state = state.setIn(['authority', username, 'owner'], 'none');
+ return state;
+ }
+
+ case CHANGE_LANGUAGE:
+ return state.set('locale', payload);
+
+ case SHOW_TRANSFER:
+ return state.set('show_transfer_modal', true);
+
+ case HIDE_TRANSFER:
+ return state.set('show_transfer_modal', false);
+
+ case SHOW_POWERDOWN:
+ return state.set('show_powerdown_modal', true);
+
+ case HIDE_POWERDOWN:
+ return state.set('show_powerdown_modal', false);
+
+ case SHOW_PROMOTE_POST:
+ return state.set('show_promote_post_modal', true);
+
+ case HIDE_PROMOTE_POST:
+ return state.set('show_promote_post_modal', false);
+
+ case SET_TRANSFER_DEFAULTS:
+ return state.set('transfer_defaults', fromJS(payload));
+
+ case CLEAR_TRANSFER_DEFAULTS:
+ return state.remove('transfer_defaults');
+
+ case SET_POWERDOWN_DEFAULTS:
+ return state.set('powerdown_defaults', fromJS(payload));
+
+ case CLEAR_POWERDOWN_DEFAULTS:
+ return state.remove('powerdown_defaults');
+
+ case USERNAME_PASSWORD_LOGIN:
+ case LOAD_SAVINGS_WITHDRAW:
+ return state; // saga
+
+ case SET_USER:
+ if (payload.vesting_shares)
+ payload.vesting_shares = parseFloat(payload.vesting_shares);
+ if (payload.delegated_vesting_shares)
+ payload.delegated_vesting_shares = parseFloat(
+ payload.delegated_vesting_shares
+ );
+ if (payload.received_vesting_shares)
+ payload.received_vesting_shares = parseFloat(
+ payload.received_vesting_shares
+ );
+ return state.mergeDeep({
+ current: payload,
+ show_login_modal: false,
+ loginBroadcastOperation: undefined,
+ loginDefault: undefined,
+ logged_out: undefined,
+ });
+
+ case CLOSE_LOGIN:
+ return state.merge({
+ login_error: undefined,
+ show_login_modal: false,
+ loginBroadcastOperation: undefined,
+ loginDefault: undefined,
+ });
+
+ case LOGIN_ERROR:
+ return state.merge({
+ login_error: payload.error,
+ logged_out: undefined,
+ });
+
+ case LOGOUT:
+ return defaultState.merge({ logged_out: true });
+
+ case SHOW_SIGN_UP:
+ return state.set('show_signup_modal', true);
+
+ case HIDE_SIGN_UP:
+ return state.set('show_signup_modal', false);
+
+ case KEYS_ERROR:
+ return state.merge({ keys_error: payload.error });
+
+ case ACCOUNT_AUTH_LOOKUP:
+ // AuthSaga
+ return state;
+
+ case SET_AUTHORITY: {
+ // AuthSaga
+ const { accountName, auth, pub_keys_used } = payload;
+ state = state.setIn(['authority', accountName], fromJS(auth));
+ if (pub_keys_used)
+ state = state.set('pub_keys_used', pub_keys_used);
+ return state;
+ }
+
+ case HIDE_CONNECTION_ERROR_MODAL:
+ return state.set('hide_connection_error_modal', true);
+
+ case SET:
+ return state.setIn(
+ Array.isArray(payload.key) ? payload.key : [payload.key],
+ fromJS(payload.value)
+ );
+
+ case SHOW_SIDE_PANEL:
+ return state.set('show_side_panel', true);
+
+ case HIDE_SIDE_PANEL:
+ return state.set('show_side_panel', false);
+
+ default:
+ return state;
+ }
+}
+
+// Action creators
+export const showLogin = payload => ({
+ type: SHOW_LOGIN,
+ payload,
+});
+
+export const hideLogin = payload => ({
+ type: HIDE_LOGIN,
+ payload,
+});
+
+export const showTerms = payload => ({
+ type: SHOW_TERMS,
+ payload,
+});
+
+export const hideTerms = payload => ({
+ type: HIDE_TERMS,
+ payload,
+});
+
+export const saveLoginConfirm = payload => ({
+ type: SAVE_LOGIN_CONFIRM,
+ payload,
+});
+
+export const saveLogin = payload => ({
+ type: SAVE_LOGIN,
+ payload,
+});
+
+export const removeHighSecurityKeys = payload => ({
+ type: REMOVE_HIGH_SECURITY_KEYS,
+ payload,
+});
+
+export const changeLanguage = payload => ({
+ type: CHANGE_LANGUAGE,
+ payload,
+});
+
+export const showTransfer = payload => ({
+ type: SHOW_TRANSFER,
+ payload,
+});
+
+export const hideTransfer = payload => ({
+ type: HIDE_TRANSFER,
+ payload,
+});
+
+export const showPowerdown = payload => ({
+ type: SHOW_POWERDOWN,
+ payload,
+});
+
+export const hidePowerdown = payload => ({
+ type: HIDE_POWERDOWN,
+ payload,
+});
+
+export const showPromotePost = payload => ({
+ type: SHOW_PROMOTE_POST,
+ payload,
+});
+
+export const hidePromotePost = payload => ({
+ type: HIDE_PROMOTE_POST,
+ payload,
+});
+
+export const setTransferDefaults = payload => ({
+ type: SET_TRANSFER_DEFAULTS,
+ payload,
+});
+
+export const clearTransferDefaults = payload => ({
+ type: CLEAR_TRANSFER_DEFAULTS,
+ payload,
+});
+
+export const setPowerdownDefaults = payload => ({
+ type: SET_POWERDOWN_DEFAULTS,
+ payload,
+});
+
+export const clearPowerdownDefaults = payload => ({
+ type: CLEAR_POWERDOWN_DEFAULTS,
+ payload,
+});
+
+export const usernamePasswordLogin = payload => ({
+ type: USERNAME_PASSWORD_LOGIN,
+ payload,
+});
+
+export const setUser = payload => ({
+ type: SET_USER,
+ payload,
+});
+
+export const closeLogin = payload => ({
+ type: CLOSE_LOGIN,
+ payload,
+});
+
+export const loginError = payload => ({
+ type: LOGIN_ERROR,
+ payload,
+});
+
+export const logout = payload => ({
+ type: LOGOUT,
+ payload,
+});
+
+export const showSignUp = payload => ({
+ type: SHOW_SIGN_UP,
+ payload,
+});
+
+export const hideSignUp = payload => ({
+ type: HIDE_SIGN_UP,
+ payload,
+});
+
+export const keysError = payload => ({
+ type: KEYS_ERROR,
+ payload,
+});
+
+export const accountAuthLookup = payload => ({
+ type: ACCOUNT_AUTH_LOOKUP,
+ payload,
+});
+
+export const setAuthority = payload => ({
+ type: SET_AUTHORITY,
+ payload,
+});
+
+export const hideConnectionErrorModal = payload => ({
+ type: HIDE_CONNECTION_ERROR_MODAL,
+ payload,
+});
+
+export const set = payload => ({
+ type: SET,
+ payload,
+});
+
+export const loadSavingsWithdraw = payload => ({
+ type: LOAD_SAVINGS_WITHDRAW,
+ payload,
+});
+
+export const uploadImage = payload => ({
+ type: UPLOAD_IMAGE,
+ payload,
+});
+
+export const showSidePanel = () => ({
+ type: SHOW_SIDE_PANEL,
+});
+
+export const hideSidePanel = () => {
+ return {
+ type: HIDE_SIDE_PANEL,
+ };
+};
diff --git a/src/app/redux/UserSaga.js b/src/app/redux/UserSaga.js
index 7a6dfc35abfd251466808573dc5a394573a219fe..b73fc5a9de0181c06e519803e1bd3f0b5d088756 100644
--- a/src/app/redux/UserSaga.js
+++ b/src/app/redux/UserSaga.js
@@ -1,19 +1,23 @@
-import {fromJS, Set, List} from 'immutable'
-import {takeLatest} from 'redux-saga';
-import {call, put, select, fork} from 'redux-saga/effects';
-import {accountAuthLookup} from 'app/redux/AuthSaga'
-import user from 'app/redux/User'
-import {getAccount} from 'app/redux/SagaShared'
-import {browserHistory} from 'react-router'
-import {serverApiLogin, serverApiLogout} from 'app/utils/ServerApiClient';
-import {serverApiRecordEvent} from 'app/utils/ServerApiClient';
-import {loadFollows} from 'app/redux/FollowSaga'
-import {PrivateKey, Signature, hash} from 'steem/lib/auth/ecc';
-import {api} from 'steem';
-import {translate} from 'app/Translator';
+import { fromJS, Set, List } from 'immutable';
+import { takeLatest } from 'redux-saga';
+import { call, put, select, fork } from 'redux-saga/effects';
+import { api } from '@steemit/steem-js';
+import { PrivateKey, Signature, hash } from '@steemit/steem-js/lib/auth/ecc';
+
+import { accountAuthLookup } from 'app/redux/AuthSaga';
+import { getAccount } from 'app/redux/SagaShared';
+import * as userActions from 'app/redux/UserReducer';
+import { receiveFeatureFlags } from 'app/redux/AppReducer';
+import { browserHistory } from 'react-router';
+import {
+ serverApiLogin,
+ serverApiLogout,
+ serverApiRecordEvent,
+} from 'app/utils/ServerApiClient';
+import { loadFollows } from 'app/redux/FollowSaga';
+import { translate } from 'app/Translator';
import DMCAUserList from 'app/utils/DMCAUserList';
-
export const userWatches = [
watchRemoveHighSecurityKeys, // keep first to remove keys early when a page change happens
loginWatch,
@@ -24,29 +28,39 @@ export const userWatches = [
lookupPreviousOwnerAuthorityWatch,
watchLoadSavingsWithdraw,
uploadImageWatch,
-]
+];
-const highSecurityPages = Array(/\/market/, /\/@.+\/(transfers|permissions|password)/, /\/~witnesses/)
+const highSecurityPages = [
+ /\/market/,
+ /\/@.+\/(transfers|permissions|password)/,
+ /\/~witnesses/,
+];
function* lookupPreviousOwnerAuthorityWatch() {
- yield* takeLatest('user/lookupPreviousOwnerAuthority', lookupPreviousOwnerAuthority);
+ yield* takeLatest(
+ 'user/lookupPreviousOwnerAuthority',
+ lookupPreviousOwnerAuthority
+ );
}
function* loginWatch() {
- yield* takeLatest('user/USERNAME_PASSWORD_LOGIN', usernamePasswordLogin);
+ yield* takeLatest(
+ userActions.USERNAME_PASSWORD_LOGIN,
+ usernamePasswordLogin
+ );
}
function* saveLoginWatch() {
- yield* takeLatest('user/SAVE_LOGIN', saveLogin_localStorage);
+ yield* takeLatest(userActions.SAVE_LOGIN, saveLogin_localStorage);
}
function* logoutWatch() {
- yield* takeLatest('user/LOGOUT', logout);
+ yield* takeLatest(userActions.LOGOUT, logout);
}
function* loginErrorWatch() {
- yield* takeLatest('user/LOGIN_ERROR', loginError);
+ yield* takeLatest(userActions.LOGIN_ERROR, loginError);
}
function* watchLoadSavingsWithdraw() {
- yield* takeLatest('user/LOAD_SAVINGS_WITHDRAW', loadSavingsWithdraw);
+ yield* takeLatest(userActions.LOAD_SAVINGS_WITHDRAW, loadSavingsWithdraw);
}
export function* watchRemoveHighSecurityKeys() {
@@ -54,37 +68,42 @@ export function* watchRemoveHighSecurityKeys() {
}
function* loadSavingsWithdraw() {
- const username = yield select(state => state.user.getIn(['current', 'username']))
- const to = yield call([api, api.getSavingsWithdrawToAsync], username)
- const fro = yield call([api, api.getSavingsWithdrawFromAsync], username)
-
- const m = {}
- for(const v of to) m[v.id] = v
- for(const v of fro) m[v.id] = v
-
- const withdraws = List(fromJS(m).values())
- .sort((a, b) => strCmp(a.get('complete'), b.get('complete')))
-
- yield put(user.actions.set({
- key: 'savings_withdraws',
- value: withdraws,
- }))
+ const username = yield select(state =>
+ state.user.getIn(['current', 'username'])
+ );
+ const to = yield call([api, api.getSavingsWithdrawToAsync], username);
+ const fro = yield call([api, api.getSavingsWithdrawFromAsync], username);
+
+ const m = {};
+ for (const v of to) m[v.id] = v;
+ for (const v of fro) m[v.id] = v;
+
+ const withdraws = List(fromJS(m).values()).sort((a, b) =>
+ strCmp(a.get('complete'), b.get('complete'))
+ );
+
+ yield put(
+ userActions.set({
+ key: 'savings_withdraws',
+ value: withdraws,
+ })
+ );
}
-const strCmp = (a, b) => a > b ? 1 : a < b ? -1 : 0
+const strCmp = (a, b) => (a > b ? 1 : a < b ? -1 : 0);
// function* getCurrentAccountWatch() {
// // yield* takeLatest('user/SHOW_TRANSFER', getCurrentAccount);
// }
-function* removeHighSecurityKeys({payload: {pathname}}) {
- const highSecurityPage = highSecurityPages.find(p => p.test(pathname)) != null
+function* removeHighSecurityKeys({ payload: { pathname } }) {
+ const highSecurityPage =
+ highSecurityPages.find(p => p.test(pathname)) != null;
// Let the user keep the active key when going from one high security page to another. This helps when
// the user logins into the Wallet then the Permissions tab appears (it was hidden). This keeps them
// from getting logged out when they click on Permissions (which is really bad because that tab
// disappears again).
- if(!highSecurityPage)
- yield put(user.actions.removeHighSecurityKeys())
+ if (!highSecurityPage) yield put(userActions.removeHighSecurityKeys());
}
/**
@@ -94,393 +113,504 @@ function* removeHighSecurityKeys({payload: {pathname}}) {
*/
function* usernamePasswordLogin(action) {
// Sets 'loading' while the login is taking place. The key generation can take a while on slow computers.
- yield call(usernamePasswordLogin2, action)
- const current = yield select(state => state.user.get('current'))
- if(current) {
- const username = current.get('username')
- yield fork(loadFollows, "getFollowingAsync", username, 'blog')
- yield fork(loadFollows, "getFollowingAsync", username, 'ignore')
+ yield call(usernamePasswordLogin2, action.payload);
+ const current = yield select(state => state.user.get('current'));
+ if (current) {
+ const username = current.get('username');
+ yield fork(loadFollows, 'getFollowingAsync', username, 'blog');
+ yield fork(loadFollows, 'getFollowingAsync', username, 'ignore');
}
}
// const isHighSecurityOperations = ['transfer', 'transfer_to_vesting', 'withdraw_vesting',
// 'limit_order_create', 'limit_order_cancel', 'account_update', 'account_witness_vote']
-
-const clean = (value) => value == null || value === '' || /null|undefined/.test(value) ? undefined : value
-
-function* usernamePasswordLogin2({payload: {username, password, saveLogin,
- operationType /*high security*/, afterLoginRedirectToWelcome
-}}) {
+const clean = value =>
+ value == null || value === '' || /null|undefined/.test(value)
+ ? undefined
+ : value;
+
+function* usernamePasswordLogin2({
+ username,
+ password,
+ saveLogin,
+ operationType /*high security*/,
+ afterLoginRedirectToWelcome,
+}) {
// login, using saved password
let feedURL = false;
- let autopost, memoWif, login_owner_pubkey, login_wif_owner_pubkey
+ let autopost, memoWif, login_owner_pubkey, login_wif_owner_pubkey;
if (!username && !password) {
- const data = localStorage.getItem('autopost2')
- if (data) { // auto-login with a low security key (like a posting key)
+ const data = localStorage.getItem('autopost2');
+ if (data) {
+ // auto-login with a low security key (like a posting key)
autopost = true; // must use simi-colon
// The 'password' in this case must be the posting private wif .. See setItme('autopost')
- [username, password, memoWif, login_owner_pubkey] = new Buffer(data, 'hex').toString().split('\t');
+ [username, password, memoWif, login_owner_pubkey] = new Buffer(
+ data,
+ 'hex'
+ )
+ .toString()
+ .split('\t');
memoWif = clean(memoWif);
login_owner_pubkey = clean(login_owner_pubkey);
}
}
// no saved password
if (!username || !password) {
- const offchain_account = yield select(state => state.offchain.get('account'))
- if (offchain_account) serverApiLogout()
- return
+ const offchain_account = yield select(state =>
+ state.offchain.get('account')
+ );
+ if (offchain_account) serverApiLogout();
+ return;
}
- let userProvidedRole // login via: username/owner
+ let userProvidedRole; // login via: username/owner
if (username.indexOf('/') > -1) {
// "alice/active" will login only with Alices active key
- [username, userProvidedRole] = username.split('/')
+ [username, userProvidedRole] = username.split('/');
}
- const pathname = yield select(state => state.global.get('pathname'))
+ const pathname = yield select(state => state.global.get('pathname'));
const highSecurityLogin =
// /owner|active/.test(userProvidedRole) ||
// isHighSecurityOperations.indexOf(operationType) !== -1 ||
- highSecurityPages.find(p => p.test(pathname)) != null
+ highSecurityPages.find(p => p.test(pathname)) != null;
- const isRole = (role, fn) => (!userProvidedRole || role === userProvidedRole ? fn() : undefined)
+ const isRole = (role, fn) =>
+ !userProvidedRole || role === userProvidedRole ? fn() : undefined;
- const account = yield call(getAccount, username)
+ const account = yield call(getAccount, username);
if (!account) {
- yield put(user.actions.loginError({ error: 'Username does not exist' }))
- return
+ yield put(userActions.loginError({ error: 'Username does not exist' }));
+ return;
}
//dmca user block
if (username && DMCAUserList.includes(username)) {
- yield put(user.actions.loginError({ error: translate('terms_violation') }))
- return
+ yield put(
+ userActions.loginError({ error: translate('terms_violation') })
+ );
+ return;
}
- let private_keys
+ let private_keys;
try {
- const private_key = PrivateKey.fromWif(password)
- login_wif_owner_pubkey = private_key.toPublicKey().toString()
+ const private_key = PrivateKey.fromWif(password);
+ login_wif_owner_pubkey = private_key.toPublicKey().toString();
private_keys = fromJS({
posting_private: isRole('posting', () => private_key),
active_private: isRole('active', () => private_key),
memo_private: private_key,
- })
+ });
} catch (e) {
// Password (non wif)
- login_owner_pubkey = PrivateKey.fromSeed(username + 'owner' + password).toPublicKey().toString()
+ login_owner_pubkey = PrivateKey.fromSeed(username + 'owner' + password)
+ .toPublicKey()
+ .toString();
private_keys = fromJS({
- posting_private: isRole('posting', () => PrivateKey.fromSeed(username + 'posting' + password)),
- active_private: isRole('active', () => PrivateKey.fromSeed(username + 'active' + password)),
+ posting_private: isRole('posting', () =>
+ PrivateKey.fromSeed(username + 'posting' + password)
+ ),
+ active_private: isRole('active', () =>
+ PrivateKey.fromSeed(username + 'active' + password)
+ ),
memo_private: PrivateKey.fromSeed(username + 'memo' + password),
- })
+ });
}
if (memoWif)
- private_keys = private_keys.set('memo_private', PrivateKey.fromWif(memoWif))
-
- yield call(accountAuthLookup, {payload: {account, private_keys, highSecurityLogin, login_owner_pubkey}})
- let authority = yield select(state => state.user.getIn(['authority', username]))
- const hasActiveAuth = authority.get('active') === 'full'
- if(!highSecurityLogin) {
- const accountName = account.get('name')
- authority = authority.set('active', 'none')
- yield put(user.actions.setAuthority({accountName, auth: authority}))
+ private_keys = private_keys.set(
+ 'memo_private',
+ PrivateKey.fromWif(memoWif)
+ );
+
+ yield call(accountAuthLookup, {
+ payload: {
+ account,
+ private_keys,
+ highSecurityLogin,
+ login_owner_pubkey,
+ },
+ });
+ let authority = yield select(state =>
+ state.user.getIn(['authority', username])
+ );
+ const hasActiveAuth = authority.get('active') === 'full';
+ if (!highSecurityLogin) {
+ const accountName = account.get('name');
+ authority = authority.set('active', 'none');
+ yield put(userActions.setAuthority({ accountName, auth: authority }));
}
- const fullAuths = authority.reduce((r, auth, type) => (auth === 'full' ? r.add(type) : r), Set())
+ const fullAuths = authority.reduce(
+ (r, auth, type) => (auth === 'full' ? r.add(type) : r),
+ Set()
+ );
if (!fullAuths.size) {
- localStorage.removeItem('autopost2')
+ localStorage.removeItem('autopost2');
const owner_pub_key = account.getIn(['owner', 'key_auths', 0, 0]);
- // const pub_keys = yield select(state => state.user.get('pub_keys_used'))
- // serverApiRecordEvent('login_attempt', JSON.stringify({name: username, ...pub_keys, cur_owner: owner_pub_key}))
- // FIXME pls parameterize opaque things like this into a constants file
- // code like this requires way too much historical knowledge to
- // understand.
- if (owner_pub_key === 'STM7sw22HqsXbz7D2CmJfmMwt9rimtk518dRzsR1f8Cgw52dQR1pR') {
- yield put(user.actions.loginError({ error: 'Hello. Your account may have been compromised. We are working on restoring an access to your account. Please send an email to support@steemit.com.' }))
- return
- }
- if(login_owner_pubkey === owner_pub_key || login_wif_owner_pubkey === owner_pub_key) {
- yield put(user.actions.loginError({ error: 'owner_login_blocked' }))
- } else if(!highSecurityLogin && hasActiveAuth) {
- yield put(user.actions.loginError({ error: 'active_login_blocked' }))
+ if (
+ login_owner_pubkey === owner_pub_key ||
+ login_wif_owner_pubkey === owner_pub_key
+ ) {
+ yield put(userActions.loginError({ error: 'owner_login_blocked' }));
+ } else if (!highSecurityLogin && hasActiveAuth) {
+ yield put(
+ userActions.loginError({ error: 'active_login_blocked' })
+ );
} else {
const generated_type = password[0] === 'P' && password.length > 40;
- serverApiRecordEvent('login_attempt', JSON.stringify({name: username, login_owner_pubkey, owner_pub_key, generated_type}))
- yield put(user.actions.loginError({ error: 'Incorrect Password' }))
+ serverApiRecordEvent(
+ 'login_attempt',
+ JSON.stringify({
+ name: username,
+ login_owner_pubkey,
+ owner_pub_key,
+ generated_type,
+ })
+ );
+ yield put(userActions.loginError({ error: 'Incorrect Password' }));
}
- return
+ return;
}
if (authority.get('posting') !== 'full')
- private_keys = private_keys.remove('posting_private')
-
- if(!highSecurityLogin || authority.get('active') !== 'full')
- private_keys = private_keys.remove('active_private')
-
- const owner_pubkey = account.getIn(['owner', 'key_auths', 0, 0])
- const active_pubkey = account.getIn(['active', 'key_auths', 0, 0])
- const posting_pubkey = account.getIn(['posting', 'key_auths', 0, 0])
-
- if (private_keys.get('memo_private') &&
- account.get('memo_key') !== private_keys.get('memo_private').toPublicKey().toString()
+ private_keys = private_keys.remove('posting_private');
+
+ if (!highSecurityLogin || authority.get('active') !== 'full')
+ private_keys = private_keys.remove('active_private');
+
+ const owner_pubkey = account.getIn(['owner', 'key_auths', 0, 0]);
+ const active_pubkey = account.getIn(['active', 'key_auths', 0, 0]);
+ const posting_pubkey = account.getIn(['posting', 'key_auths', 0, 0]);
+
+ if (
+ private_keys.get('memo_private') &&
+ account.get('memo_key') !==
+ private_keys
+ .get('memo_private')
+ .toPublicKey()
+ .toString()
)
// provided password did not yield memo key
- private_keys = private_keys.remove('memo_private')
+ private_keys = private_keys.remove('memo_private');
- if(!highSecurityLogin) {
- if(
+ if (!highSecurityLogin) {
+ if (
posting_pubkey === owner_pubkey ||
posting_pubkey === active_pubkey
) {
- yield put(user.actions.loginError({ error: 'This login gives owner or active permissions and should not be used here. Please provide a posting only login.' }))
- localStorage.removeItem('autopost2')
- return
+ yield put(
+ userActions.loginError({
+ error:
+ 'This login gives owner or active permissions and should not be used here. Please provide a posting only login.',
+ })
+ );
+ localStorage.removeItem('autopost2');
+ return;
}
}
- const memo_pubkey = private_keys.has('memo_private') ?
- private_keys.get('memo_private').toPublicKey().toString() : null
-
- if(
- memo_pubkey === owner_pubkey ||
- memo_pubkey === active_pubkey
- )
+ const memo_pubkey = private_keys.has('memo_private')
+ ? private_keys
+ .get('memo_private')
+ .toPublicKey()
+ .toString()
+ : null;
+
+ if (memo_pubkey === owner_pubkey || memo_pubkey === active_pubkey)
// Memo key could be saved in local storage.. In RAM it is not purged upon LOCATION_CHANGE
- private_keys = private_keys.remove('memo_private')
+ private_keys = private_keys.remove('memo_private');
// If user is signing operation by operaion and has no saved login, don't save to RAM
- if(!operationType || saveLogin) {
- if(username) feedURL = '/@' + username + '/feed';
+ if (!operationType || saveLogin) {
+ if (username) feedURL = '/@' + username + '/feed';
// Keep the posting key in RAM but only when not signing an operation.
// No operation or the user has checked: Keep me logged in...
- yield put(user.actions.setUser({username, private_keys, login_owner_pubkey, vesting_shares: account.get('vesting_shares'),
- received_vesting_shares: account.get('received_vesting_shares'),
- delegated_vesting_shares: account.get('delegated_vesting_shares')}))
+ yield put(
+ userActions.setUser({
+ username,
+ private_keys,
+ login_owner_pubkey,
+ vesting_shares: account.get('vesting_shares'),
+ received_vesting_shares: account.get('received_vesting_shares'),
+ delegated_vesting_shares: account.get(
+ 'delegated_vesting_shares'
+ ),
+ })
+ );
} else {
- if(username) feedURL = '/@' + username + '/feed';
- yield put(user.actions.setUser({username, vesting_shares: account.get('vesting_shares'),
- received_vesting_shares: account.get('received_vesting_shares'),
- delegated_vesting_shares: account.get('delegated_vesting_shares')}))
+ if (username) feedURL = '/@' + username + '/feed';
+ yield put(
+ userActions.setUser({
+ username,
+ vesting_shares: account.get('vesting_shares'),
+ received_vesting_shares: account.get('received_vesting_shares'),
+ delegated_vesting_shares: account.get(
+ 'delegated_vesting_shares'
+ ),
+ })
+ );
}
- if (!autopost && saveLogin)
- yield put(user.actions.saveLogin());
+ if (!autopost && saveLogin) yield put(userActions.saveLogin());
try {
// const challengeString = yield serverApiLoginChallenge()
- const offchainData = yield select(state => state.offchain)
- const serverAccount = offchainData.get('account')
- const challengeString = offchainData.get('login_challenge')
+ const offchainData = yield select(state => state.offchain);
+ const serverAccount = offchainData.get('account');
+ const challengeString = offchainData.get('login_challenge');
if (!serverAccount && challengeString) {
- const signatures = {}
- const challenge = {token: challengeString}
- const bufSha = hash.sha256(JSON.stringify(challenge, null, 0))
+ const signatures = {};
+ const challenge = { token: challengeString };
+ const bufSha = hash.sha256(JSON.stringify(challenge, null, 0));
const sign = (role, d) => {
- if (!d) return
- const sig = Signature.signBufferSha256(bufSha, d)
- signatures[role] = sig.toHex()
- }
- sign('posting', private_keys.get('posting_private'))
+ if (!d) return;
+ const sig = Signature.signBufferSha256(bufSha, d);
+ signatures[role] = sig.toHex();
+ };
+ sign('posting', private_keys.get('posting_private'));
// sign('active', private_keys.get('active_private'))
serverApiLogin(username, signatures);
}
- } catch(error) {
+ } catch (error) {
// Does not need to be fatal
console.error('Server Login Error', error);
}
+
+ // Feature flags
+ yield fork(
+ getFeatureFlags,
+ username,
+ private_keys.get('posting_private').toString()
+ );
+
if (afterLoginRedirectToWelcome) {
- browserHistory.push('/welcome')
- } else if(feedURL) {
- if(document.location.pathname === '/') browserHistory.push(feedURL);
+ browserHistory.push('/welcome');
+ } else if (feedURL) {
+ if (document.location.pathname === '/') browserHistory.push(feedURL);
+ }
+}
+
+function* getFeatureFlags(username, posting_private) {
+ try {
+ const flags = yield call(
+ [api, api.signedCallAsync],
+ 'conveyor.get_feature_flags',
+ { account: username },
+ username,
+ posting_private
+ );
+ yield put(receiveFeatureFlags(flags));
+ } catch (error) {
+ // Do nothing; feature flags are not ready yet.
}
}
function* saveLogin_localStorage() {
if (!process.env.BROWSER) {
- console.error('Non-browser environment, skipping localstorage')
- return
+ console.error('Non-browser environment, skipping localstorage');
+ return;
}
- localStorage.removeItem('autopost2')
- const [username, private_keys, login_owner_pubkey] = yield select(state => ([
+ localStorage.removeItem('autopost2');
+ const [username, private_keys, login_owner_pubkey] = yield select(state => [
state.user.getIn(['current', 'username']),
state.user.getIn(['current', 'private_keys']),
state.user.getIn(['current', 'login_owner_pubkey']),
- ]))
+ ]);
if (!username) {
- console.error('Not logged in')
- return
+ console.error('Not logged in');
+ return;
}
// Save the lowest security key
- const posting_private = private_keys.get('posting_private')
+ const posting_private = private_keys.get('posting_private');
if (!posting_private) {
- console.error('No posting key to save?')
- return
+ console.error('No posting key to save?');
+ return;
}
- const account = yield select(state => state.global.getIn(['accounts', username]))
- if(!account) {
- console.error('Missing global.accounts[' + username + ']')
- return
+ const account = yield select(state =>
+ state.global.getIn(['accounts', username])
+ );
+ if (!account) {
+ console.error('Missing global.accounts[' + username + ']');
+ return;
}
- const postingPubkey = posting_private.toPublicKey().toString()
+ const postingPubkey = posting_private.toPublicKey().toString();
try {
account.getIn(['active', 'key_auths']).forEach(auth => {
- if(auth.get(0) === postingPubkey)
- throw 'Login will not be saved, posting key is the same as active key'
- })
+ if (auth.get(0) === postingPubkey)
+ throw 'Login will not be saved, posting key is the same as active key';
+ });
account.getIn(['owner', 'key_auths']).forEach(auth => {
- if(auth.get(0) === postingPubkey)
- throw 'Login will not be saved, posting key is the same as owner key'
- })
- } catch(e) {
- console.error(e)
- return
+ if (auth.get(0) === postingPubkey)
+ throw 'Login will not be saved, posting key is the same as owner key';
+ });
+ } catch (e) {
+ console.error(e);
+ return;
}
- const memoKey = private_keys.get('memo_private')
- const memoWif = memoKey && memoKey.toWif()
- const data = new Buffer(`${username}\t${posting_private.toWif()}\t${memoWif || ''}\t${login_owner_pubkey || ''}`).toString('hex')
+ const memoKey = private_keys.get('memo_private');
+ const memoWif = memoKey && memoKey.toWif();
+ const data = new Buffer(
+ `${username}\t${posting_private.toWif()}\t${memoWif ||
+ ''}\t${login_owner_pubkey || ''}`
+ ).toString('hex');
// autopost is a auto login for a low security key (like the posting key)
- localStorage.setItem('autopost2', data)
+ localStorage.setItem('autopost2', data);
}
function* logout() {
- yield put(user.actions.saveLoginConfirm(false)) // Just incase it is still showing
- if (process.env.BROWSER)
- localStorage.removeItem('autopost2')
+ yield put(userActions.saveLoginConfirm(false)); // Just incase it is still showing
+ if (process.env.BROWSER) localStorage.removeItem('autopost2');
serverApiLogout();
}
-function* loginError({payload: {/*error*/}}) {
+function* loginError({
+ payload: {
+ /*error*/
+ },
+}) {
serverApiLogout();
}
/**
If the owner key was changed after the login owner key, this function will find the next owner key history record after the change and store it under user.previous_owner_authority.
*/
-function* lookupPreviousOwnerAuthority({payload: {}}) {
- const current = yield select(state => state.user.get('current'))
- if(!current) return
+function* lookupPreviousOwnerAuthority({ payload: {} }) {
+ const current = yield select(state => state.user.getIn(['current']));
+ if (!current) return;
- const login_owner_pubkey = current.get('login_owner_pubkey')
- if(!login_owner_pubkey) return
+ const login_owner_pubkey = current.get('login_owner_pubkey');
+ if (!login_owner_pubkey) return;
- const username = current.get('username')
- const key_auths = yield select(state => state.global.getIn(['accounts', username, 'owner', 'key_auths']))
+ const username = current.get('username');
+ const key_auths = yield select(state =>
+ state.global.getIn(['accounts', username, 'owner', 'key_auths'])
+ );
if (key_auths && key_auths.find(key => key.get(0) === login_owner_pubkey)) {
// console.log('UserSaga ---> Login matches current account owner');
- return
+ return;
}
// Owner history since this index was installed July 14
- let owner_history = fromJS(yield call([api, api.getOwnerHistoryAsync], username))
- if(owner_history.count() === 0) return
- owner_history = owner_history.sort((b, a) => {//sort decending
- const aa = a.get('last_valid_time')
- const bb = b.get('last_valid_time')
- return aa < bb ? -1 : aa > bb ? 1 : 0
- })
+ let owner_history = fromJS(
+ yield call([api, api.getOwnerHistoryAsync], username)
+ );
+ if (owner_history.count() === 0) return;
+ owner_history = owner_history.sort((b, a) => {
+ //sort decending
+ const aa = a.get('last_valid_time');
+ const bb = b.get('last_valid_time');
+ return aa < bb ? -1 : aa > bb ? 1 : 0;
+ });
// console.log('UserSaga ---> owner_history', owner_history.toJS())
const previous_owner_authority = owner_history.find(o => {
- const auth = o.get('previous_owner_authority')
- const weight_threshold = auth.get('weight_threshold')
- const key3 = auth.get('key_auths').find(key2 => key2.get(0) === login_owner_pubkey && key2.get(1) >= weight_threshold)
- return key3 ? auth : null
- })
- if(!previous_owner_authority) {
+ const auth = o.get('previous_owner_authority');
+ const weight_threshold = auth.get('weight_threshold');
+ const key3 = auth
+ .get('key_auths')
+ .find(
+ key2 =>
+ key2.get(0) === login_owner_pubkey &&
+ key2.get(1) >= weight_threshold
+ );
+ return key3 ? auth : null;
+ });
+ if (!previous_owner_authority) {
console.log('UserSaga ---> Login owner does not match owner history');
- return
+ return;
}
// console.log('UserSage ---> previous_owner_authority', previous_owner_authority.toJS())
- yield put(user.actions.setUser({previous_owner_authority}))
+ yield put(userActions.setUser({ previous_owner_authority }));
}
function* uploadImageWatch() {
- yield* takeLatest('user/UPLOAD_IMAGE', uploadImage);
+ yield* takeLatest(userActions.UPLOAD_IMAGE, uploadImage);
}
-function* uploadImage({payload: {file, dataUrl, filename = 'image.txt', progress}}) {
- const _progress = progress
+function* uploadImage({
+ payload: { file, dataUrl, filename = 'image.txt', progress },
+}) {
+ const _progress = progress;
progress = msg => {
// console.log('Upload image progress', msg)
- _progress(msg)
- }
+ _progress(msg);
+ };
- const stateUser = yield select(state => state.user)
- const username = stateUser.getIn(['current', 'username'])
- const d = stateUser.getIn(['current', 'private_keys', 'posting_private'])
- if(!username) {
- progress({error: 'Please login first.'})
- return
+ const stateUser = yield select(state => state.user);
+ const username = stateUser.getIn(['current', 'username']);
+ const d = stateUser.getIn(['current', 'private_keys', 'posting_private']);
+ if (!username) {
+ progress({ error: 'Please login first.' });
+ return;
}
- if(!d) {
- progress({error: 'Login with your posting key'})
- return
+ if (!d) {
+ progress({ error: 'Login with your posting key' });
+ return;
}
- if(!file && !dataUrl) {
- console.error('uploadImage required: file or dataUrl')
- return
+ if (!file && !dataUrl) {
+ console.error('uploadImage required: file or dataUrl');
+ return;
}
- let data, dataBs64
- if(file) {
+ let data, dataBs64;
+ if (file) {
// drag and drop
- const reader = new FileReader()
+ const reader = new FileReader();
data = yield new Promise(resolve => {
reader.addEventListener('load', () => {
- const result = new Buffer(reader.result, 'binary')
- resolve(result)
- })
- reader.readAsBinaryString(file)
- })
+ const result = new Buffer(reader.result, 'binary');
+ resolve(result);
+ });
+ reader.readAsBinaryString(file);
+ });
} else {
// recover from preview
- const commaIdx = dataUrl.indexOf(',')
- dataBs64 = dataUrl.substring(commaIdx + 1)
- data = new Buffer(dataBs64, 'base64')
+ const commaIdx = dataUrl.indexOf(',');
+ dataBs64 = dataUrl.substring(commaIdx + 1);
+ data = new Buffer(dataBs64, 'base64');
}
// The challenge needs to be prefixed with a constant (both on the server and checked on the client) to make sure the server can't easily make the client sign a transaction doing something else.
- const prefix = new Buffer('ImageSigningChallenge')
- const bufSha = hash.sha256(Buffer.concat([prefix, data]))
+ const prefix = new Buffer('ImageSigningChallenge');
+ const bufSha = hash.sha256(Buffer.concat([prefix, data]));
- const formData = new FormData()
- if(file) {
- formData.append('file', file)
+ const formData = new FormData();
+ if (file) {
+ formData.append('file', file);
} else {
// formData.append('file', file, filename) <- Failed to add filename=xxx to Content-Disposition
// Can't easily make this look like a file so this relies on the server supporting: filename and filebinary
- formData.append('filename', filename)
- formData.append('filebase64', dataBs64)
+ formData.append('filename', filename);
+ formData.append('filebase64', dataBs64);
}
- const sig = Signature.signBufferSha256(bufSha, d)
- const postUrl = `${$STM_Config.upload_image}/${username}/${sig.toHex()}`
-
- const xhr = new XMLHttpRequest()
- xhr.open('POST', postUrl)
- xhr.onload = function () {
- console.log(xhr.status, xhr.responseText)
- const res = JSON.parse(xhr.responseText)
- const {error} = res
- if(error) {
- progress({error: 'Error: ' + error})
- return
+ const sig = Signature.signBufferSha256(bufSha, d);
+ const postUrl = `${$STM_Config.upload_image}/${username}/${sig.toHex()}`;
+
+ const xhr = new XMLHttpRequest();
+ xhr.open('POST', postUrl);
+ xhr.onload = function() {
+ console.log(xhr.status, xhr.responseText);
+ const res = JSON.parse(xhr.responseText);
+ const { error } = res;
+ if (error) {
+ progress({ error: 'Error: ' + error });
+ return;
}
- const {url} = res
- progress({url})
- }
- xhr.onerror = function (error) {
- console.error(filename, error)
- progress({error: 'Unable to contact the server.'})
- }
- xhr.upload.onprogress = function (event) {
+ const { url } = res;
+ progress({ url });
+ };
+ xhr.onerror = function(error) {
+ console.error(filename, error);
+ progress({ error: 'Unable to contact the server.' });
+ };
+ xhr.upload.onprogress = function(event) {
if (event.lengthComputable) {
- const percent = Math.round((event.loaded / event.total) * 100)
- progress({message: `Uploading ${percent}%`})
+ const percent = Math.round(event.loaded / event.total * 100);
+ progress({ message: `Uploading ${percent}%` });
// console.log('Upload', percent)
}
- }
- xhr.send(formData)
+ };
+ xhr.send(formData);
}
-
// function* getCurrentAccount() {
// const current = yield select(state => state.user.get('current'))
// if (!current) return
diff --git a/src/app/redux/tests/AppReducer.test.js b/src/app/redux/tests/AppReducer.test.js
deleted file mode 100644
index c20ae36bda2c0a67872566e3aebf02129193b7cc..0000000000000000000000000000000000000000
--- a/src/app/redux/tests/AppReducer.test.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/*global describe, it, before, beforeEach, after, afterEach */
-import chai, {expect} from 'chai';
-import dirtyChai from 'dirty-chai';
-import chaiImmutable from 'chai-immutable';
-import {Map} from 'immutable';
-import reducer from '../AppReducer';
-chai.use(dirtyChai);
-chai.use(chaiImmutable);
-
-const defaultState = Map({
- effects: Map({}),
- loading: false,
- error: ''
-});
-
-const effectTriggered = {
- type: 'EFFECT_TRIGGERED',
- effectId: 1,
- effect: {
- CALL: true
- }
-};
-
-const effectResolved = {
- type: 'EFFECT_RESOLVED',
- effectId: '1'
-};
-
-
-describe('AppReducer', () => {
- it('should return default state', () => {
- expect(
- reducer(undefined, {})
- ).to.equal(defaultState);
- });
-
- it('triggered effect should be added to effects and turn on loading', () => {
- const state = reducer(undefined, effectTriggered);
- expect(state.get('loading')).to.be.true();
- expect(state.get('effects').size).to.equal(1);
- });
-
- it('resolved effect should be added to effects and turn on loading', () => {
- const triggeredState = Map({
- effects: Map({['1']: Date.now()}),
- loading: true,
- error: ''
- });
- const state = reducer(triggeredState, effectResolved);
- expect(state.get('effects').size).to.equal(0);
- expect(state.get('loading')).to.be.false();
- });
-});
diff --git a/src/app/redux/tests/global.json b/src/app/redux/tests/global.json
index f25e836722382bae9b52c20c26f571e9172ee652..4fd5323e87872adf192c0a1c234c6563a2d305ab 100644
--- a/src/app/redux/tests/global.json
+++ b/src/app/redux/tests/global.json
@@ -1,82 +1,83 @@
{
- "pathname": "trending",
- "props": {
- "id": "2.0.0",
- "head_block_number": 38897,
- "head_block_id": "000097f1d40a280e4758128e7b57d60cee9df36d",
- "time": "2016-03-24T15:39:06",
- "current_witness": "mottler-5",
- "total_pow": "18446744048449238345",
- "num_pow_witnesses": 79,
- "virtual_supply": "156738.000 STEEM",
- "current_supply": "156738.000 STEEM",
- "confidential_supply": "0.000 STEEM",
- "current_sbd_supply": "0.000 SBD",
- "confidential_sbd_supply": "0.000 SBD",
- "total_vesting_fund_steem": "274.000 STEEM",
- "total_vesting_shares": "274.000000 VESTS",
- "total_reward_fund_steem": "77794.000 STEEM",
- "total_reward_shares2": "0",
- "sbd_interest_rate": 1000,
- "average_block_size": 117,
- "maximum_block_size": 131072,
- "current_aslot": 47582,
- "recent_slots_filled": "329648522672200722443889453235959593423",
- "last_irreversible_block_num": 38876,
- "max_virtual_bandwidth": "2203586534107862357",
- "current_reserve_ratio": 1945
- },
- "tag_idx": {
- "trending": [],
- "active": [],
- "recent": [],
- "best": []
- },
- "categories": {},
- "content": {},
- "accounts": {},
- "pow_queue": [],
- "witnesses": {
- "id": "2.7.0",
- "current_virtual_time": "0",
- "next_shuffle_block_num": 38913,
- "current_shuffled_witnesses": [
- "mottler-6",
- "alice1",
- "mottler-4",
- "faddy3",
- "dumpthisjunk",
- "dealthandtaxes",
- "lambda",
- "cloop3",
- "mr11acdee3",
- "dumpcoin",
- "nxt",
- "devshuster",
- "nxt1",
- "mottler-7",
- "failcoin1",
- "mottler-1",
- "smooth",
- "mottler-5",
- "blizzt",
- "rurikovich",
- "woot"
- ],
- "median_props": {
- "account_creation_fee": "100.000 STEEM",
- "maximum_block_size": 131072,
- "sbd_interest_rate": 1000
+ "pathname": "trending",
+ "props": {
+ "id": "2.0.0",
+ "head_block_number": 38897,
+ "head_block_id": "000097f1d40a280e4758128e7b57d60cee9df36d",
+ "time": "2016-03-24T15:39:06",
+ "current_witness": "mottler-5",
+ "total_pow": "18446744048449238345",
+ "num_pow_witnesses": 79,
+ "virtual_supply": "156738.000 STEEM",
+ "current_supply": "156738.000 STEEM",
+ "confidential_supply": "0.000 STEEM",
+ "current_sbd_supply": "0.000 SBD",
+ "confidential_sbd_supply": "0.000 SBD",
+ "total_vesting_fund_steem": "274.000 STEEM",
+ "total_vesting_shares": "274.000000 VESTS",
+ "total_reward_fund_steem": "77794.000 STEEM",
+ "total_reward_shares2": "0",
+ "sbd_interest_rate": 1000,
+ "average_block_size": 117,
+ "maximum_block_size": 131072,
+ "current_aslot": 47582,
+ "recent_slots_filled": "329648522672200722443889453235959593423",
+ "last_irreversible_block_num": 38876,
+ "max_virtual_bandwidth": "2203586534107862357",
+ "current_reserve_ratio": 1945
+ },
+ "status": {},
+ "tag_idx": {
+ "trending": [],
+ "active": [],
+ "recent": [],
+ "best": []
+ },
+ "categories": {},
+ "content": {},
+ "accounts": {},
+ "pow_queue": [],
+ "witnesses": {
+ "id": "2.7.0",
+ "current_virtual_time": "0",
+ "next_shuffle_block_num": 38913,
+ "current_shuffled_witnesses": [
+ "mottler-6",
+ "alice1",
+ "mottler-4",
+ "faddy3",
+ "dumpthisjunk",
+ "dealthandtaxes",
+ "lambda",
+ "cloop3",
+ "mr11acdee3",
+ "dumpcoin",
+ "nxt",
+ "devshuster",
+ "nxt1",
+ "mottler-7",
+ "failcoin1",
+ "mottler-1",
+ "smooth",
+ "mottler-5",
+ "blizzt",
+ "rurikovich",
+ "woot"
+ ],
+ "median_props": {
+ "account_creation_fee": "100.000 STEEM",
+ "maximum_block_size": 131072,
+ "sbd_interest_rate": 1000
+ }
+ },
+ "discussion_idx": {
+ "": {
+ "category": "",
+ "trending": [],
+ "recent": [],
+ "active": [],
+ "maturing": [],
+ "best": []
+ }
}
- },
- "discussion_idx": {
- "": {
- "category": "",
- "trending": [],
- "recent": [],
- "active": [],
- "maturing": [],
- "best": []
- }
- }
}
diff --git a/src/app/redux/tests/global.test.js b/src/app/redux/tests/global.test.js
index a55397619e51f371e7f93979b9513e5dd1dba5a1..b1631faaea9cfe62ef83b9d1b4f8cacc27d427b2 100644
--- a/src/app/redux/tests/global.test.js
+++ b/src/app/redux/tests/global.test.js
@@ -1,25 +1,18 @@
/*global describe, it, before, beforeEach, after, afterEach */
-
-import chai, {expect} from 'chai';
-import chaiImmutable from 'chai-immutable';
-import Immutable, {Map} from 'immutable';
-import ReducerModule from '../GlobalReducer';
-chai.use(chaiImmutable);
-
-const {reducer, actions} = ReducerModule;
+import Immutable from 'immutable';
+import reducer, * as globalActions from '../GlobalReducer';
describe('global reducer', () => {
it('should return empty state', () => {
- expect(
- reducer(undefined, {})
- ).to.equal(Map({}));
+ const reduced = reducer(undefined, {});
+
+ expect(reduced.toJS()).toEqual({ status: {} });
});
it('should apply new global state', () => {
const state = Immutable.fromJS(require('./global.json'));
+ const reduced = reducer(undefined, globalActions.receiveState(state));
//const action = {type: 'global/RECEIVE_STATE', payload: state};
- expect(
- reducer(undefined, actions.receiveState(state))
- ).to.equal(state);
+ expect(reduced.toJS()).toEqual(state.toJS());
});
});
diff --git a/src/app/utils/Accessors.js b/src/app/utils/Accessors.js
index dd56b75e4ecc880fc6ff2ff7317aec8b28261bda..b650f8f0781824eb87dbc32852bfae8235951761 100644
--- a/src/app/utils/Accessors.js
+++ b/src/app/utils/Accessors.js
@@ -1,11 +1,17 @@
export function immutableAccessor(obj, ...keys) {
- if (!obj) return {}
+ if (!obj) return {};
if (keys.length === 1) return obj.get(keys[0]);
- return keys.reduce((res, key) => {res[key] = obj.get(key); return res;}, {});
+ return keys.reduce((res, key) => {
+ res[key] = obj.get(key);
+ return res;
+ }, {});
}
export function objAccessor(obj, ...keys) {
- if (!obj) return {}
+ if (!obj) return {};
if (keys.length === 1) return obj[keys[0]];
- return keys.reduce((res, key) => {res[key] = obj[key]; return res;}, {});
+ return keys.reduce((res, key) => {
+ res[key] = obj[key];
+ return res;
+ }, {});
}
diff --git a/src/app/utils/AppPropTypes.js b/src/app/utils/AppPropTypes.js
index b74c1c0573137d4295e538579001f4af92ddb0c7..58a91eb3c4db3bba990e34615023300b9249239d 100644
--- a/src/app/utils/AppPropTypes.js
+++ b/src/app/utils/AppPropTypes.js
@@ -1,8 +1,8 @@
-import {PropTypes} from 'react';
+import { PropTypes } from 'react';
const Children = PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
- PropTypes.node
+ PropTypes.node,
]);
-export default {Children};
+export default { Children };
diff --git a/src/app/utils/BadActorList.js b/src/app/utils/BadActorList.js
index 87fa7eb0cf8fb26be6d40058a562b1308fc31393..1cf79805ae410e0f2ff464e3d050ab273602488a 100644
--- a/src/app/utils/BadActorList.js
+++ b/src/app/utils/BadActorList.js
@@ -1,45 +1,326 @@
const list = `
-polonox
-poloneix
+abits
+acx
+aex.com
+allcoin.com
+appreciater
+apreciator
+ausbitban
+ausbltbank
+battrex
+bbittrex
+bcex
+bellyrub
+berniesandlers
+bernieslanders
+berniestandards
+bernlesanders
+bettrex
biitrex
biittrex
+binan
+binanc
+binance
+binance.com
+binanced
+binancee
+binances
+binanse
+binnance
+bit-z
+bitex
+bitfinex
+bitfinex.com
+bitfinix
+bitflip
+bithumb
+bithumb.com
+bitifinex
+bitkrx
+bitnaru
+bitre
+bitreex
+bitrex
+bitrexx
+bitrix
+bitrrex
+bitrtex
+bitrx
+bitsane
+bitsane.com
+bitstamp
+bitstamp.net
+bitt
+bitteex
bitter
+bitterex
bitterx
bittex
+bitthai
+bittr
bittrax
bittre
bittrec
+bittrecs
+bittred
+bittreex
+bittrek
bittres
+bittresx
+bittret
+bittrev
+bittrex-deposit
bittrex.com
+bittrexchange
bittrexe
+bittrexs
+bittrext
bittrexx
+bittrexxx
bittrez
bittrix
+bittrrex
+bittrrx
bittrx
+bittrxe
+bitttec
+bitttex
bitttrex
-bitrex
-bitrexx
-bitrix
-bitrrex
-bttrex
-btrex
-bttrex
-ittrex
-bittrex-deposit
+bittylicious
+bittylicious.com
+blcktrades
+blcoktrades
+bleutrade
+bleutrade.com
+block-trades
+block-trades-com
+blockrade
blockrades
+blockrtades
+blocktades
+blocktardes
blocktraades
+blocktrad
+blocktrade
+blocktraded
+blocktradee
+blocktradees
+blocktrader
+blocktraders
+blocktrades-com
+blocktrades-info
+blocktrades-us
+blocktrades.com
+blocktrades.info
+blocktrades.us
+blocktradess
+blocktradesss
+blocktradez
+blocktrading
+blocktrads
blocktradse
+blocktraeds
+blocktraes
+blocktrdaes
+blocktrdes
+blocktredes
+blockttrades
+bloctkrades
+bloctrades
+blokctrades
+bloktrades
+bloocktrades
+bocktrades
+bolcktrades
+bomerang
+boooster
+boostar
+booste
+boosterr
+boostr
+boostre
+boostter
+boster
+btc38
+btc-alpha
+btc-alpha.com
+btcalpha
+btcmarkets
+btcmarkets.net
+btitrex
+btrex
+bttrex
+bttrx
+buildawale
+buildawhile
+buildwhale
+c-cex
+c-cex.com
+canadiancoconut
+ccex
+cexio
+changellly
+changelly.com
+changely
+coin-room
+coinbas
+coinbase
+coinbase.com
+coinbased
+coinegg
+coinegg.com
+coinpayment
+coinpayments
+coinpia
+coinroom.com
+coinsmarkets
+coinsmarkets.com
+coinspot
+coinzest
+community-coin
+coolcoin.com
+curi
+curied
+curies
+curing
+d-tube
+dcrypto8
+decrypto8
+deep8
+deepcripto8
+deepcrpto8
+deepcrypo8
+deepcrypt8
+deepcrypto0
+deepcrypto7
+deepcrypto9
+deepcrypto88
+deepcrypto-8
+deepcryptoo8
+deepcryptos
+deepcryptos8
+deepcryto8
+deepcrytpo8
+deepcypto8
+deeprypto8
+depcrypto8
+donkeypon
+eepcrypto8
+etherdelta
+etherdelta.com
+exrates
+exx.com
+freeewallet
+freewalet.org
+freewaller
+frewallet
+fyrstiken
+gatecoin.com
+gatehub
+gatehub.net
+gdax.com
+gemini.com
+gtg.witnesses
+hitbtc.com
+hitbtcexchange
+huobi.pro
+idex.market
+inance
+ittrex
+ittrexx
+kcx
+kevinwon
+kocostock
+koinex
+kraken
+kraken.com
+kucoi
+kucoin
+kucoinn
+kucoins
+linkcoin
+litebit
+little-pepper
+livecoin.com
+livecoinnet
+livingroomofsato
+localtrade
+localtrade.pro
+locktrades
+mercatox.com
+minnnowbooster
+minnobooster
+minnooboster
+minnoowbooster
+minnowboooster
+minnowboost
+minnowbooste
+minnowboosted
+minnowboosteer
+minnowboosterr
+minnowboosters
+minnowboostr
+minnowboostre
+minnowbootser
+minnowboster
+minnowbuster
+minnowhelp
+minnowpooster
+minnows
+minnowsuport
+minnowsupports
+minnowwbooster
+minobooster
+minowbooster
+minowboster
+minowhelper
+minowsupport
+myupblt
+neraex
+neraex.com
+nextgencrypted
+nextgencryptos
+okex.com
+olonie
+oloniex
+openledgerdex
+p-funk
+paloniex
+paypals
+pextokens
+pfuck
+piloniex
+plolniex
+ploniex
+plooniex
+pokoniex
+polaniex
+poleniex
+poliniex
+polionex
+pollniex
+polloniex
+polloniexx
+pollonix
+polniex
+polnoiex
+polobiex
+poloex
poloiex
poloinex
+pololniex
polomiex
polon
poloneex
+poloneiex
poloneix
polonex
poloni
poloniax
polonie
poloniec
+poloniecs
+polonied
poloniee
polonieex
poloniek
@@ -47,12 +328,17 @@ polonieks
polonies
poloniet
poloniets
+poloniew
poloniex.com
poloniexcold
+poloniexcom
poloniexe
poloniexs
poloniext
+poloniexwalle
+poloniexwallet
poloniexx
+poloniexxx
poloniey
poloniez
poloniiex
@@ -61,48 +347,101 @@ poloniks
poloniox
polonium
polonix
+polonixe
+polonixx
polonniex
+polonoiex
+polonox
+polonx
+polonyex
polooniex
+poluniex
+pononiex
+poolniex
+pooloniex
pooniex
poooniex
-plolniex
-ploniex
-plooniex
-poloex
-oloniex
-pooloniex
-poliniex
-polniex
-poleniex
-polionex
-pollniex
-polloniex
-polnoiex
-polonyex
-polonied
-polonixe
-blocktardes
-blocktrade
-bocktrades
-changelly.com
-changely
-shapeshif
-shapeshift
+poponiex
+postpromote
+pse
+ptunk
+puloniex
+qryptos
+qryptos.com
randomwhale
randowale
+randowhal
randwhale
-coinpayments
-minnowboost
-minnowboster
-minowbooster
-minnowbooste
-minnowboooster
-minnnowbooster
-blocktades
-bloocktrades
-bloctrades
-blocktradess
-blocktrade
-`.trim().split('\n');
+rendowhale
+scoin
+shapeshif
+shapeshift
+steampunks
+steemitpay
+steempay
+steempays
+steemupbit
+sweetsj
+sweetssj
+sweetsss
+sweetsssjs
+sweetssssj
+swetsssj
+tdax
+tdax.com
+teamsteam
+techno-comanche
+technocommander
+thealien
+thebiton
+therocktrading
+tidex.com
+topbtc
+ttrex
+upbbit
+upbi
+upbit
+upbit.com
+upbits
+upbitt
+upblt
+upm
+upmee
+uppme
+uppmee
+viabtc
+vittrex
+wallet.bitshares
+whaleshare
+www.aex.com
+www.binance.com
+www.bit-z.com
+www.bitfinex.com
+www.bithumb.com
+www.bitstamp.net
+www.bittrex.com
+www.coinbase.com
+www.coinegg.com
+www.coolcoin.com
+www.exx.com
+www.gatecoin.com
+www.gatehub.net
+www.gdax.com
+www.huobi.pro
+www.kraken.com
+www.livecoin.net
+www.okex.com
+www.poloniex.com
+www.qryptos.com
+www.xbtce.com
+xbtce.com
+yobit
+yobit.net
+youbit
+yunbi
+zeniex
+`
+ .trim()
+ .split('\n');
export default list;
diff --git a/src/app/utils/BrowserTests.js b/src/app/utils/BrowserTests.js
index ddab1b8e93ef11636dcd25a29d05e1c42e8323e4..a41f22c8bef505d2e4f483446867e6963620a1d6 100644
--- a/src/app/utils/BrowserTests.js
+++ b/src/app/utils/BrowserTests.js
@@ -1,44 +1,46 @@
-import assert from 'assert'
-import {serverApiRecordEvent} from 'app/utils/ServerApiClient'
-import {PrivateKey, PublicKey} from 'steem/lib/auth/ecc'
-import {config} from 'steem';
+import assert from 'assert';
+import { serverApiRecordEvent } from 'app/utils/ServerApiClient';
+import { PrivateKey, PublicKey } from '@steemit/steem-js/lib/auth/ecc';
+import { config } from '@steemit/steem-js';
-export const browserTests = {}
+export const browserTests = {};
export default function runTests() {
- let rpt = ''
- let pass = true
+ let rpt = '';
+ let pass = true;
function it(name, fn) {
- console.log('Testing', name)
- rpt += 'Testing ' + name + '\n'
+ console.log('Testing', name);
+ rpt += 'Testing ' + name + '\n';
try {
- fn()
- } catch(error) {
- console.error(error)
- pass = false
- rpt += error.stack + '\n\n'
- serverApiRecordEvent('client_error', error)
+ fn();
+ } catch (error) {
+ console.error(error);
+ pass = false;
+ rpt += error.stack + '\n\n';
+ serverApiRecordEvent('client_error', error);
}
}
- let private_key, public_key
- const wif = '5JdeC9P7Pbd1uGdFVEsJ41EkEnADbbHGq6p1BwFxm6txNBsQnsw'
- const pubkey = config.get('address_prefix') +'8m5UgaFAAYQRuaNejYdS8FVLVp9Ss3K1qAVk5de6F8s3HnVbvA'
+ let private_key, public_key;
+ const wif = '5JdeC9P7Pbd1uGdFVEsJ41EkEnADbbHGq6p1BwFxm6txNBsQnsw';
+ const pubkey =
+ config.get('address_prefix') +
+ '8m5UgaFAAYQRuaNejYdS8FVLVp9Ss3K1qAVk5de6F8s3HnVbvA';
it('create private key', () => {
- private_key = PrivateKey.fromSeed('1')
- assert.equal(private_key.toWif(), wif)
- })
+ private_key = PrivateKey.fromSeed('1');
+ assert.equal(private_key.toWif(), wif);
+ });
it('supports WIF format', () => {
- assert(PrivateKey.fromWif(wif))
- })
+ assert(PrivateKey.fromWif(wif));
+ });
it('finds public from private key', () => {
- public_key = private_key.toPublicKey()
+ public_key = private_key.toPublicKey();
// substring match ignore prefix
- assert.equal(public_key.toString(), pubkey, 'Public key did not match')
- })
+ assert.equal(public_key.toString(), pubkey, 'Public key did not match');
+ });
it('parses public key', () => {
- assert(PublicKey.fromString(public_key.toString()))
- })
- if(!pass) return rpt
+ assert(PublicKey.fromString(public_key.toString()));
+ });
+ if (!pass) return rpt;
}
diff --git a/src/app/utils/ChainValidation.js b/src/app/utils/ChainValidation.js
index b3e3417e7c6998a2a98b08966ce2400250832fcf..b5a465fa0d21ae8632e3b11a6a93e4711f74e5ba 100644
--- a/src/app/utils/ChainValidation.js
+++ b/src/app/utils/ChainValidation.js
@@ -1,65 +1,78 @@
import tt from 'counterpart';
import BadActorList from 'app/utils/BadActorList';
import VerifiedExchangeList from 'app/utils/VerifiedExchangeList';
-import {PrivateKey, PublicKey} from 'steem/lib/auth/ecc';
+import { PrivateKey, PublicKey } from '@steemit/steem-js/lib/auth/ecc';
export function validate_account_name(value, memo) {
- let i, label, len, length, ref, suffix;
+ let i, label, len, length, ref;
- suffix = tt('chainvalidation_js.account_name_should');
if (!value) {
- return suffix + tt('chainvalidation_js.not_be_empty');
+ return tt('chainvalidation_js.account_name_should_not_be_empty');
}
length = value.length;
if (length < 3) {
- return suffix + tt('chainvalidation_js.be_longer');
+ return tt('chainvalidation_js.account_name_shouldbe_longer');
}
if (length > 16) {
- return suffix + tt('chainvalidation_js.be_shorter');
- }
- if (/\./.test(value)) {
- suffix = tt('chainvalidation_js.each_account_segment_should');
+ return tt('chainvalidation_js.account_name_shouldbe_shorter');
}
if (BadActorList.includes(value)) {
- return 'Use caution sending to this account. Please double check your spelling for possible phishing. ';
+ return tt('chainvalidation_js.badactor');
}
if (VerifiedExchangeList.includes(value) && !memo) {
- return tt('chainvalidation_js.verified_exchange_no_memo')
+ return tt('chainvalidation_js.verified_exchange_no_memo');
}
ref = value.split('.');
for (i = 0, len = ref.length; i < len; i++) {
label = ref[i];
if (!/^[a-z]/.test(label)) {
- return suffix + tt('chainvalidation_js.start_with_a_letter');
+ return tt(
+ 'chainvalidation_js.each_account_segment_should_start_with_a_letter'
+ );
}
if (!/^[a-z0-9-]*$/.test(label)) {
- return suffix + tt('chainvalidation_js.have_only_letters_digits_or_dashes');
+ return tt(
+ 'chainvalidation_js.each_account_segment_should_have_only_letters_digits_or_dashes'
+ );
}
if (/--/.test(label)) {
- return suffix + tt('chainvalidation_js.have_only_one_dash_in_a_row');
+ return tt(
+ 'chainvalidation_js.each_account_segment_should_have_only_one_dash_in_a_row'
+ );
}
if (!/[a-z0-9]$/.test(label)) {
- return suffix + tt('chainvalidation_js.end_with_a_letter_or_digit');
+ return tt(
+ 'chainvalidation_js.each_account_segment_should_end_with_a_letter_or_digit'
+ );
}
if (!(label.length >= 3)) {
- return suffix + tt('chainvalidation_js.be_longer');
+ return tt(
+ 'chainvalidation_js.each_account_segment_should_be_longer'
+ );
}
}
return null;
}
export function validate_memo_field(value, username, memokey) {
- let suffix;
- value = value.split(' ').filter(v=>v!='');
+ value = value.split(' ').filter(v => v != '');
for (var w in value) {
- if (PrivateKey.isWif(value[w])) {
- return suffix = 'Do not use private keys in memos. ';
- }
- if (memokey === PrivateKey.fromSeed(username + 'memo' + value[w]).toPublicKey().toString()) {
- return suffix = 'Do not use passwords in memos. ';
- }
- if (/5[HJK]\w{40,45}/i.test(value[w])) {
- return suffix = 'Please do not include what appears to be a private key or password. '
+ // Only perform key tests if it might be a key, i.e. it is a long string.
+ if (value[w].length >= 39) {
+ if (/5[HJK]\w{40,45}/i.test(value[w])) {
+ return tt('chainvalidation_js.memo_has_privatekey');
+ }
+ if (PrivateKey.isWif(value[w])) {
+ return tt('chainvalidation_js.memo_is_privatekey');
+ }
+ if (
+ memokey ===
+ PrivateKey.fromSeed(username + 'memo' + value[w])
+ .toPublicKey()
+ .toString()
+ ) {
+ return tt('chainvalidation_js.memo_is_password');
+ }
}
}
return null;
diff --git a/src/app/utils/ComponentFormatters.jsx b/src/app/utils/ComponentFormatters.jsx
index d5ee9912f07b4563f55451de57f979b5cdd8b3c1..18987c469d767718b7a489db1880d7fdcd316ed7 100644
--- a/src/app/utils/ComponentFormatters.jsx
+++ b/src/app/utils/ComponentFormatters.jsx
@@ -1,6 +1,10 @@
-import React from 'react'
+import React from 'react';
-export const authorNameAndRep = (author, authorRepLog10) =>
- {author}
- {authorRepLog10 != null && ({authorRepLog10}) }
-
\ No newline at end of file
+export const authorNameAndRep = (author, authorRepLog10) => (
+
+ {author}
+ {authorRepLog10 != null && (
+ ({authorRepLog10})
+ )}
+
+);
diff --git a/src/app/utils/ConsoleExports.js b/src/app/utils/ConsoleExports.js
index 1e3ce8987c9e7ab7c5ea57558b24affd7c9f09e2..25fbf58648d26b7ca1882662a429314c4e36018a 100644
--- a/src/app/utils/ConsoleExports.js
+++ b/src/app/utils/ConsoleExports.js
@@ -1,55 +1,63 @@
-import {PrivateKey, PublicKey, Aes, key_utils} from 'steem/lib/auth/ecc';
-
+import {
+ PrivateKey,
+ PublicKey,
+ Aes,
+ key_utils,
+} from '@steemit/steem-js/lib/auth/ecc';
// import secureRandom from 'secure-random'
// import links from 'app/utils/Links'
// import assert from 'assert'
module.exports = {
-
- PrivateKey, PublicKey, Aes, key_utils,
+ PrivateKey,
+ PublicKey,
+ Aes,
+ key_utils,
// Run once to start, then again to stop and print a report
// https://facebook.github.io/react/docs/perf.html
perf: () => {
- const Perf = require('react-addons-perf')
+ const Perf = require('react-addons-perf');
if (perfStarted) {
- Perf.stop()
- const lm = Perf.getLastMeasurements()
- Perf.printInclusive(lm)
- Perf.printExclusive(lm)
- Perf.printWasted(lm)
- perfStarted = false
+ Perf.stop();
+ const lm = Perf.getLastMeasurements();
+ Perf.printInclusive(lm);
+ Perf.printExclusive(lm);
+ Perf.printWasted(lm);
+ perfStarted = false;
} else {
- Perf.start()
- perfStarted = true
+ Perf.start();
+ perfStarted = true;
}
- return Perf
+ return Perf;
},
resolve: (object, atty = '_') => {
- if (! object.then) {
- console.log(object)
- return object
+ if (!object.then) {
+ console.log(object);
+ return object;
}
return new Promise((resolve, reject) => {
- object.then(result => {
- console.log(result)
- resolve(result)
- window[atty] = result
- }).catch(error => {
- console.error(error)
- reject(error)
- window[atty] = error
- })
- })
+ object
+ .then(result => {
+ console.log(result);
+ resolve(result);
+ window[atty] = result;
+ })
+ .catch(error => {
+ console.error(error);
+ reject(error);
+ window[atty] = error;
+ });
+ });
},
init: context => {
- if (! context) return
+ if (!context) return;
for (const obj in module.exports) {
- if (obj === 'init') continue
- context[obj] = module.exports[obj]
+ if (obj === 'init') continue;
+ context[obj] = module.exports[obj];
}
},
@@ -62,6 +70,6 @@ module.exports = {
// assert(match[0] === 'https://example.com', 'no match')
// }
// },
-}
+};
-let perfStarted = false
+let perfStarted = false;
diff --git a/src/app/utils/ContentPreview.js b/src/app/utils/ContentPreview.js
index bea503b85951745a27dceac497aa67aae980e5ec..6ccbec67396d9b082cf2985e0ca9d94f2919c279 100644
--- a/src/app/utils/ContentPreview.js
+++ b/src/app/utils/ContentPreview.js
@@ -10,7 +10,7 @@ export default function contentPreview(content, length) {
words++;
if (words > max_words) break;
if (i > length) break;
- };
+ }
res += ch;
}
return res;
diff --git a/src/app/utils/DMCAList.js b/src/app/utils/DMCAList.js
index 8e270d9bd2214f15ad226a313bff4d0b287bc6dc..0f70d32e30b45a5cecae7ab0262f39b045f889a4 100644
--- a/src/app/utils/DMCAList.js
+++ b/src/app/utils/DMCAList.js
@@ -44,4 +44,10 @@ export default `
/photography/@elvinanurhaliza/photohraphy-dewy-flowers
/photography/@elvinanurhaliza/spider-finepix-s4800-reptiles-etc
/entertainment/@seanfrederic/feature-film-loco-i-m-a-producer-on-starts-filming-soon
-`.trim().split('\n');
+/cryptocurrency/@kriptonoob/palm-beach-confidential-report-cindicator-125
+/crypto/@medicbtom/palm-beach-confidential-released-their-monthly-pick
+/news/@vaerospace/fire-and-fury-pdf-direct-download-from-ipfs-a-great-giggle
+/steemshorts/@mianusman/mianusman-contest-steemshort-1-illustration-short-story-and-even-shorter-illustration
+`
+ .trim()
+ .split('\n');
diff --git a/src/app/utils/DMCAUserList.js b/src/app/utils/DMCAUserList.js
index 9bbe44616875c6fbef3396d9a29383e1e5c9ab3b..85bc4e62ddc464c37300d9c8e873a6bbec74528d 100644
--- a/src/app/utils/DMCAUserList.js
+++ b/src/app/utils/DMCAUserList.js
@@ -3,6 +3,8 @@ spaces
the-gaming-llama
cmgsteems
iamgod
-`.trim().split('\n');
+`
+ .trim()
+ .split('\n');
export default list;
diff --git a/src/app/utils/DomUtils.js b/src/app/utils/DomUtils.js
index 36021a826f944fda05cf3feafd5ee76ae8b19d11..4a5e99f490434f7e2c661c279dad5038afe8d55e 100644
--- a/src/app/utils/DomUtils.js
+++ b/src/app/utils/DomUtils.js
@@ -1,5 +1,10 @@
export function findParent(el, class_name) {
- if (el.className && el.className.indexOf && el.className.indexOf(class_name) !== -1) return el;
+ if (
+ el.className &&
+ el.className.indexOf &&
+ el.className.indexOf(class_name) !== -1
+ )
+ return el;
if (el.parentNode) return findParent(el.parentNode, class_name);
return null;
}
diff --git a/src/app/utils/ExtractContent.js b/src/app/utils/ExtractContent.js
index f972c08955e9691bf34f6f83c06f402edbc709cf..c8e07e19fe036b41f517273ed169020b229808d8 100644
--- a/src/app/utils/ExtractContent.js
+++ b/src/app/utils/ExtractContent.js
@@ -1,11 +1,11 @@
-import remarkableStripper from 'app/utils/RemarkableStripper'
-import links from 'app/utils/Links'
-import sanitize from 'sanitize-html'
-import {htmlDecode} from 'app/utils/Html'
-import HtmlReady from 'shared/HtmlReady'
-import Remarkable from 'remarkable'
+import remarkableStripper from 'app/utils/RemarkableStripper';
+import links from 'app/utils/Links';
+import sanitize from 'sanitize-html';
+import { htmlDecode } from 'app/utils/Html';
+import HtmlReady from 'shared/HtmlReady';
+import Remarkable from 'remarkable';
-const remarkable = new Remarkable({ html: true, linkify: false })
+const remarkable = new Remarkable({ html: true, linkify: false });
export default function extractContent(get, content) {
const {
@@ -18,7 +18,7 @@ export default function extractContent(get, content) {
title,
created,
net_rshares,
- children
+ children,
} = get(
content,
'author',
@@ -36,69 +36,83 @@ export default function extractContent(get, content) {
let link = `/@${author}/${permlink}`;
if (category) link = `/${category}${link}`;
const body = get(content, 'body');
- let jsonMetadata = {}
- let image_link
+ let jsonMetadata = {};
+ let image_link;
try {
- jsonMetadata = JSON.parse(json_metadata)
- if(typeof jsonMetadata == 'string') {
+ jsonMetadata = JSON.parse(json_metadata);
+ if (typeof jsonMetadata == 'string') {
// At least one case where jsonMetadata was double-encoded: #895
- jsonMetadata = JSON.parse(jsonMetadata)
+ jsonMetadata = JSON.parse(jsonMetadata);
}
// First, attempt to find an image url in the json metadata
- if(jsonMetadata) {
- if(jsonMetadata.image && Array.isArray(jsonMetadata.image)) {
- [image_link] = jsonMetadata.image
+ if (jsonMetadata) {
+ if (jsonMetadata.image && Array.isArray(jsonMetadata.image)) {
+ [image_link] = jsonMetadata.image;
}
}
- } catch(error) {
+ } catch (error) {
// console.error('Invalid json metadata string', json_metadata, 'in post', author, permlink);
}
// If nothing found in json metadata, parse body and check images/links
- if(!image_link) {
- let rtags
+ if (!image_link) {
+ let rtags;
{
- const isHtml = /^([\S\s]*)<\/html>$/.test(body)
- const htmlText = isHtml ? body : remarkable.render(body.replace(/|$)/g, '(html comment removed: $1)'))
- rtags = HtmlReady(htmlText, {mutate: false})
+ const isHtml = /^([\S\s]*)<\/html>$/.test(body);
+ const htmlText = isHtml
+ ? body
+ : remarkable.render(
+ body.replace(
+ /|$)/g,
+ '(html comment removed: $1)'
+ )
+ );
+ rtags = HtmlReady(htmlText, { mutate: false });
}
- [image_link] = Array.from(rtags.images)
+ [image_link] = Array.from(rtags.images);
}
// Was causing broken thumnails. IPFS was not finding images uploaded to another server until a restart.
// if(config.ipfs_prefix && image_link) // allow localhost nodes to see ipfs images
// image_link = image_link.replace(links.ipfsPrefix, config.ipfs_prefix)
- let desc
- let desc_complete = false
- if(!desc) {
+ let desc;
+ let desc_complete = false;
+ if (!desc) {
// Short description.
// Remove bold and header, etc.
// Stripping removes links with titles (so we got the links above)..
// Remove block quotes if detected at beginning of comment preview if comment has a parent
- const body2 = remarkableStripper.render(get(content, 'depth') > 1 ? body.replace(/(^(\n|\r|\s)*)>([\s\S]*?).*\s*/g, '') : body);
- desc = sanitize(body2, {allowedTags: []})// remove all html, leaving text
- desc = htmlDecode(desc)
+ const body2 = remarkableStripper.render(
+ get(content, 'depth') > 1
+ ? body.replace(/(^(\n|\r|\s)*)>([\s\S]*?).*\s*/g, '')
+ : body
+ );
+ desc = sanitize(body2, { allowedTags: [] }); // remove all html, leaving text
+ desc = htmlDecode(desc);
// Strip any raw URLs from preview text
desc = desc.replace(/https?:\/\/[^\s]+/g, '');
// Grab only the first line (not working as expected. does rendering/sanitizing strip newlines?)
- desc = desc.trim().split("\n")[0];
+ desc = desc.trim().split('\n')[0];
- if(desc.length > 140) {
- desc = desc.substring(0, 140).trim();
+ if (desc.length > 140) {
+ desc = desc.substring(0, 140).trim();
- const dotSpace = desc.lastIndexOf('. ')
- if(dotSpace > 80 && !get(content, 'depth') > 1) {
- desc = desc.substring(0, dotSpace + 1)
- } else {
- // Truncate, remove the last (likely partial) word (along with random punctuation), and add ellipses
- desc = desc.substring(0, 120).trim().replace(/[,!\?]?\s+[^\s]+$/, "…");
- }
+ const dotSpace = desc.lastIndexOf('. ');
+ if (dotSpace > 80 && !get(content, 'depth') > 1) {
+ desc = desc.substring(0, dotSpace + 1);
+ } else {
+ // Truncate, remove the last (likely partial) word (along with random punctuation), and add ellipses
+ desc = desc
+ .substring(0, 120)
+ .trim()
+ .replace(/[,!\?]?\s+[^\s]+$/, '…');
+ }
}
- desc_complete = body2 === desc // is the entire body in desc?
+ desc_complete = body2 === desc; // is the entire body in desc?
}
const pending_payout = get(content, 'pending_payout_value');
return {
diff --git a/src/app/utils/ExtractMeta.js b/src/app/utils/ExtractMeta.js
index e2745db514fce365c0fad199d75cf9850f814c95..0b25e6ef9d16955584b0a56f1471b7aaca8cdbee 100644
--- a/src/app/utils/ExtractMeta.js
+++ b/src/app/utils/ExtractMeta.js
@@ -1,86 +1,115 @@
import extractContent from 'app/utils/ExtractContent';
-import {objAccessor} from 'app/utils/Accessors';
+import { objAccessor } from 'app/utils/Accessors';
import normalizeProfile from 'app/utils/NormalizeProfile';
-const site_desc = 'Steemit is a social media platform where everyone gets paid for creating and curating content. It leverages a robust digital points system (Steem) for digital rewards.';
+const site_desc =
+ 'Steemit is a social media platform where everyone gets paid for creating and curating content. It leverages a robust digital points system (Steem) for digital rewards.';
function addSiteMeta(metas) {
- metas.push({title: 'Steemit'});
- metas.push({name: 'description', content: site_desc});
- metas.push({property: 'og:type', content: 'website'});
- metas.push({property: 'og:site_name', content: 'Steemit'});
- metas.push({property: 'og:title', content: 'Steemit'});
- metas.push({property: 'og:description', content: site_desc});
- metas.push({property: 'og:image', content: 'https://steemit.com/images/steemit.png'});
- metas.push({property: 'fb:app_id', content: $STM_Config.fb_app});
- metas.push({name: 'twitter:card', content: 'summary'});
- metas.push({name: 'twitter:site', content: '@steemit'});
- metas.push({name: 'twitter:title', content: '#Steemit'});
- metas.push({name: 'twitter:description', site_desc});
- metas.push({name: 'twitter:image', content: 'https://steemit.com/images/steemit.png'});
+ metas.push({ title: 'Steemit' });
+ metas.push({ name: 'description', content: site_desc });
+ metas.push({ property: 'og:type', content: 'website' });
+ metas.push({ property: 'og:site_name', content: 'Steemit' });
+ metas.push({ property: 'og:title', content: 'Steemit' });
+ metas.push({ property: 'og:description', content: site_desc });
+ metas.push({
+ property: 'og:image',
+ content: 'https://steemit.com/images/steemit.png',
+ });
+ metas.push({ property: 'fb:app_id', content: $STM_Config.fb_app });
+ metas.push({ name: 'twitter:card', content: 'summary' });
+ metas.push({ name: 'twitter:site', content: '@steemit' });
+ metas.push({ name: 'twitter:title', content: '#Steemit' });
+ metas.push({ name: 'twitter:description', site_desc });
+ metas.push({
+ name: 'twitter:image',
+ content: 'https://steemit.com/images/steemit.png',
+ });
}
export default function extractMeta(chain_data, rp) {
const metas = [];
- if (rp.username && rp.slug) { // post
+ if (rp.username && rp.slug) {
+ // post
const post = `${rp.username}/${rp.slug}`;
const content = chain_data.content[post];
- const author = chain_data.accounts[rp.username];
+ const author = chain_data.accounts[rp.username];
const profile = normalizeProfile(author);
- if (content && content.id !== '0.0.0') { // API currently returns 'false' data with id 0.0.0 for posts that do not exist
+ if (content && content.id !== '0.0.0') {
+ // API currently returns 'false' data with id 0.0.0 for posts that do not exist
const d = extractContent(objAccessor, content, false);
- const url = 'https://steemit.com' + d.link;
+ const url = 'https://steemit.com' + d.link;
const title = d.title + ' — Steemit';
- const desc = d.desc + " by " + d.author;
- const image = d.image_link || profile.profile_image
- const {category, created} = d
+ const desc = d.desc + ' by ' + d.author;
+ const image = d.image_link || profile.profile_image;
+ const { category, created } = d;
// Standard meta
- metas.push({title});
- metas.push({canonical: url});
- metas.push({name: 'description', content: desc});
+ metas.push({ title });
+ metas.push({ canonical: url });
+ metas.push({ name: 'description', content: desc });
// Open Graph data
- metas.push({property: 'og:title', content: title});
- metas.push({property: 'og:type', content: 'article'});
- metas.push({property: 'og:url', content: url});
- metas.push({property: 'og:image', content: image || 'https://steemit.com/images/steemit.png'});
- metas.push({property: 'og:description', content: desc});
- metas.push({property: 'og:site_name', content: 'Steemit'});
- metas.push({property: 'fb:app_id', content: $STM_Config.fb_app});
- metas.push({property: 'article:tag', content: category});
- metas.push({property: 'article:published_time', content: created});
+ metas.push({ name: 'og:title', content: title });
+ metas.push({ name: 'og:type', content: 'article' });
+ metas.push({ name: 'og:url', content: url });
+ metas.push({
+ name: 'og:image',
+ content: image || 'https://steemit.com/images/steemit.png',
+ });
+ metas.push({ name: 'og:description', content: desc });
+ metas.push({ name: 'og:site_name', content: 'Steemit' });
+ metas.push({ name: 'fb:app_id', content: $STM_Config.fb_app });
+ metas.push({ name: 'article:tag', content: category });
+ metas.push({
+ name: 'article:published_time',
+ content: created,
+ });
// Twitter card data
- metas.push({name: 'twitter:card', content: image ? 'summary_large_image' : 'summary'});
- metas.push({name: 'twitter:site', content: '@steemit'});
- metas.push({name: 'twitter:title', content: title});
- metas.push({name: 'twitter:description', content: desc});
- metas.push({name: 'twitter:image', content: image || 'https://steemit.com/images/steemit-twshare-2.png'});
+ metas.push({
+ name: 'twitter:card',
+ content: image ? 'summary_large_image' : 'summary',
+ });
+ metas.push({ name: 'twitter:site', content: '@steemit' });
+ metas.push({ name: 'twitter:title', content: title });
+ metas.push({ name: 'twitter:description', content: desc });
+ metas.push({
+ name: 'twitter:image',
+ content:
+ image || 'https://steemit.com/images/steemit-twshare-2.png',
+ });
} else {
addSiteMeta(metas);
}
- } else if (rp.accountname) { // user profile root
+ } else if (rp.accountname) {
+ // user profile root
const account = chain_data.accounts[rp.accountname];
- let {name, about, profile_image} = normalizeProfile(account);
- if(name == null) name = account.name;
- if(about == null) about = "Join thousands on steemit who share, post and earn rewards.";
- if(profile_image == null) profile_image = 'https://steemit.com/images/steemit-twshare-2.png';
+ let { name, about, profile_image } = normalizeProfile(account);
+ if (name == null) name = account.name;
+ if (about == null)
+ about =
+ 'Join thousands on steemit who share, post and earn rewards.';
+ if (profile_image == null)
+ profile_image = 'https://steemit.com/images/steemit-twshare-2.png';
// Set profile tags
const title = `@${account.name}`;
- const desc = `The latest posts from ${name}. Follow me at @${account.name}. ${about}`;
+ const desc = `The latest posts from ${name}. Follow me at @${
+ account.name
+ }. ${about}`;
const image = profile_image;
// Standard meta
- metas.push({name: 'description', content: desc});
+ metas.push({ name: 'description', content: desc });
// Twitter card data
- metas.push({name: 'twitter:card', content: 'summary'});
- metas.push({name: 'twitter:site', content: '@steemit'});
- metas.push({name: 'twitter:title', content: title});
- metas.push({name: 'twitter:description', content: desc});
- metas.push({name: 'twitter:image', content: image});
- } else { // site
+ metas.push({ name: 'twitter:card', content: 'summary' });
+ metas.push({ name: 'twitter:site', content: '@steemit' });
+ metas.push({ name: 'twitter:title', content: title });
+ metas.push({ name: 'twitter:description', content: desc });
+ metas.push({ name: 'twitter:image', content: image });
+ } else {
+ // site
addSiteMeta(metas);
}
return metas;
diff --git a/src/app/utils/FormatCoins.js b/src/app/utils/FormatCoins.js
index 390ed29488103e0ce726eb49dbdd30ae6263aa19..727447f9ed469458372a4a7cdc66d1b03424ce74 100644
--- a/src/app/utils/FormatCoins.js
+++ b/src/app/utils/FormatCoins.js
@@ -1,15 +1,27 @@
-import { APP_NAME, LIQUID_TOKEN, LIQUID_TOKEN_UPPERCASE, DEBT_TOKEN, DEBT_TOKEN_SHORT, CURRENCY_SIGN, VESTING_TOKEN } from 'app/client_config';
+import {
+ APP_NAME,
+ LIQUID_TOKEN,
+ LIQUID_TOKEN_UPPERCASE,
+ DEBT_TOKEN,
+ DEBT_TOKEN_SHORT,
+ CURRENCY_SIGN,
+ VESTING_TOKEN,
+} from 'app/client_config';
// TODO add comments and explanations
// TODO change name to formatCoinTypes?
// TODO make use of DEBT_TICKER etc defined in config/clietn_config
export function formatCoins(string) {
- // return null or undefined if string is not provided
- if(!string) return string
- // TODO use .to:owerCase() ? for string normalisation
- string = string.replace('SBD', DEBT_TOKEN_SHORT ).replace('SD', DEBT_TOKEN_SHORT)
- .replace('Steem Power', VESTING_TOKEN).replace('STEEM POWER', VESTING_TOKEN)
- .replace('Steem', LIQUID_TOKEN).replace('STEEM', LIQUID_TOKEN_UPPERCASE)
- .replace('$', CURRENCY_SIGN)
- return string
+ // return null or undefined if string is not provided
+ if (!string) return string;
+ // TODO use .to:owerCase() ? for string normalisation
+ string = string
+ .replace('SBD', DEBT_TOKEN_SHORT)
+ .replace('SD', DEBT_TOKEN_SHORT)
+ .replace('Steem Power', VESTING_TOKEN)
+ .replace('STEEM POWER', VESTING_TOKEN)
+ .replace('Steem', LIQUID_TOKEN)
+ .replace('STEEM', LIQUID_TOKEN_UPPERCASE)
+ .replace('$', CURRENCY_SIGN);
+ return string;
}
diff --git a/src/app/utils/FormatDecimal.test.js b/src/app/utils/FormatDecimal.test.js
index 044ff01383a4b6bdb4dbd18e407b4d3f5da5defb..7782f7cee7b6cb324627b7d0bd137d49ca496efd 100644
--- a/src/app/utils/FormatDecimal.test.js
+++ b/src/app/utils/FormatDecimal.test.js
@@ -1,9 +1,4 @@
-/*global describe, it, before, beforeEach, after, afterEach */
-
-import chai, {expect} from 'chai';
-import dirtyChai from 'dirty-chai';
-import {formatDecimal} from './ParsersAndFormatters';
-chai.use(dirtyChai);
+import { formatDecimal } from './ParsersAndFormatters';
describe('formatDecimal', () => {
it('should format decimals', () => {
@@ -13,11 +8,11 @@ describe('formatDecimal', () => {
['102', '102.00'],
[1000.12, '1,000.12'],
[100000, '100,000.00'],
- [1000000000000.00, '1,000,000,000,000.00'],
+ [1000000000000.0, '1,000,000,000,000.00'],
[-1000, '-1,000.00'],
];
test_cases.forEach(v => {
- expect(formatDecimal(v[0]).join('')).to.equal(v[1]);
+ expect(formatDecimal(v[0]).join('')).toBe(v[1]);
});
});
});
diff --git a/src/app/utils/FrontendLogger.js b/src/app/utils/FrontendLogger.js
new file mode 100644
index 0000000000000000000000000000000000000000..d1cb163249a394a5828bf45d63e6f68c236d183c
--- /dev/null
+++ b/src/app/utils/FrontendLogger.js
@@ -0,0 +1,45 @@
+import { serverApiRecordEvent } from 'app/utils/ServerApiClient';
+
+/**
+ * Handles window error events by logging to overseer.
+ *
+ * This function relies on these globals:
+ * - process.env.VERSION
+ * - window.location.href
+ *
+ * @param {ErrorEvent} event
+ */
+export default function frontendLogger(event) {
+ if (window.$STM_csrf) {
+ const report = formatEventReport(
+ event,
+ window.location.href,
+ process.env.VERSION
+ );
+ serverApiRecordEvent('client_error', report);
+ }
+}
+
+/**
+ * Format a browser error event report
+ *
+ * @param {ErrorEvent} event
+ * @param {string} href
+ * @param {string} version
+ *
+ * @return {object}
+ */
+export function formatEventReport(event, href, version) {
+ const trace =
+ typeof event.error === 'object' &&
+ event.error !== null &&
+ typeof event.error.stack === 'string'
+ ? event.error.stack
+ : false;
+ return {
+ trace,
+ message: event.message,
+ href,
+ version,
+ };
+}
diff --git a/src/app/utils/FrontendLogger.test.js b/src/app/utils/FrontendLogger.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..8b62ffa0b56b7f29dae8e987a35da01a2fb3dad6
--- /dev/null
+++ b/src/app/utils/FrontendLogger.test.js
@@ -0,0 +1,35 @@
+import { formatEventReport } from './FrontendLogger';
+
+describe('formatEventReport', () => {
+ it('should handle modern firefox/chrome errors with a stacktrace', () => {
+ const modernErrorEvent = {
+ error: {
+ stack: 'i am a stacktrace',
+ },
+ message: 'i am a message',
+ };
+
+ const logged = formatEventReport(
+ modernErrorEvent,
+ 'location',
+ 'version'
+ );
+
+ expect(logged.trace).toEqual('i am a stacktrace');
+ expect(logged.message).toEqual('i am a message');
+ expect(logged.version).toEqual('version');
+ expect(logged.href).toEqual('location');
+ });
+ it('should handle errors from browsers that do not provide a stack trace', () => {
+ const lameErrorEvent = {
+ message: 'i am an old error',
+ };
+
+ const logged = formatEventReport(lameErrorEvent, 'location', 'version');
+
+ expect(logged.trace).toEqual(false);
+ expect(logged.message).toEqual('i am an old error');
+ expect(logged.version).toEqual('version');
+ expect(logged.href).toEqual('location');
+ });
+});
diff --git a/src/app/utils/Html.js b/src/app/utils/Html.js
index 7ebb8abae9b5c72a4e8c667549926b075fb0e8ad..4ecc1fd92cbb64c3015648a5594151152b795f47 100644
--- a/src/app/utils/Html.js
+++ b/src/app/utils/Html.js
@@ -1,8 +1,8 @@
-
-export const htmlDecode = txt => txt.replace(/&[a-z]+;/g, ch => {
- const char = htmlCharMap[ch.substring(1, ch.length - 1)]
- return char ? char : ch
-})
+export const htmlDecode = txt =>
+ txt.replace(/&[a-z]+;/g, ch => {
+ const char = htmlCharMap[ch.substring(1, ch.length - 1)];
+ return char ? char : ch;
+ });
const htmlCharMap = {
amp: '&',
@@ -17,5 +17,5 @@ const htmlCharMap = {
trade: '™',
hellip: '…',
pound: '£',
- copy: ''
-}
+ copy: '',
+};
diff --git a/src/app/utils/ImageUserBlockList.js b/src/app/utils/ImageUserBlockList.js
index a439d57b4999fbb735c6c7e6b24a6a08b3c58139..12a8c911e204f4116aef16cf4c461880f00ff1f0 100644
--- a/src/app/utils/ImageUserBlockList.js
+++ b/src/app/utils/ImageUserBlockList.js
@@ -1,5 +1,7 @@
const list = `
iamgod
-`.trim().split('\n');
+`
+ .trim()
+ .split('\n');
export default list;
diff --git a/src/app/utils/JsPlugins.js b/src/app/utils/JsPlugins.js
index 3009b2a359b1e6bded46c4f0a31147afd0165bc7..b5d95e7c15998092ec7222fe30df4606eb20d525 100644
--- a/src/app/utils/JsPlugins.js
+++ b/src/app/utils/JsPlugins.js
@@ -1,38 +1,30 @@
// 3rd party plugins
export default function init(config) {
-
if (config.google_analytics_id) {
- (function (i, s, o, g, r, a, m) {
+ (function(i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
- i[r] = i[r] || function () {
- (i[r].q = i[r].q || []).push(arguments)
- }, i[r].l = 1 * new Date();
- a = s.createElement(o),
- m = s.getElementsByTagName(o)[0];
+ (i[r] =
+ i[r] ||
+ function() {
+ (i[r].q = i[r].q || []).push(arguments);
+ }),
+ (i[r].l = 1 * new Date());
+ (a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
- m.parentNode.insertBefore(a, m)
- })(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
- ga('create', config.google_analytics_id, 'auto');
- }
-
- if (config.facebook_app_id) {
- window.fbAsyncInit = function () {
- FB.init({
- appId: config.facebook_app_id,
- xfbml: true,
- version: 'v2.6'
- });
- };
- (function (d, s, id) {
- var js, fjs = d.getElementsByTagName(s)[0];
- if (d.getElementById(id)) {return;}
- js = d.createElement(s);
- js.id = id;
- js.src = "//connect.facebook.net/en_US/sdk.js";
- fjs.parentNode.insertBefore(js, fjs);
- }(document, 'script', 'facebook-jssdk'));
+ m.parentNode.insertBefore(a, m);
+ })(
+ window,
+ document,
+ 'script',
+ 'https://www.google-analytics.com/analytics.js',
+ 'ga'
+ );
+ ga('create', {
+ trackingId: config.google_analytics_id,
+ cookieDomain: 'auto',
+ sampleRate: 5,
+ });
}
-
}
diff --git a/src/app/utils/Links.js b/src/app/utils/Links.js
index 6b39fe6edda406336e5ecd8d6e341dc3ef2f82c5..ce1137a2f0b14223a8fda6680dfae06b47edc39f 100644
--- a/src/app/utils/Links.js
+++ b/src/app/utils/Links.js
@@ -1,24 +1,38 @@
+import { PARAM_VIEW_MODE, VIEW_MODE_WHISTLE } from '../../shared/constants';
-const urlChar = '[^\\s"<>\\]\\[\\(\\)]'
-const urlCharEnd = urlChar.replace(/\]$/, '.,\']') // insert bad chars to end on
-const imagePath = '(?:(?:\\.(?:tiff?|jpe?g|gif|png|svg|ico)|ipfs/[a-z\\d]{40,}))'
-const domainPath = '(?:[-a-zA-Z0-9\\._]*[-a-zA-Z0-9])'
-const urlChars = '(?:' + urlChar + '*' + urlCharEnd + ')?'
+const urlChar = '[^\\s"<>\\]\\[\\(\\)]';
+const urlCharEnd = urlChar.replace(/\]$/, ".,']"); // insert bad chars to end on
+const imagePath =
+ '(?:(?:\\.(?:tiff?|jpe?g|gif|png|svg|ico)|ipfs/[a-z\\d]{40,}))';
+const domainPath = '(?:[-a-zA-Z0-9\\._]*[-a-zA-Z0-9])';
+const urlChars = '(?:' + urlChar + '*' + urlCharEnd + ')?';
-const urlSet = ({domain = domainPath, path} = {}) => {
- // urlChars is everything but html or markdown stop chars
- return `https?:\/\/${domain}(?::\\d{2,5})?(?:[/\\?#]${urlChars}${path ? path : ''})${path ? '' : '?'}`
-}
+const urlSet = ({ domain = domainPath, path } = {}) => {
+ // urlChars is everything but html or markdown stop chars
+ return `https?:\/\/${domain}(?::\\d{2,5})?(?:[/\\?#]${urlChars}${
+ path ? path : ''
+ })${path ? '' : '?'}`;
+};
/**
Unless your using a 'g' (glob) flag you can store and re-use your regular expression. Use the cache below. If your using a glob (for example: replace all), the regex object becomes stateful and continues where it left off when called with the same string so naturally the regexp object can't be cached for long.
*/
-export const any = (flags = 'i') => new RegExp(urlSet(), flags)
-export const local = (flags = 'i') => new RegExp(urlSet({domain: '(?:localhost|(?:.*\\.)?steemit.com)'}), flags)
-export const remote = (flags = 'i') => new RegExp(urlSet({domain: `(?!localhost|(?:.*\\.)?steemit.com)${domainPath}`}), flags)
-export const youTube = (flags = 'i') => new RegExp(urlSet({domain: '(?:(?:.*\.)?youtube.com|youtu.be)'}), flags)
-export const image = (flags = 'i') => new RegExp(urlSet({path: imagePath}), flags)
-export const imageFile = (flags = 'i') => new RegExp(imagePath, flags)
+export const any = (flags = 'i') => new RegExp(urlSet(), flags);
+export const local = (flags = 'i') =>
+ new RegExp(
+ urlSet({ domain: '(?:localhost|(?:.*\\.)?steemit.com)' }),
+ flags
+ );
+export const remote = (flags = 'i') =>
+ new RegExp(
+ urlSet({ domain: `(?!localhost|(?:.*\\.)?steemit.com)${domainPath}` }),
+ flags
+ );
+export const youTube = (flags = 'i') =>
+ new RegExp(urlSet({ domain: '(?:(?:.*.)?youtube.com|youtu.be)' }), flags);
+export const image = (flags = 'i') =>
+ new RegExp(urlSet({ path: imagePath }), flags);
+export const imageFile = (flags = 'i') => new RegExp(imagePath, flags);
// export const nonImage = (flags = 'i') => new RegExp(urlSet({path: '!' + imageFile}), flags)
// export const markDownImageRegExp = (flags = 'i') => new RegExp('\!\[[\w\s]*\]\(([^\)]+)\)', flags);
@@ -33,7 +47,66 @@ export default {
vimeoId: /(?:vimeo.com\/|player.vimeo.com\/video\/)([0-9]+)/,
// simpleLink: new RegExp(`(.*)<\/a>`, 'ig'),
ipfsPrefix: /(https?:\/\/.*)?\/ipfs/i,
-}
+};
+
+//TODO: possible this should go somewhere else.
+/**
+ * Returns a new object extended from outputParams with [key] == inputParams[key] if the value is in allowedValues
+ * @param outputParams
+ * @param inputParams
+ * @param key
+ * @param allowedValues
+ * @returns {*}
+ */
+export const addToParams = (outputParams, inputParams, key, allowedValues) => {
+ const respParams = Object.assign({}, outputParams);
+ if (inputParams[key] && allowedValues.indexOf(inputParams[key]) > -1) {
+ respParams[key] = inputParams[key];
+ }
+ return respParams;
+};
+
+//TODO: possible this should go somewhere else.
+export const makeParams = (params, prefix) => {
+ let paramsList = [];
+ if (params.constructor === Array) {
+ paramsList = params;
+ } else {
+ Object.entries(params).forEach(([key, value]) => {
+ paramsList.push(`${key}=${value}`);
+ });
+ }
+ if (paramsList.length > 0) {
+ return (
+ (prefix !== false
+ ? typeof prefix === 'string' ? prefix : '?'
+ : '') + paramsList.join('&')
+ );
+ }
+ return '';
+};
+
+/**
+ *
+ * @param {string} search - window.location.search formatted string (may omit '?')
+ * @returns {string}
+ */
+export const determineViewMode = search => {
+ const searchList =
+ search.indexOf('?') === 0
+ ? search.substr(1).split('&')
+ : search.split('&');
+ for (let i = 0; i < searchList.length; i++) {
+ if (searchList[i].indexOf(PARAM_VIEW_MODE) === 0) {
+ if (searchList[i] == PARAM_VIEW_MODE + '=' + VIEW_MODE_WHISTLE) {
+ //we only want to support known view modes.
+ return VIEW_MODE_WHISTLE;
+ }
+ return '';
+ }
+ }
+ return '';
+};
// Original regex
// const urlRegex = '^(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$';
diff --git a/src/app/utils/Links.test.js b/src/app/utils/Links.test.js
index 4c84e170216783c84960755f4dd34184ecaa1c7c..b5aff96ad901da81b91330894c2b6b44eef97695 100644
--- a/src/app/utils/Links.test.js
+++ b/src/app/utils/Links.test.js
@@ -1,110 +1,310 @@
-
-import assert from 'assert'
-import secureRandom from 'secure-random'
-import links, * as linksRe from 'app/utils/Links'
+import assert from 'assert';
+import secureRandom from 'secure-random';
+import links, * as linksRe from 'app/utils/Links';
+import { PARAM_VIEW_MODE, VIEW_MODE_WHISTLE } from '../../shared/constants';
describe('Links', () => {
it('all', () => {
- match(linksRe.any(), 'https://example.com/wiki/Poe\'s_law', 'https://example.com/wiki/Poe\'s_law')
- match(linksRe.any(), 'https://example.com\'', 'https://example.com')
- match(linksRe.any(), '"https://example.com', 'https://example.com')
- match(linksRe.any(), 'https://example.com\"', 'https://example.com')
- match(linksRe.any(), 'https://example.com\'', 'https://example.com')
- match(linksRe.any(), 'https://example.com<', 'https://example.com')
- match(linksRe.any(), 'https://example.com>', 'https://example.com')
- match(linksRe.any(), 'https://example.com\n', 'https://example.com')
- match(linksRe.any(), ' https://example.com ', 'https://example.com')
- match(linksRe.any(), 'https://example.com ', 'https://example.com')
- match(linksRe.any(), 'https://example.com.', 'https://example.com')
- match(linksRe.any(), 'https://example.com/page.', 'https://example.com/page')
- match(linksRe.any(), 'https://example.com,', 'https://example.com')
- match(linksRe.any(), 'https://example.com/page,', 'https://example.com/page')
- })
+ match(
+ linksRe.any(),
+ "https://example.com/wiki/Poe's_law",
+ "https://example.com/wiki/Poe's_law"
+ );
+ match(linksRe.any(), "https://example.com'", 'https://example.com');
+ match(linksRe.any(), '"https://example.com', 'https://example.com');
+ match(linksRe.any(), 'https://example.com"', 'https://example.com');
+ match(linksRe.any(), "https://example.com'", 'https://example.com');
+ match(linksRe.any(), 'https://example.com<', 'https://example.com');
+ match(linksRe.any(), 'https://example.com>', 'https://example.com');
+ match(linksRe.any(), 'https://example.com\n', 'https://example.com');
+ match(linksRe.any(), ' https://example.com ', 'https://example.com');
+ match(linksRe.any(), 'https://example.com ', 'https://example.com');
+ match(linksRe.any(), 'https://example.com.', 'https://example.com');
+ match(
+ linksRe.any(),
+ 'https://example.com/page.',
+ 'https://example.com/page'
+ );
+ match(linksRe.any(), 'https://example.com,', 'https://example.com');
+ match(
+ linksRe.any(),
+ 'https://example.com/page,',
+ 'https://example.com/page'
+ );
+ });
it('multiple matches', () => {
- const all = linksRe.any('ig')
- let match = all.exec('\nhttps://example.com/1\nhttps://example.com/2')
- assert.equal(match[0], 'https://example.com/1')
- match = all.exec('https://example.com/1 https://example.com/2')
- assert.equal(match[0], 'https://example.com/2')
- })
+ const all = linksRe.any('ig');
+ let match = all.exec('\nhttps://example.com/1\nhttps://example.com/2');
+ assert.equal(match[0], 'https://example.com/1');
+ match = all.exec('https://example.com/1 https://example.com/2');
+ assert.equal(match[0], 'https://example.com/2');
+ });
it('by domain', () => {
- const locals = ['https://localhost/', 'http://steemit.com', 'http://steemit.com/group']
- match(linksRe.local(), locals)
- matchNot(linksRe.remote(), locals)
+ const locals = [
+ 'https://localhost/',
+ 'http://steemit.com',
+ 'http://steemit.com/group',
+ ];
+ match(linksRe.local(), locals);
+ matchNot(linksRe.remote(), locals);
- const remotes = ['https://example.com/', 'http://abc.co']
- match(linksRe.remote(), remotes)
- matchNot(linksRe.local(), remotes)
+ const remotes = ['https://example.com/', 'http://abc.co'];
+ match(linksRe.remote(), remotes);
+ matchNot(linksRe.local(), remotes);
// match(linksRe({external: false}), largeData + 'https://steemit.com2/next', 'https://steemit.com2/next')
- })
+ });
it('by image', () => {
- match(linksRe.image(), 'https://example.com/a.jpeg')
- match(linksRe.image(), 'https://example.com/a/b.jpeg')
- match(linksRe.image(), '', 'https://example.com/img2/nehoshtanit.jpg')
- match(linksRe.image(), ' {
+ it('creates an empty string when there are no params', () => {
+ assert(linksRe.makeParams([]) === '', 'not empty on array');
+ assert(linksRe.makeParams({}) === '', 'not empty on object');
+ assert(
+ linksRe.makeParams({}, false) === '',
+ 'not empty on object with prefix false'
+ );
+ assert(
+ linksRe.makeParams([], false) === '',
+ 'not empty on array with prefix false'
+ );
+ assert(
+ linksRe.makeParams([], '?') === '',
+ 'not empty on array with prefix string'
+ );
+ assert(
+ linksRe.makeParams({}, '?') === '',
+ 'not empty on object with prefix string'
+ );
+ });
+ it('creates the correct string when passed an array', () => {
+ assert(
+ linksRe.makeParams(['bop=boop', 'troll=bridge']) ===
+ '?bop=boop&troll=bridge',
+ 'incorrect string with'
+ );
+ assert(
+ linksRe.makeParams(['bop=boop', 'troll=bridge'], false) ===
+ 'bop=boop&troll=bridge',
+ 'incorrect string with prefix false'
+ );
+ assert(
+ linksRe.makeParams(['bop=boop', 'troll=bridge'], '&') ===
+ '&bop=boop&troll=bridge',
+ 'incorrect string with prefix &'
+ );
+ });
+ it('creates the correct string when passed an object', () => {
+ assert(
+ linksRe.makeParams({ bop: 'boop', troll: 'bridge' }) ===
+ '?bop=boop&troll=bridge',
+ 'incorrect string'
+ );
+ assert(
+ linksRe.makeParams({ bop: 'boop', troll: 'bridge' }, false) ===
+ 'bop=boop&troll=bridge',
+ 'incorrect string with prefix false'
+ );
+ assert(
+ linksRe.makeParams({ bop: 'boop', troll: 'bridge' }, '&') ===
+ '&bop=boop&troll=bridge',
+ 'incorrect string with prefix &'
+ );
+ });
+});
+
+describe('determineViewMode', () => {
+ it('returns empty string when no parameter in search', () => {
+ assert(
+ linksRe.determineViewMode('') === '',
+ linksRe.determineViewMode('') + 'not empty on empty string'
+ );
+ assert(
+ linksRe.determineViewMode('?afs=asdf') === '',
+ 'not empty on incorrect parameter'
+ );
+ assert(
+ linksRe.determineViewMode('?afs=asdf&apple=sauce') === '',
+ 'not empty on incorrect parameter'
+ );
+ });
+
+ it('returns empty string when unrecognized value for parameter in search', () => {
+ assert(
+ linksRe.determineViewMode(`?${PARAM_VIEW_MODE}=asd`) === '',
+ 'not empty on incorrect parameter value'
+ );
+ assert(
+ linksRe.determineViewMode(
+ `?${PARAM_VIEW_MODE}=${VIEW_MODE_WHISTLE}1`
+ ) === '',
+ 'not empty on incorrect parameter value'
+ );
+ assert(
+ linksRe.determineViewMode(
+ `?${PARAM_VIEW_MODE}=asdf&apple=sauce`
+ ) === '',
+ 'not empty on incorrect parameter value'
+ );
+ assert(
+ linksRe.determineViewMode(
+ `?apple=sauce&${PARAM_VIEW_MODE}=asdf`
+ ) === '',
+ 'not empty on incorrect parameter value'
+ );
+ });
+ it('returns correct value when recognized value for parameter in search', () => {
+ assert(
+ linksRe.determineViewMode(
+ `?${PARAM_VIEW_MODE}=${VIEW_MODE_WHISTLE}`
+ ) === VIEW_MODE_WHISTLE,
+ 'wrong response on correct parameter'
+ );
+ assert(
+ linksRe.determineViewMode(
+ `?${PARAM_VIEW_MODE}=${VIEW_MODE_WHISTLE}&apple=sauce`
+ ) === VIEW_MODE_WHISTLE,
+ 'wrong response on correct parameter'
+ );
+ assert(
+ linksRe.determineViewMode(
+ `?apple=sauce&${PARAM_VIEW_MODE}=${VIEW_MODE_WHISTLE}`
+ ) === VIEW_MODE_WHISTLE,
+ 'wrong response on correct parameter'
+ );
+ });
+});
// 1st in the browser it is very expensive to re-create a regular expression many times, however, in nodejs is is very in-expensive (it is as if it is caching it).
describe('Performance', () => {
- const largeData = secureRandom.randomBuffer(1024 * 10).toString('hex')
+ const largeData = secureRandom.randomBuffer(1024 * 10).toString('hex');
it('any, ' + largeData.length + ' bytes x 10,000', () => {
for (let i = 0; i < 10000; i++) {
- const match = (largeData + 'https://example.com').match(linksRe.any())
- assert(match, 'no match')
- assert(match[0] === 'https://example.com', 'no match')
+ const match = (largeData + 'https://example.com').match(
+ linksRe.any()
+ );
+ assert(match, 'no match');
+ assert(match[0] === 'https://example.com', 'no match');
}
- })
+ });
it('image (large), ' + largeData.length + ' bytes x 10,000', () => {
for (let i = 0; i < 10000; i++) {
- matchNot(linksRe.image(), 'https://lh3.googleusercontent.com/OehcduRZPcVIX_2tlOKgYHADtBvorTfL4JtjfGAPWZyiiI9p_g2ZKEUKfuv3By-aiVfirXaYvEsViJEbxts6IeVYqidnpgkkkXAe0Q79_ARXX6CU5hBK2sZaHKa20U3jBzYbMxT-OVNX8-JYf-GYa2geUQa6pVpUDY35iaiiNBObF-TMIUOqm0P61gCdukTFwLgld2BBlxoVNNt_w6VglYHJP0W4izVNkEu7ugrU-qf2Iw9hb22SGIFNpbzL_ldomDMthIuYfKSYGsqe2ClvNKRz-_vVCQr7ggRXra16uQOdUUv5IVnkK67p9yR8ioajJ4tiGdzazYVow46pbeZ76i9_NoEYnOEX2_a7niofnC5BgAjoQEeoes1cMWVM7V8ZSexBA-cxmi0EVLds4RBkInvaUZjVL7h3oJ5I19GugPTzlyVyYtkf1ej6LNttkagqHgMck87UQGvCbwDX9ECTngffwQPYZlZKnthW0DlkFGgHN8T9uqEpl-3ki50gTa6gC0Q16mEeDRKZe7_g5Sw52OjMsfWxmBBWWMSHzlQKKAIKMKKaD6Td0O_zpiXXp7Fyl7z_iESvCpOAUAIKnyJyF_Y0UYktEmw=w2066-h1377-no')
+ matchNot(
+ linksRe.image(),
+ 'https://lh3.googleusercontent.com/OehcduRZPcVIX_2tlOKgYHADtBvorTfL4JtjfGAPWZyiiI9p_g2ZKEUKfuv3By-aiVfirXaYvEsViJEbxts6IeVYqidnpgkkkXAe0Q79_ARXX6CU5hBK2sZaHKa20U3jBzYbMxT-OVNX8-JYf-GYa2geUQa6pVpUDY35iaiiNBObF-TMIUOqm0P61gCdukTFwLgld2BBlxoVNNt_w6VglYHJP0W4izVNkEu7ugrU-qf2Iw9hb22SGIFNpbzL_ldomDMthIuYfKSYGsqe2ClvNKRz-_vVCQr7ggRXra16uQOdUUv5IVnkK67p9yR8ioajJ4tiGdzazYVow46pbeZ76i9_NoEYnOEX2_a7niofnC5BgAjoQEeoes1cMWVM7V8ZSexBA-cxmi0EVLds4RBkInvaUZjVL7h3oJ5I19GugPTzlyVyYtkf1ej6LNttkagqHgMck87UQGvCbwDX9ECTngffwQPYZlZKnthW0DlkFGgHN8T9uqEpl-3ki50gTa6gC0Q16mEeDRKZe7_g5Sw52OjMsfWxmBBWWMSHzlQKKAIKMKKaD6Td0O_zpiXXp7Fyl7z_iESvCpOAUAIKnyJyF_Y0UYktEmw=w2066-h1377-no'
+ );
}
- })
+ });
it('image, ' + largeData.length + ' bytes x 10,000', () => {
for (let i = 0; i < 10000; i++) {
- const match = (largeData + 'https://example.com/img.jpeg').match(linksRe.image())
- assert(match, 'no match')
- assert(match[0] === 'https://example.com/img.jpeg', 'no match')
+ const match = (largeData + 'https://example.com/img.jpeg').match(
+ linksRe.image()
+ );
+ assert(match, 'no match');
+ assert(match[0] === 'https://example.com/img.jpeg', 'no match');
}
- })
+ });
it('remote, ' + largeData.length + ' bytes x 10,000', () => {
for (let i = 0; i < 10000; i++) {
- const match = (largeData + 'https://example.com').match(linksRe.remote())
- assert(match, 'no match')
- assert(match[0] === 'https://example.com', 'no match')
+ const match = (largeData + 'https://example.com').match(
+ linksRe.remote()
+ );
+ assert(match, 'no match');
+ assert(match[0] === 'https://example.com', 'no match');
}
- })
+ });
it('youTube', () => {
- match(linksRe.youTube(), 'https://youtu.be/xG7ajrbj4zs?t=7s')
- match(linksRe.youTube(), 'https://www.youtube.com/watch?v=xG7ajrbj4zs&t=14s')
- match(linksRe.youTube(), 'https://www.youtube.com/watch?v=xG7ajrbj4zs&feature=youtu.be&t=14s')
- })
+ match(linksRe.youTube(), 'https://youtu.be/xG7ajrbj4zs?t=7s');
+ match(
+ linksRe.youTube(),
+ 'https://www.youtube.com/watch?v=xG7ajrbj4zs&t=14s'
+ );
+ match(
+ linksRe.youTube(),
+ 'https://www.youtube.com/watch?v=xG7ajrbj4zs&feature=youtu.be&t=14s'
+ );
+ });
it('youTubeId', () => {
- match(links.youTubeId, 'https://youtu.be/xG7ajrbj4zs?t=7s', 'xG7ajrbj4zs', 1)
- match(links.youTubeId, 'https://www.youtube.com/watch?v=xG7ajrbj4zs&t=14s', 'xG7ajrbj4zs', 1)
- match(links.youTubeId, 'https://www.youtube.com/watch?v=xG7ajrbj4zs&feature=youtu.be&t=14s', 'xG7ajrbj4zs', 1)
- })
-})
+ match(
+ links.youTubeId,
+ 'https://youtu.be/xG7ajrbj4zs?t=7s',
+ 'xG7ajrbj4zs',
+ 1
+ );
+ match(
+ links.youTubeId,
+ 'https://www.youtube.com/watch?v=xG7ajrbj4zs&t=14s',
+ 'xG7ajrbj4zs',
+ 1
+ );
+ match(
+ links.youTubeId,
+ 'https://www.youtube.com/watch?v=xG7ajrbj4zs&feature=youtu.be&t=14s',
+ 'xG7ajrbj4zs',
+ 1
+ );
+ });
+});
-const match = (...args) => compare(true, ...args)
-const matchNot = (...args) => compare(false, ...args)
+const match = (...args) => compare(true, ...args);
+const matchNot = (...args) => compare(false, ...args);
const compare = (matching, re, input, output = input, pos = 0) => {
if (Array.isArray(input)) {
for (let i = 0; i < input.length; i++)
- compare(matching, re, input[i], output[i])
- return
+ compare(matching, re, input[i], output[i]);
+ return;
}
// console.log('compare, input', input)
// console.log('compare, output', output)
- const m = input.match(re)
- if(matching) {
- assert(m, `No match --> ${input} --> output ${output} --> using ${re.toString()}`)
+ const m = input.match(re);
+ if (matching) {
+ assert(
+ m,
+ `No match --> ${input} --> output ${
+ output
+ } --> using ${re.toString()}`
+ );
// console.log('m', m)
- assert.equal(m[pos], output, `Unmatched ${m[pos]} --> input ${input} --> output ${output} --> using ${re.toString()}`)
+ assert.equal(
+ m[pos],
+ output,
+ `Unmatched ${m[pos]} --> input ${input} --> output ${
+ output
+ } --> using ${re.toString()}`
+ );
} else {
- assert(!m, `False match --> input ${input} --> output ${output} --> using ${re.toString()}`)
+ assert(
+ !m,
+ `False match --> input ${input} --> output ${
+ output
+ } --> using ${re.toString()}`
+ );
}
-}
+};
diff --git a/src/app/utils/MarketClasses.js b/src/app/utils/MarketClasses.js
index 678eb10d0ac7d3fc77bb8e76adc82907a01250c6..e103eeb32bfa35d50c2740e52cdc533e2bece7f0 100644
--- a/src/app/utils/MarketClasses.js
+++ b/src/app/utils/MarketClasses.js
@@ -1,12 +1,15 @@
-import {roundDown, roundUp} from "./MarketUtils";
-import { LIQUID_TICKER, DEBT_TICKER } from 'app/client_config'
+import { roundDown, roundUp } from './MarketUtils';
+import { LIQUID_TICKER, DEBT_TICKER } from 'app/client_config';
const precision = 1000;
class Order {
constructor(order, side) {
this.side = side;
this.price = parseFloat(order.real_price);
- this.price = side === 'asks' ? roundUp(this.price, 6) : Math.max(roundDown(this.price, 6), 0.000001);
+ this.price =
+ side === 'asks'
+ ? roundUp(this.price, 6)
+ : Math.max(roundDown(this.price, 6), 0.000001);
this.stringPrice = this.price.toFixed(6);
this.steem = parseInt(order.steem, 10);
this.sbd = parseInt(order.sbd, 10);
@@ -38,12 +41,15 @@ class Order {
}
add(order) {
- return new Order({
- real_price: this.price,
- steem: this.steem + order.steem,
- sbd: this.sbd + order.sbd,
- date: this.date
- }, this.type);
+ return new Order(
+ {
+ real_price: this.price,
+ steem: this.steem + order.steem,
+ sbd: this.sbd + order.sbd,
+ date: this.date,
+ },
+ this.type
+ );
}
equals(order) {
@@ -56,26 +62,34 @@ class Order {
}
class TradeHistory {
-
constructor(fill) {
// Norm date (FF bug)
var zdate = fill.date;
- if(!/Z$/.test(zdate))
- zdate = zdate + 'Z'
+ if (!/Z$/.test(zdate)) zdate = zdate + 'Z';
this.date = new Date(zdate);
- this.type = fill.current_pays.indexOf(DEBT_TICKER) !== -1 ? "bid" : "ask";
- this.color = this.type == "bid" ? "buy-color" : "sell-color";
- if (this.type === "bid") {
- this.sbd = parseFloat(fill.current_pays.split(" " + DEBT_TICKER)[0]);
- this.steem = parseFloat(fill.open_pays.split(" " + LIQUID_TICKER)[0]);
+ this.type =
+ fill.current_pays.indexOf(DEBT_TICKER) !== -1 ? 'bid' : 'ask';
+ this.color = this.type == 'bid' ? 'buy-color' : 'sell-color';
+ if (this.type === 'bid') {
+ this.sbd = parseFloat(
+ fill.current_pays.split(' ' + DEBT_TICKER)[0]
+ );
+ this.steem = parseFloat(
+ fill.open_pays.split(' ' + LIQUID_TICKER)[0]
+ );
} else {
- this.sbd = parseFloat(fill.open_pays.split(" " + DEBT_TICKER)[0]);
- this.steem = parseFloat(fill.current_pays.split(" " + LIQUID_TICKER)[0]);
+ this.sbd = parseFloat(fill.open_pays.split(' ' + DEBT_TICKER)[0]);
+ this.steem = parseFloat(
+ fill.current_pays.split(' ' + LIQUID_TICKER)[0]
+ );
}
this.price = this.sbd / this.steem;
- this.price = this.type === 'ask' ? roundUp(this.price, 6) : Math.max(roundDown(this.price, 6), 0.000001);
+ this.price =
+ this.type === 'ask'
+ ? roundUp(this.price, 6)
+ : Math.max(roundDown(this.price, 6), 0.000001);
this.stringPrice = this.price.toFixed(6);
}
@@ -114,5 +128,5 @@ class TradeHistory {
module.exports = {
Order,
- TradeHistory
-}
+ TradeHistory,
+};
diff --git a/src/app/utils/MarketUtils.js b/src/app/utils/MarketUtils.js
index 6b6e9215db09e95cdaa2a2add2efa5948ff7ef9f..e4d61ff84b13554ebbae04b9d815a05e55a80ef5 100644
--- a/src/app/utils/MarketUtils.js
+++ b/src/app/utils/MarketUtils.js
@@ -1,24 +1,44 @@
function roundUp(num, precision) {
- let satoshis = parseFloat(num) * Math.pow(10, precision)
+ let satoshis = parseFloat(num) * Math.pow(10, precision);
// Attempt to correct floating point: 1.0001 satoshis should not round up.
- satoshis = satoshis - 0.0001
+ satoshis = satoshis - 0.0001;
// Round up, restore precision
- return Math.ceil(satoshis) / Math.pow(10, precision)
+ return Math.ceil(satoshis) / Math.pow(10, precision);
}
function roundDown(num, precision) {
- let satoshis = parseFloat(num) * Math.pow(10, precision)
+ let satoshis = parseFloat(num) * Math.pow(10, precision);
// Attempt to correct floating point: 1.9999 satoshis should not round down.
- satoshis = satoshis + 0.0001
+ satoshis = satoshis + 0.0001;
// Round down, restore precision
- return Math.floor(satoshis) / Math.pow(10, precision)
+ return Math.floor(satoshis) / Math.pow(10, precision);
}
+/**
+ * Returns a sorting function which uses a given column and value-fetcher.
+ *
+ * @param {Function} getValue
+ * @param {String} columnName
+ * @param {Number} dir either 1 or -1
+ */
+const createOrderSorter = (getValue, columnName, dir) => (a, b) => {
+ if (getValue(a[columnName]) < getValue(b[columnName])) {
+ return -1 * dir;
+ }
+
+ if (getValue(a[columnName]) > getValue(b[columnName])) {
+ return 1 * dir;
+ }
+
+ return 0;
+};
+
module.exports = {
roundUp,
- roundDown
-}
+ roundDown,
+ createOrderSorter,
+};
diff --git a/src/app/utils/NormalizeProfile.js b/src/app/utils/NormalizeProfile.js
index 1fef9b06c8ed485f08b89b84b32edeb1f771e6ae..d9f3fbfc25ed1b8cfee66f8728c087d99a5ad5e3 100644
--- a/src/app/utils/NormalizeProfile.js
+++ b/src/app/utils/NormalizeProfile.js
@@ -1,61 +1,76 @@
-import linksRe from 'app/utils/Links'
+import linksRe from 'app/utils/Links';
function truncate(str, len) {
- if(str) {
- str = str.trim()
- if(str.length > len) {
- str = str.substring(0, len - 1) + '...'
+ if (str) {
+ str = str.trim();
+ if (str.length > len) {
+ str = str.substring(0, len - 1) + '...';
}
}
- return str
+ return str;
}
/**
* Enforce profile data length & format standards.
*/
export default function normalizeProfile(account) {
-
- if(! account) return {}
+ if (!account) return {};
// Parse
let profile = {};
- if(account.json_metadata) {
+ if (account.json_metadata) {
try {
const md = JSON.parse(account.json_metadata);
- if(md.profile) {
+ if (md.profile) {
profile = md.profile;
}
- if(!(typeof profile == 'object')) {
- console.error('Expecting object in account.json_metadata.profile:', profile);
+ if (!(typeof profile == 'object')) {
+ console.error(
+ 'Expecting object in account.json_metadata.profile:',
+ profile
+ );
profile = {};
}
} catch (e) {
- console.error('Invalid json metadata string', account.json_metadata, 'in account', account.name);
+ console.error(
+ 'Invalid json metadata string',
+ account.json_metadata,
+ 'in account',
+ account.name
+ );
}
}
// Read & normalize
- let {name, about, location, website, profile_image, cover_image} = profile
+ let {
+ name,
+ about,
+ location,
+ website,
+ profile_image,
+ cover_image,
+ } = profile;
- name = truncate(name, 20)
- about = truncate(about, 160)
- location = truncate(location, 30)
+ name = truncate(name, 20);
+ about = truncate(about, 160);
+ location = truncate(location, 30);
- if(/^@/.test(name)) name = null;
- if(website && website.length > 100) website = null;
- if (website && website.indexOf("http") === -1) {
+ if (/^@/.test(name)) name = null;
+ if (website && website.length > 100) website = null;
+ if (website && website.indexOf('http') === -1) {
website = 'http://' + website;
}
- if(website) {
+ if (website) {
// enforce that the url regex matches, and fully
- const m = website.match(linksRe.any)
- if(!m || m[0] !== website) {
+ const m = website.match(linksRe.any);
+ if (!m || m[0] !== website) {
website = null;
}
}
- if(profile_image && !/^https?:\/\//.test(profile_image)) profile_image = null;
- if(cover_image && !/^https?:\/\//.test(cover_image)) cover_image = null;
+ if (profile_image && !/^https?:\/\//.test(profile_image))
+ profile_image = null;
+ if (cover_image && !/^https?:\/\//.test(cover_image)) cover_image = null;
return {
name,
diff --git a/src/app/utils/Notifications.js b/src/app/utils/Notifications.js
deleted file mode 100644
index d3f876140433dcf48584ff342771758422bdd5d5..0000000000000000000000000000000000000000
--- a/src/app/utils/Notifications.js
+++ /dev/null
@@ -1,9 +0,0 @@
-export const NTYPES = ['total', 'feed', 'reward', 'send', 'mention', 'follow', 'vote', 'comment_reply', 'post_reply', 'account_update', 'message', 'receive'];
-
-export function notificationsArrayToMap(data) {
- const notifications = data && data.length ? (data.length === 1 ? data[0].slice(1) : data) : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
- return notifications.reduce((result, n, i) => {
- result[NTYPES[i]] = n;
- return result;
- }, {});
-}
diff --git a/src/app/utils/ParsersAndFormatters.js b/src/app/utils/ParsersAndFormatters.js
index 98e873724f8266d88a07c9d19ba17ad051d7a39c..650cfe13285b1087599694dda094ec40aa58bab4 100644
--- a/src/app/utils/ParsersAndFormatters.js
+++ b/src/app/utils/ParsersAndFormatters.js
@@ -23,8 +23,18 @@ export function formatDecimal(value, decPlaces = 2, truncate0s = true) {
i = parseInt(abs_value.toFixed(decPlaces), 10) + '';
j = i.length;
j = i.length > 3 ? j % 3 : 0;
- const decPart = (decPlaces ? decSeparator + Math.abs(abs_value - i).toFixed(decPlaces).slice(2) : '');
- return [sign + (j ? i.substr(0, j) + thouSeparator : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thouSeparator), decPart];
+ const decPart = decPlaces
+ ? decSeparator +
+ Math.abs(abs_value - i)
+ .toFixed(decPlaces)
+ .slice(2)
+ : '';
+ return [
+ sign +
+ (j ? i.substr(0, j) + thouSeparator : '') +
+ i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thouSeparator),
+ decPart,
+ ];
}
export function parsePayoutAmount(amount) {
@@ -38,59 +48,71 @@ export function parsePayoutAmount(amount) {
*/
function log10(str) {
const leadingDigits = parseInt(str.substring(0, 4));
- const log = Math.log(leadingDigits) / Math.LN10 + 0.00000001
+ const log = Math.log(leadingDigits) / Math.LN10 + 0.00000001;
const n = str.length - 1;
return n + (log - parseInt(log));
}
export const repLog10 = rep2 => {
- if(rep2 == null) return rep2
- let rep = String(rep2)
- const neg = rep.charAt(0) === '-'
- rep = neg ? rep.substring(1) : rep
+ if (rep2 == null) return rep2;
+ let rep = String(rep2);
+ const neg = rep.charAt(0) === '-';
+ rep = neg ? rep.substring(1) : rep;
- let out = log10(rep)
- if(isNaN(out)) out = 0
+ let out = log10(rep);
+ if (isNaN(out)) out = 0;
out = Math.max(out - 9, 0); // @ -9, $0.50 earned is approx magnitude 1
- out = (neg ? -1 : 1) * out
- out = (out * 9) + 25 // 9 points per magnitude. center at 25
+ out = (neg ? -1 : 1) * out;
+ out = out * 9 + 25; // 9 points per magnitude. center at 25
// base-line 0 to darken and < 0 to auto hide (grep rephide)
- out = parseInt(out)
- return out
-}
+ out = parseInt(out);
+ return out;
+};
export function countDecimals(amount) {
- if(amount == null) return amount
- amount = String(amount).match(/[\d\.]+/g).join('') // just dots and digits
- const parts = amount.split('.')
- return parts.length > 2 ? undefined : parts.length === 1 ? 0 : parts[1].length
+ if (amount == null) return amount;
+ amount = String(amount)
+ .match(/[\d\.]+/g)
+ .join(''); // just dots and digits
+ const parts = amount.split('.');
+ return parts.length > 2
+ ? undefined
+ : parts.length === 1 ? 0 : parts[1].length;
}
// this function searches for right translation of provided error (usually from back-end)
export function translateError(string) {
- if (typeof(string) != 'string') return string;
+ if (typeof string != 'string') return string;
switch (string) {
case 'Account not found':
- return tt('g.account_not_found')
+ return tt('g.account_not_found');
case 'Incorrect Password':
- return tt('g.incorrect_password')
+ return tt('g.incorrect_password');
case 'Username does not exist':
- return tt('g.username_does_not_exist')
+ return tt('g.username_does_not_exist');
case 'Account name should be longer.':
- return tt('g.account_name_should_be_longer')
+ return tt('g.account_name_should_be_longer');
case 'Account name should be shorter.':
- return tt('g.account_name_should_be_shorter')
+ return tt('g.account_name_should_be_shorter');
case 'Account name should start with a letter.':
- return tt('g.account_name_should_start_with_a_letter')
- case 'Account name should have only letters, digits, or dashes.':
- return tt('g.account_name_should_have_only_letters_digits_or_dashes')
+ return tt('g.account_name_should_start_with_a_letter');
+ case 'Account name should have only letters, digits, periods or dashes.':
+ return tt(
+ 'g.account_name_should_have_only_letters_digits_or_dashes'
+ );
case 'vote currently exists, user must be indicate a desire to reject witness':
- return tt('g.vote_currently_exists_user_must_be_indicate_a_to_reject_witness')
+ return tt(
+ 'g.vote_currently_exists_user_must_be_indicate_a_to_reject_witness'
+ );
case 'Only one Steem account allowed per IP address every 10 minutes':
- return tt('g.only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes')
+ return tt(
+ 'g.only_one_APP_NAME_account_allowed_per_ip_address_every_10_minutes'
+ );
case 'Cannot increase reward of post within the last minute before payout':
- return tt('g.cannot_increase_reward_of_post_within_the_last_minute_before_payout')
+ return tt(
+ 'g.cannot_increase_reward_of_post_within_the_last_minute_before_payout'
+ );
default:
- return string
+ return string;
}
}
diff --git a/src/app/utils/ProxifyUrl.js b/src/app/utils/ProxifyUrl.js
index 9f5f6afd3a4a6fa9e1b934844dae12f5d119385d..5f547793482eee221e2fc83582bf6ad9a73ca32c 100644
--- a/src/app/utils/ProxifyUrl.js
+++ b/src/app/utils/ProxifyUrl.js
@@ -32,12 +32,13 @@ export default (url, dimensions = false) => {
if (dimensions && $STM_Config && $STM_Config.img_proxy_prefix) {
let dims = dimensions + '/';
if (typeof dimensions !== 'string') {
- dims = (proxyList) ? proxyList.shift().match(/([0-9]+x[0-9]+)\//g)[0] : NATURAL_SIZE;
+ dims = proxyList
+ ? proxyList.shift().match(/([0-9]+x[0-9]+)\//g)[0]
+ : NATURAL_SIZE;
}
if (NATURAL_SIZE !== dims || !rProxyDomain.test(respUrl)) {
return $STM_Config.img_proxy_prefix + dims + respUrl;
}
}
return respUrl;
-}
-
+};
diff --git a/src/app/utils/ProxifyUrl.test.js b/src/app/utils/ProxifyUrl.test.js
index e1f8db77de1e29af27d2f2334308097fb07af4d8..2a4a0405683198b8c5549b87cc6651edf1e6cb0d 100644
--- a/src/app/utils/ProxifyUrl.test.js
+++ b/src/app/utils/ProxifyUrl.test.js
@@ -1,61 +1,155 @@
/*global describe, global, before:false, it*/
-import assert from 'assert'
-import proxifyImageUrl from './ProxifyUrl'
+import assert from 'assert';
+import proxifyImageUrl from './ProxifyUrl';
describe('ProxifyUrl', () => {
- before(() => {
- global.$STM_Config = {img_proxy_prefix: 'https://steemitimages.com/'};
+ beforeAll(() => {
+ global.$STM_Config = { img_proxy_prefix: 'https://steemitimages.com/' };
});
it('naked URL', () => {
- testCase('https://example.com/img.png', '100x200', 'https://steemitimages.com/100x200/https://example.com/img.png')
- testCase('https://example.com/img.png', '0x0', 'https://steemitimages.com/0x0/https://example.com/img.png')
- testCase('https://example.com/img.png', true, 'https://steemitimages.com/0x0/https://example.com/img.png')
- testCase('https://example.com/img.png', false, 'https://example.com/img.png')
- })
+ testCase(
+ 'https://example.com/img.png',
+ '100x200',
+ 'https://steemitimages.com/100x200/https://example.com/img.png'
+ );
+ testCase(
+ 'https://example.com/img.png',
+ '0x0',
+ 'https://steemitimages.com/0x0/https://example.com/img.png'
+ );
+ testCase(
+ 'https://example.com/img.png',
+ true,
+ 'https://steemitimages.com/0x0/https://example.com/img.png'
+ );
+ testCase(
+ 'https://example.com/img.png',
+ false,
+ 'https://example.com/img.png'
+ );
+ });
it('naked steemit hosted URL', () => {
- testCase('https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', '256x512', 'https://steemitimages.com/256x512/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
- testCase('https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', false, 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
- })
+ testCase(
+ 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg',
+ '256x512',
+ 'https://steemitimages.com/256x512/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg'
+ );
+ testCase(
+ 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg',
+ false,
+ 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg'
+ );
+ });
it('proxied steemit hosted URL', () => {
- testCase('https://steemitimages.com/0x0/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', '256x512', 'https://steemitimages.com/256x512/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
- testCase('https://steemitimages.com/256x512/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', false, 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
- })
+ testCase(
+ 'https://steemitimages.com/0x0/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg',
+ '256x512',
+ 'https://steemitimages.com/256x512/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg'
+ );
+ testCase(
+ 'https://steemitimages.com/256x512/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg',
+ false,
+ 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg'
+ );
+ });
it('proxied URL', () => {
- testCase('https://steemitimages.com/0x0/https://example.com/img.png', '100x200', 'https://steemitimages.com/100x200/https://example.com/img.png')
- testCase('https://steemitimages.com/256x512/https://peopledotcom.files.wordpress.com/2017/09/grumpy-harvey-cat.jpg?w=2000', '100x200', 'https://steemitimages.com/100x200/https://peopledotcom.files.wordpress.com/2017/09/grumpy-harvey-cat.jpg?w=2000')
- testCase('https://steemitimages.com/0x0/https://example.com/img.png', false, 'https://example.com/img.png')
- })
+ testCase(
+ 'https://steemitimages.com/0x0/https://example.com/img.png',
+ '100x200',
+ 'https://steemitimages.com/100x200/https://example.com/img.png'
+ );
+ testCase(
+ 'https://steemitimages.com/256x512/https://peopledotcom.files.wordpress.com/2017/09/grumpy-harvey-cat.jpg?w=2000',
+ '100x200',
+ 'https://steemitimages.com/100x200/https://peopledotcom.files.wordpress.com/2017/09/grumpy-harvey-cat.jpg?w=2000'
+ );
+ testCase(
+ 'https://steemitimages.com/0x0/https://example.com/img.png',
+ false,
+ 'https://example.com/img.png'
+ );
+ });
it('double-proxied URL', () => {
- testCase('https://steemitimages.com/0x0/https://steemitimages.com/0x0/https://example.com/img.png', '100x200', 'https://steemitimages.com/100x200/https://example.com/img.png')
- testCase('https://steemitimages.com/0x0/https://steemitimages.com/256x512/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', false, 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
- })
+ testCase(
+ 'https://steemitimages.com/0x0/https://steemitimages.com/0x0/https://example.com/img.png',
+ '100x200',
+ 'https://steemitimages.com/100x200/https://example.com/img.png'
+ );
+ testCase(
+ 'https://steemitimages.com/0x0/https://steemitimages.com/256x512/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg',
+ false,
+ 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg'
+ );
+ });
it('preserve dimensions - single-proxied URL', () => {
//simple preservation
- testCase('https://steemitdevimages.com/100x200/https://example.com/img.png', true, 'https://steemitimages.com/100x200/https://example.com/img.png')
- testCase('https://steemitdevimages.com/1001x2001/https://example.com/img.png', true, 'https://steemitimages.com/1001x2001/https://example.com/img.png')
- })
+ testCase(
+ 'https://steemitdevimages.com/100x200/https://example.com/img.png',
+ true,
+ 'https://steemitimages.com/100x200/https://example.com/img.png'
+ );
+ testCase(
+ 'https://steemitdevimages.com/1001x2001/https://example.com/img.png',
+ true,
+ 'https://steemitimages.com/1001x2001/https://example.com/img.png'
+ );
+ });
it('preserve dimensions - double-proxied URL', () => {
//simple preservation at a 2 nesting level
//foreign domain
- testCase('https://steemitimages.com/100x200/https://steemitimages.com/0x0/https://example.com/img.png', true, 'https://steemitimages.com/100x200/https://example.com/img.png')
- testCase('https://steemitdevimages.com/1001x2001/https://steemitimages.com/0x0/https://example.com/img.png', true, 'https://steemitimages.com/1001x2001/https://example.com/img.png')
+ testCase(
+ 'https://steemitimages.com/100x200/https://steemitimages.com/0x0/https://example.com/img.png',
+ true,
+ 'https://steemitimages.com/100x200/https://example.com/img.png'
+ );
+ testCase(
+ 'https://steemitdevimages.com/1001x2001/https://steemitimages.com/0x0/https://example.com/img.png',
+ true,
+ 'https://steemitimages.com/1001x2001/https://example.com/img.png'
+ );
//steemit domain
- testCase('https://steemitdevimages.com/1001x2001/https://steemitimages.com/0x0/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', true, 'https://steemitimages.com/1001x2001/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
- })
+ testCase(
+ 'https://steemitdevimages.com/1001x2001/https://steemitimages.com/0x0/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg',
+ true,
+ 'https://steemitimages.com/1001x2001/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg'
+ );
+ });
it('preserve dimensions - strip proxies & dimensions when appropriate', () => {
//simple preservation at a 2 nesting level
//steemit domain
- testCase('https://steemitimages.com/0x0/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', true, 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
+ testCase(
+ 'https://steemitimages.com/0x0/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg',
+ true,
+ 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg'
+ );
//foreign domain
- testCase('https://steemitimages.com/0x0/https://example.com/img.png', true, 'https://steemitimages.com/0x0/https://example.com/img.png')
+ testCase(
+ 'https://steemitimages.com/0x0/https://example.com/img.png',
+ true,
+ 'https://steemitimages.com/0x0/https://example.com/img.png'
+ );
//case where last is natural sizing, assumes natural sizing - straight to direct steemit file url
- testCase('https://steemitimages.com/0x0/https://steemitimages.com/100x100/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', true, 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
+ testCase(
+ 'https://steemitimages.com/0x0/https://steemitimages.com/100x100/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg',
+ true,
+ 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg'
+ );
//case where last is natural sizing, assumes natural sizing - straight to direct steemit /0x0/ domain host url
- testCase('https://steemitimages.com/0x0/https://steemitimages.com/100x100/https://example.com/img.png', true, 'https://steemitimages.com/0x0/https://example.com/img.png')
- })
-})
+ testCase(
+ 'https://steemitimages.com/0x0/https://steemitimages.com/100x100/https://example.com/img.png',
+ true,
+ 'https://steemitimages.com/0x0/https://example.com/img.png'
+ );
+ });
+});
const testCase = (inputUrl, outputDims, expectedUrl) => {
const outputUrl = proxifyImageUrl(inputUrl, outputDims);
- assert.equal(outputUrl, expectedUrl, `(${inputUrl}, ${outputDims}) should return ${expectedUrl}. output was ${outputUrl}`)
-}
+ assert.equal(
+ outputUrl,
+ expectedUrl,
+ `(${inputUrl}, ${outputDims}) should return ${
+ expectedUrl
+ }. output was ${outputUrl}`
+ );
+};
diff --git a/src/app/utils/ReactForm.js b/src/app/utils/ReactForm.js
index fecc7a1f9006f700bab0409adc21ca42be75991e..4964b0d8c66a1275b228abc67d11118627deda14 100644
--- a/src/app/utils/ReactForm.js
+++ b/src/app/utils/ReactForm.js
@@ -5,165 +5,171 @@
@arg {object} initialValues required for checkboxes {save: false, ...}
@arg {function} validation - values => ({ username: ! values.username ? 'Required' : null, ... })
*/
-export default function reactForm({name, instance, fields, initialValues, validation = () => {}}) {
- if(typeof instance !== 'object') throw new TypeError('instance is a required object')
- if(!Array.isArray(fields)) throw new TypeError('fields is a required array')
- if(typeof initialValues !== 'object') throw new TypeError('initialValues is a required object')
+export default function reactForm({
+ name,
+ instance,
+ fields,
+ initialValues,
+ validation = () => {},
+}) {
+ if (typeof instance !== 'object')
+ throw new TypeError('instance is a required object');
+ if (!Array.isArray(fields))
+ throw new TypeError('fields is a required array');
+ if (typeof initialValues !== 'object')
+ throw new TypeError('initialValues is a required object');
// Give API users access to this.props, this.state, this.etc..
- validation = validation.bind(instance)
+ validation = validation.bind(instance);
- const formState = instance.state = instance.state || {}
+ const formState = (instance.state = instance.state || {});
formState[name] = {
// validate: () => setFormState(instance, fields, validation),
handleSubmit: submitCallback => event => {
- event.preventDefault()
- const {valid} = setFormState(name, instance, fields, validation)
- if(!valid) return
- const data = getData(fields, instance.state)
- let formValid = true
- const fs = instance.state[name] || {}
- fs.submitting = true
+ event.preventDefault();
+ const { valid } = setFormState(name, instance, fields, validation);
+ if (!valid) return;
+ const data = getData(fields, instance.state);
+ let formValid = true;
+ const fs = instance.state[name] || {};
+ fs.submitting = true;
// User can call this function upon successful submission
const updateInitialValues = () => {
- setInitialValuesFromForm(name, instance, fields, initialValues)
- formState[name].resetForm()
- }
-
- instance.setState(
- {[name]: fs},
- () => {
- // TODO, support promise ret
- const ret = submitCallback({data, event, updateInitialValues}) || {}
- // Look for field level errors
- for(const fieldName of Object.keys(ret)) {
- const error = ret[fieldName]
- if(!error) continue
- const value = instance.state[fieldName] || {}
- value.error = error
- value.touched = true
- if(error) formValid = false
- instance.setState({[fieldName]: value})
- }
- fs.submitting = false
- fs.valid = formValid
- instance.setState({[name]: fs})
+ setInitialValuesFromForm(name, instance, fields, initialValues);
+ formState[name].resetForm();
+ };
+
+ instance.setState({ [name]: fs }, () => {
+ // TODO, support promise ret
+ const ret =
+ submitCallback({ data, event, updateInitialValues }) || {};
+ // Look for field level errors
+ for (const fieldName of Object.keys(ret)) {
+ const error = ret[fieldName];
+ if (!error) continue;
+ const value = instance.state[fieldName] || {};
+ value.error = error;
+ value.touched = true;
+ if (error) formValid = false;
+ instance.setState({ [fieldName]: value });
}
- )
+ fs.submitting = false;
+ fs.valid = formValid;
+ instance.setState({ [name]: fs });
+ });
},
resetForm: () => {
- for(const field of fields) {
- const fieldName = n(field)
- const f = instance.state[fieldName]
- const def = initialValues[fieldName]
- f.props.onChange(def)
+ for (const field of fields) {
+ const fieldName = n(field);
+ const f = instance.state[fieldName];
+ const def = initialValues[fieldName];
+ f.props.onChange(def);
}
},
clearForm: () => {
- for(const field of fields) {
- const fieldName = n(field)
- const f = instance.state[fieldName]
- f.props.onChange()
+ for (const field of fields) {
+ const fieldName = n(field);
+ const f = instance.state[fieldName];
+ f.props.onChange();
}
},
- }
+ };
- for(const field of fields) {
- const fieldName = n(field)
- const fieldType = t(field)
+ for (const field of fields) {
+ const fieldName = n(field);
+ const fieldType = t(field);
- const fs = formState[fieldName] = {
+ const fs = (formState[fieldName] = {
value: null,
error: null,
touched: false,
- }
+ });
// Caution: fs.props is expanded , so only add valid props for the component
- fs.props = {name: fieldName}
+ fs.props = { name: fieldName };
{
- const initialValue = initialValues[fieldName]
- if(fieldType === 'checked') {
- fs.value = toString(initialValue)
- fs.props.checked = toBoolean(initialValue)
- } else if(fieldType === 'selected') {
- fs.props.selected = toString(initialValue)
- fs.value = fs.props.selected
+ const initialValue = initialValues[fieldName];
+ if (fieldType === 'checked') {
+ fs.value = toString(initialValue);
+ fs.props.checked = toBoolean(initialValue);
+ } else if (fieldType === 'selected') {
+ fs.props.selected = toString(initialValue);
+ fs.value = fs.props.selected;
} else {
- fs.props.value = toString(initialValue)
- fs.value = fs.props.value
+ fs.props.value = toString(initialValue);
+ fs.value = fs.props.value;
}
}
fs.props.onChange = e => {
- const value = e && e.target ? e.target.value : e // API may pass value directly
- const v = {...(instance.state[fieldName] || {})}
- const initialValue = initialValues[fieldName]
-
- if(fieldType === 'checked') {
- v.touched = toString(value) !== toString(initialValue)
- v.value = v.props.checked = toBoolean(value)
- v.value = value
- } else if(fieldType === 'selected') {
- v.touched = toString(value) !== toString(initialValue)
- v.value = v.props.selected = toString(value)
+ const value = e && e.target ? e.target.value : e; // API may pass value directly
+ const v = { ...(instance.state[fieldName] || {}) };
+ const initialValue = initialValues[fieldName];
+
+ if (fieldType === 'checked') {
+ v.touched = toString(value) !== toString(initialValue);
+ v.value = v.props.checked = toBoolean(value);
+ v.value = value;
+ } else if (fieldType === 'selected') {
+ v.touched = toString(value) !== toString(initialValue);
+ v.value = v.props.selected = toString(value);
} else {
- v.touched = toString(value) !== toString(initialValue)
- v.value = v.props.value = toString(value)
+ v.touched = toString(value) !== toString(initialValue);
+ v.value = v.props.value = toString(value);
}
- instance.setState(
- {[fieldName]: v},
- () => {setFormState(name, instance, fields, validation)}
- )
- }
+ instance.setState({ [fieldName]: v }, () => {
+ setFormState(name, instance, fields, validation);
+ });
+ };
fs.props.onBlur = () => {
// Some errors are better shown only after blur === true
- const v = {...(instance.state[fieldName] || {})}
- v.blur = true
- instance.setState({[fieldName]: v})
- }
+ const v = { ...(instance.state[fieldName] || {}) };
+ v.blur = true;
+ instance.setState({ [fieldName]: v });
+ };
}
}
function setFormState(name, instance, fields, validation) {
- let formValid = true
- let formTouched = false
- const v = validation(getData(fields, instance.state))
- for(const field of fields) {
- const fieldName = n(field)
- const validate = v[fieldName]
- const error = validate ? validate : null
- const value = {...(instance.state[fieldName] || {})}
- value.error = error
- formTouched = formTouched || value.touched
- if(error) formValid = false
- instance.setState({[fieldName]: value})
+ let formValid = true;
+ let formTouched = false;
+ const v = validation(getData(fields, instance.state));
+ for (const field of fields) {
+ const fieldName = n(field);
+ const validate = v[fieldName];
+ const error = validate ? validate : null;
+ const value = { ...(instance.state[fieldName] || {}) };
+ value.error = error;
+ formTouched = formTouched || value.touched;
+ if (error) formValid = false;
+ instance.setState({ [fieldName]: value });
}
- const fs = {...(instance.state[name] || {})}
- fs.valid = formValid
- fs.touched = formTouched
- instance.setState({[name]: fs})
- return fs
+ const fs = { ...(instance.state[name] || {}) };
+ fs.valid = formValid;
+ fs.touched = formTouched;
+ instance.setState({ [name]: fs });
+ return fs;
}
function setInitialValuesFromForm(name, instance, fields, initialValues) {
- const data = getData(fields, instance.state)
- for(const field of fields) {
- const fieldName = n(field)
- initialValues[fieldName] = data[fieldName]
+ const data = getData(fields, instance.state);
+ for (const field of fields) {
+ const fieldName = n(field);
+ initialValues[fieldName] = data[fieldName];
}
}
function getData(fields, state) {
- const data = {}
- for(const field of fields) {
- const fieldName = n(field)
- data[fieldName] = state[fieldName].value
+ const data = {};
+ for (const field of fields) {
+ const fieldName = n(field);
+ data[fieldName] = state[fieldName].value;
}
- return data
+ return data;
}
/*
@@ -176,18 +182,21 @@ function getData(fields, state) {
@return {string} type
*/
function t(field) {
- const [, type = 'string'] = field.split(':')
- return type
+ const [, type = 'string'] = field.split(':');
+ return type;
}
/**
@return {string} name
*/
function n(field) {
- const [name] = field.split(':')
- return name
+ const [name] = field.split(':');
+ return name;
}
-const hasValue = v => v == null ? false : (typeof v === 'string' ? v.trim() : v) === '' ? false : true
-const toString = v => hasValue(v) ? v : ''
-const toBoolean = v => hasValue(v) ? JSON.parse(v) : ''
+const hasValue = v =>
+ v == null
+ ? false
+ : (typeof v === 'string' ? v.trim() : v) === '' ? false : true;
+const toString = v => (hasValue(v) ? v : '');
+const toBoolean = v => (hasValue(v) ? JSON.parse(v) : '');
diff --git a/src/app/utils/ReduxForms.js b/src/app/utils/ReduxForms.js
index 8e8e2a0bd76f771fde53d00cf1c9a87fb71dbfac..54a788e9e92004b1efd0e65609cb07ab560fec46 100644
--- a/src/app/utils/ReduxForms.js
+++ b/src/app/utils/ReduxForms.js
@@ -1,9 +1,27 @@
export const cleanReduxInput = i => {
// Remove all props that don't belong. Triggers React warnings.
- const {name, placeholder, label, value, checked, onChange, onBlur, onFocus} = i
- const ret = {name, placeholder, label, value, checked, onChange, onBlur, onFocus}
- if(ret.value == null) delete ret.value
- if(ret.label == null) delete ret.label
- if(ret.type == null) delete ret.type
- return ret
-}
+ const {
+ name,
+ placeholder,
+ label,
+ value,
+ checked,
+ onChange,
+ onBlur,
+ onFocus,
+ } = i;
+ const ret = {
+ name,
+ placeholder,
+ label,
+ value,
+ checked,
+ onChange,
+ onBlur,
+ onFocus,
+ };
+ if (ret.value == null) delete ret.value;
+ if (ret.label == null) delete ret.label;
+ if (ret.type == null) delete ret.type;
+ return ret;
+};
diff --git a/src/app/utils/RegisterServiceWorker.js b/src/app/utils/RegisterServiceWorker.js
index 4da112e26c12efab41be0bf310ea048c8ad4b98a..f5b407222a325b153e884f1983f81280c39d4d43 100644
--- a/src/app/utils/RegisterServiceWorker.js
+++ b/src/app/utils/RegisterServiceWorker.js
@@ -1,34 +1,49 @@
export default function registerServiceWorker() {
if (!navigator.serviceWorker) return Promise.resolve(false);
- return navigator.serviceWorker.register('/service-worker.js', {scope: '/'})
- .then(function (registration) {
- navigator.serviceWorker.ready.catch(e => console.error('-- registerServiceWorker error -->', e));
- return navigator.serviceWorker.ready.then(function (serviceWorkerRegistration) {
+ return navigator.serviceWorker
+ .register('/service-worker.js', { scope: '/' })
+ .then(function(registration) {
+ navigator.serviceWorker.ready.catch(e =>
+ console.error('-- registerServiceWorker error -->', e)
+ );
+ return navigator.serviceWorker.ready.then(function(
+ serviceWorkerRegistration
+ ) {
let subscription = serviceWorkerRegistration.pushManager.getSubscription();
- return subscription.then(function (subscription) {
- if (subscription) {
- return subscription;
- }
- return serviceWorkerRegistration.pushManager.subscribe({
- userVisibleOnly: true
- });
+ return subscription.then(function(subscription) {
+ if (subscription) {
+ return subscription;
+ }
+ return serviceWorkerRegistration.pushManager.subscribe({
+ userVisibleOnly: true,
});
+ });
});
- }).then(function (subscription) {
- const rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
- const key = rawKey ?
- btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) :
- '';
- const rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
- const authSecret = rawAuthSecret ?
- btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) :
- '';
+ })
+ .then(function(subscription) {
+ const rawKey = subscription.getKey
+ ? subscription.getKey('p256dh')
+ : '';
+ const key = rawKey
+ ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey)))
+ : '';
+ const rawAuthSecret = subscription.getKey
+ ? subscription.getKey('auth')
+ : '';
+ const authSecret = rawAuthSecret
+ ? btoa(
+ String.fromCharCode.apply(
+ null,
+ new Uint8Array(rawAuthSecret)
+ )
+ )
+ : '';
return {
endpoint: subscription.endpoint,
keys: {
p256dh: key,
- auth: authSecret
- }
+ auth: authSecret,
+ },
};
});
}
diff --git a/src/app/utils/RemarkablePlugin.js b/src/app/utils/RemarkablePlugin.js
index 61bceda792a3df71e0afc6dbc0d3a26a9ab69cac..9c6befefef62ae7461dbb6b52d121161df2fd105 100644
--- a/src/app/utils/RemarkablePlugin.js
+++ b/src/app/utils/RemarkablePlugin.js
@@ -51,7 +51,7 @@ console.log('renderedText', renderedText)
// text: (tokens, i, options, env, renderer) => {
// if(tagRules.youtubeId)
// return `youtube:${tagRules.youtubeId}${tagRules.youtubeTime ? ',' + tagRules.youtubeTime : ''}`
-//
+//
// if(tagLinkOpen)
// return renderer.rules.text(tokens, i, options, env, renderer)
// let content = tokens[i].content
@@ -77,7 +77,7 @@ console.log('renderedText', renderedText)
// // unescapted ipfs links (temp, until the reply editor categorizes the image)
// //if(config.ipfs_prefix)
// // content = content.replace(linksRe.ipfsPrefix, config.ipfs_prefix)
-//
+//
// return content
// },
// link_close: (tokens, i, options, env, renderer) => {
@@ -93,7 +93,7 @@ console.log('renderedText', renderedText)
// let hashtags = new Set()
// let usertags = new Set()
// let tagLinkOpen
-//
+//
// export const imageLinks = {
// done: () => {
// if(image.length > 1) links.delete(image[1])
diff --git a/src/app/utils/RemarkableStripper.js b/src/app/utils/RemarkableStripper.js
index f0c2a82875e4d8b67e182417bd68847489bc95ef..9bbb8bfb833c6b26bdd0b4363dacbc11c29200ea 100644
--- a/src/app/utils/RemarkableStripper.js
+++ b/src/app/utils/RemarkableStripper.js
@@ -1,23 +1,23 @@
-import Remarkable from 'remarkable'
+import Remarkable from 'remarkable';
-const remarkable = new Remarkable()
-export default remarkable
+const remarkable = new Remarkable();
+export default remarkable;
/** Removes all markdown leaving just plain text */
const remarkableStripper = md => {
md.renderer.render = (tokens, options, env) => {
- let str = ''
+ let str = '';
for (let i = 0; i < tokens.length; i++) {
if (tokens[i].type === 'inline') {
str += md.renderer.render(tokens[i].children, options, env);
} else {
// console.log('content', tokens[i])
- const content = tokens[i].content
- str += (content || '') + ' '
+ const content = tokens[i].content;
+ str += (content || '') + ' ';
}
}
- return str
- }
-}
+ return str;
+ };
+};
-remarkable.use(remarkableStripper) // removes all markdown
+remarkable.use(remarkableStripper); // removes all markdown
diff --git a/src/app/utils/SanitizeConfig.js b/src/app/utils/SanitizeConfig.js
index b4206a9dd23f424badd85649b528bad412f728ed..ae92e9df41eed35482140d42c859817eeaa9854e 100644
--- a/src/app/utils/SanitizeConfig.js
+++ b/src/app/utils/SanitizeConfig.js
@@ -1,52 +1,75 @@
-import { getPhishingWarningMessage } from 'shared/HtmlReady'; // the only allowable title attribute for a div
+import {
+ getPhishingWarningMessage,
+ getExternalLinkWarningMessage,
+} from 'shared/HtmlReady'; // the only allowable title attributes for div and a tags
const iframeWhitelist = [
{
re: /^(https?:)?\/\/player.vimeo.com\/video\/.*/i,
- fn: (src) => {
+ fn: src => {
//
- if(!src) return null
- const m = src.match(/https:\/\/player\.vimeo\.com\/video\/([0-9]+)/)
- if(!m || m.length !== 2) return null
- return 'https://player.vimeo.com/video/' + m[1]
- }
+ if (!src) return null;
+ const m = src.match(
+ /https:\/\/player\.vimeo\.com\/video\/([0-9]+)/
+ );
+ if (!m || m.length !== 2) return null;
+ return 'https://player.vimeo.com/video/' + m[1];
+ },
},
- { re: /^(https?:)?\/\/www.youtube.com\/embed\/.*/i,
- fn: (src) => {
- return src.replace(/\?.+$/, ''); // strip query string (yt: autoplay=1,controls=0,showinfo=0, etc)
- }
+ {
+ re: /^(https?:)?\/\/www.youtube.com\/embed\/.*/i,
+ fn: src => {
+ return src.replace(/\?.+$/, ''); // strip query string (yt: autoplay=1,controls=0,showinfo=0, etc)
+ },
},
{
re: /^https:\/\/w.soundcloud.com\/player\/.*/i,
- fn: (src) => {
- if(!src) return null
+ fn: src => {
+ if (!src) return null;
//
- const m = src.match(/url=(.+?)&/)
- if(!m || m.length !== 2) return null
- return 'https://w.soundcloud.com/player/?url=' + m[1] +
+ const m = src.match(/url=(.+?)&/);
+ if (!m || m.length !== 2) return null;
+ return (
+ 'https://w.soundcloud.com/player/?url=' +
+ m[1] +
'&auto_play=false&hide_related=false&show_comments=true' +
'&show_user=true&show_reposts=false&visual=true'
- }
- }
+ );
+ },
+ },
];
-export const noImageText = '(Image not shown due to low ratings)'
+export const noImageText = '(Image not shown due to low ratings)';
export const allowedTags = `
div, iframe, del,
a, p, b, i, q, br, ul, li, ol, img, h1, h2, h3, h4, h5, h6, hr,
blockquote, pre, code, em, strong, center, table, thead, tbody, tr, th, td,
strike, sup, sub
-`.trim().split(/,\s*/)
+`
+ .trim()
+ .split(/,\s*/);
// Medium insert plugin uses: div, figure, figcaption, iframe
-export default ({large = true, highQualityPost = true, noImage = false, sanitizeErrors = []}) => ({
+export default ({
+ large = true,
+ highQualityPost = true,
+ noImage = false,
+ sanitizeErrors = [],
+}) => ({
allowedTags,
- // figure, figcaption,
+ // figure, figcaption,
// SEE https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
allowedAttributes: {
// "src" MUST pass a whitelist (below)
- iframe: ['src', 'width', 'height', 'frameborder', 'allowfullscreen',
- 'webkitallowfullscreen', 'mozallowfullscreen'],
+ iframe: [
+ 'src',
+ 'width',
+ 'height',
+ 'frameborder',
+ 'allowfullscreen',
+ 'webkitallowfullscreen',
+ 'mozallowfullscreen',
+ ],
// class attribute is strictly whitelisted (below)
// and title is only set in the case of a phishing warning
@@ -55,84 +78,112 @@ export default ({large = true, highQualityPost = true, noImage = false, sanitize
// style is subject to attack, filtering more below
td: ['style'],
img: ['src', 'alt'],
- a: ['href', 'rel'],
+
+ // title is only set in the case of an external link warning
+ a: ['href', 'rel', 'title'],
},
+ allowedSchemes: ['http', 'https', 'steem'],
transformTags: {
iframe: (tagName, attribs) => {
const srcAtty = attribs.src;
- for(const item of iframeWhitelist)
- if(item.re.test(srcAtty)) {
- const src = typeof item.fn === 'function' ? item.fn(srcAtty, item.re) : srcAtty
- if(!src) break
+ for (const item of iframeWhitelist)
+ if (item.re.test(srcAtty)) {
+ const src =
+ typeof item.fn === 'function'
+ ? item.fn(srcAtty, item.re)
+ : srcAtty;
+ if (!src) break;
return {
tagName: 'iframe',
attribs: {
frameborder: '0',
allowfullscreen: 'allowfullscreen',
webkitallowfullscreen: 'webkitallowfullscreen', // deprecated but required for vimeo : https://vimeo.com/forums/help/topic:278181
- mozallowfullscreen: 'mozallowfullscreen', // deprecated but required for vimeo
+ mozallowfullscreen: 'mozallowfullscreen', // deprecated but required for vimeo
src,
- width: large ? '640' : '480',
+ width: large ? '640' : '480',
height: large ? '360' : '270',
},
- }
+ };
}
- console.log('Blocked, did not match iframe "src" white list urls:', tagName, attribs)
- sanitizeErrors.push('Invalid iframe URL: ' + srcAtty)
- return {tagName: 'div', text: `(Unsupported ${srcAtty})`}
+ console.log(
+ 'Blocked, did not match iframe "src" white list urls:',
+ tagName,
+ attribs
+ );
+ sanitizeErrors.push('Invalid iframe URL: ' + srcAtty);
+ return { tagName: 'div', text: `(Unsupported ${srcAtty})` };
},
img: (tagName, attribs) => {
- if(noImage) return {tagName: 'div', text: noImageText}
+ if (noImage) return { tagName: 'div', text: noImageText };
//See https://github.com/punkave/sanitize-html/issues/117
- let {src, alt} = attribs
- if(!/^(https?:)?\/\//i.test(src)) {
- console.log('Blocked, image tag src does not appear to be a url', tagName, attribs)
- sanitizeErrors.push('An image in this post did not save properly.')
- return {tagName: 'img', attribs: {src: 'brokenimg.jpg'}}
+ let { src, alt } = attribs;
+ if (!/^(https?:)?\/\//i.test(src)) {
+ console.log(
+ 'Blocked, image tag src does not appear to be a url',
+ tagName,
+ attribs
+ );
+ sanitizeErrors.push(
+ 'An image in this post did not save properly.'
+ );
+ return { tagName: 'img', attribs: { src: 'brokenimg.jpg' } };
}
// replace http:// with // to force https when needed
- src = src.replace(/^http:\/\//i, '//')
- let atts = {src}
- if(alt && alt !== '') atts.alt = alt
- return {tagName, attribs: atts}
+ src = src.replace(/^http:\/\//i, '//');
+ let atts = { src };
+ if (alt && alt !== '') atts.alt = alt;
+ return { tagName, attribs: atts };
},
div: (tagName, attribs) => {
- const attys = {}
- const classWhitelist = ['pull-right', 'pull-left', 'text-justify', 'text-rtl', 'text-center', 'text-right', 'videoWrapper', 'phishy']
- const validClass = classWhitelist.find(e => attribs.class == e)
- if(validClass)
- attys.class = validClass
- if (validClass === 'phishy' && attribs.title === getPhishingWarningMessage())
- attys.title = attribs.title
+ const attys = {};
+ const classWhitelist = [
+ 'pull-right',
+ 'pull-left',
+ 'text-justify',
+ 'text-rtl',
+ 'text-center',
+ 'text-right',
+ 'videoWrapper',
+ 'phishy',
+ ];
+ const validClass = classWhitelist.find(e => attribs.class == e);
+ if (validClass) attys.class = validClass;
+ if (
+ validClass === 'phishy' &&
+ attribs.title === getPhishingWarningMessage()
+ )
+ attys.title = attribs.title;
return {
tagName,
- attribs: attys
- }
+ attribs: attys,
+ };
},
td: (tagName, attribs) => {
- const attys = {}
- if(attribs.style === 'text-align:right')
- attys.style = 'text-align:right'
+ const attys = {};
+ if (attribs.style === 'text-align:right')
+ attys.style = 'text-align:right';
return {
tagName,
- attribs: attys
- }
+ attribs: attys,
+ };
},
a: (tagName, attribs) => {
- let {href} = attribs
- if(!href) href = '#'
- href = href.trim()
- const attys = {href}
+ let { href } = attribs;
+ if (!href) href = '#';
+ href = href.trim();
+ const attys = { href };
// If it's not a (relative or absolute) steemit URL...
if (!href.match(/^(\/(?!\/)|https:\/\/steemit.com)/)) {
// attys.target = '_blank' // pending iframe impl https://mathiasbynens.github.io/rel-noopener/
- attys.rel = highQualityPost ? 'noopener' : 'nofollow noopener'
+ attys.rel = highQualityPost ? 'noopener' : 'nofollow noopener';
+ attys.title = getExternalLinkWarningMessage();
}
return {
tagName,
- attribs: attys
- }
+ attribs: attys,
+ };
},
- }
-})
+ },
+});
diff --git a/src/app/utils/ServerApiClient.js b/src/app/utils/ServerApiClient.js
index d4bae6d7520257701e12569fcac2fe7ad5978663..5c19c197cceef632d70b3408253ea74e0c17733e 100644
--- a/src/app/utils/ServerApiClient.js
+++ b/src/app/utils/ServerApiClient.js
@@ -1,5 +1,4 @@
-import {NTYPES, notificationsArrayToMap} from 'app/utils/Notifications';
-import {api} from 'steem';
+import { api } from '@steemit/steem-js';
const request_base = {
method: 'post',
@@ -7,95 +6,83 @@ const request_base = {
credentials: 'same-origin',
headers: {
Accept: 'application/json',
- 'Content-type': 'application/json'
- }
+ 'Content-type': 'application/json',
+ },
};
export function serverApiLogin(account, signatures) {
if (!process.env.BROWSER || window.$STM_ServerBusy) return;
- const request = Object.assign({}, request_base, {body: JSON.stringify({account, signatures, csrf: $STM_csrf})});
+ const request = Object.assign({}, request_base, {
+ body: JSON.stringify({ account, signatures, csrf: $STM_csrf }),
+ });
fetch('/api/v1/login_account', request);
}
export function serverApiLogout() {
if (!process.env.BROWSER || window.$STM_ServerBusy) return;
- const request = Object.assign({}, request_base, {body: JSON.stringify({csrf: $STM_csrf})});
+ const request = Object.assign({}, request_base, {
+ body: JSON.stringify({ csrf: $STM_csrf }),
+ });
fetch('/api/v1/logout_account', request);
}
let last_call;
export function serverApiRecordEvent(type, val, rate_limit_ms = 5000) {
if (!process.env.BROWSER || window.$STM_ServerBusy) return;
- if (last_call && (new Date() - last_call) < rate_limit_ms) return;
+ if (last_call && new Date() - last_call < rate_limit_ms) return;
last_call = new Date();
const value = val && val.stack ? `${val.toString()} | ${val.stack}` : val;
- const request = Object.assign({}, request_base, {body: JSON.stringify({csrf: $STM_csrf, type, value})});
- fetch('/api/v1/record_event', request);
- api.call('overseer.collect', {collection: 'event', metadata: {type, value}}, (error) => {
- // if (error) console.warn('overseer error', error, error.data);
+ const request = Object.assign({}, request_base, {
+ body: JSON.stringify({ csrf: $STM_csrf, type, value }),
});
-}
-
-export function getNotifications(account) {
- if (!process.env.BROWSER || window.$STM_ServerBusy) return Promise.resolve(null);
- const request = Object.assign({}, request_base, {method: 'get'});
- return fetch(`/api/v1/notifications/${account}`, request).then(r => r.json()).then(res => {
- return notificationsArrayToMap(res);
-});
-}
-
-export function markNotificationRead(account, fields) {
- if (!process.env.BROWSER || window.$STM_ServerBusy) return Promise.resolve(null);
- const request = Object.assign({}, request_base, {method: 'put', mode: 'cors'});
- const field_nums_str = fields.map(f => NTYPES.indexOf(f)).join('-');
- return fetch(`/api/v1/notifications/${account}/${field_nums_str}`, request).then(r => r.json()).then(res => {
- return notificationsArrayToMap(res);
-});
+ fetch('/api/v1/record_event', request);
+ api.call(
+ 'overseer.collect',
+ { collection: 'event', metadata: { type, value } },
+ error => {
+ // if (error) console.warn('overseer error', error, error.data);
+ }
+ );
}
let last_page, last_views, last_page_promise;
export function recordPageView(page, ref, account) {
if (last_page_promise && page === last_page) return last_page_promise;
- if (window.ga) { // virtual pageview
+ if (window.ga) {
+ // virtual pageview
window.ga('set', 'page', page);
window.ga('send', 'pageview');
}
- api.call('overseer.pageview', {page, referer: ref, account}, (error) => {
+ api.call('overseer.pageview', { page, referer: ref, account }, error => {
// if (error) console.warn('overseer error', error, error.data);
});
- if (!process.env.BROWSER || window.$STM_ServerBusy) return Promise.resolve(0);
- const request = Object.assign({}, request_base, {body: JSON.stringify({csrf: $STM_csrf, page, ref})});
- last_page_promise = fetch(`/api/v1/page_view`, request).then(r => r.json()).then(res => {
- last_views = res.views;
- return last_views;
-});
+ if (!process.env.BROWSER || window.$STM_ServerBusy)
+ return Promise.resolve(0);
+ const request = Object.assign({}, request_base, {
+ body: JSON.stringify({ csrf: $STM_csrf, page, ref }),
+ });
+ last_page_promise = fetch(`/api/v1/page_view`, request)
+ .then(r => r.json())
+ .then(res => {
+ last_views = res.views;
+ return last_views;
+ });
last_page = page;
return last_page_promise;
}
-export function webPushRegister(account, webpush_params) {
- if (!process.env.BROWSER || window.$STM_ServerBusy) return;
- const request = Object.assign({}, request_base, {body: JSON.stringify({csrf: $STM_csrf, account, webpush_params})});
- fetch('/api/v1/notifications/register', request);
-}
-
-export function sendConfirmEmail(account) {
- const request = Object.assign({}, request_base, {body: JSON.stringify({csrf: $STM_csrf, account})});
- fetch('/api/v1/notifications/send_confirm', request);
-}
-
export function saveCords(x, y) {
- const request = Object.assign({}, request_base, {body: JSON.stringify({csrf: $STM_csrf, x: x, y: y})});
+ const request = Object.assign({}, request_base, {
+ body: JSON.stringify({ csrf: $STM_csrf, x: x, y: y }),
+ });
fetch('/api/v1/save_cords', request);
}
export function setUserPreferences(payload) {
- if (!process.env.BROWSER || window.$STM_ServerBusy) return Promise.resolve();
- const request = Object.assign({}, request_base, {body: JSON.stringify({csrf: window.$STM_csrf, payload})});
+ if (!process.env.BROWSER || window.$STM_ServerBusy)
+ return Promise.resolve();
+ const request = Object.assign({}, request_base, {
+ body: JSON.stringify({ csrf: window.$STM_csrf, payload }),
+ });
return fetch('/api/v1/setUserPreferences', request);
}
-
-if (process.env.BROWSER) {
- window.getNotifications = getNotifications;
- window.markNotificationRead = markNotificationRead;
-}
diff --git a/src/app/utils/SlateEditor/Align.js b/src/app/utils/SlateEditor/Align.js
index b1c7d154a12154a4d5eb2dc8829f6b73d8cd38ad..671866ad7437c402c53b3f73219702474a00adb4 100644
--- a/src/app/utils/SlateEditor/Align.js
+++ b/src/app/utils/SlateEditor/Align.js
@@ -1,26 +1,30 @@
-import React from 'react'
+import React from 'react';
export default class Align extends React.Component {
-
getAlignClass = () => {
- const {node} = this.props
- switch(node.data.get('align')) {
- case 'text-right': return 'text-right';
- case 'text-left': return 'text-left';
- case 'text-center': return 'text-center';
- case 'pull-right': return 'pull-right';
- case 'pull-left': return 'pull-left';
+ const { node } = this.props;
+ switch (node.data.get('align')) {
+ case 'text-right':
+ return 'text-right';
+ case 'text-left':
+ return 'text-left';
+ case 'text-center':
+ return 'text-center';
+ case 'pull-right':
+ return 'pull-right';
+ case 'pull-left':
+ return 'pull-left';
}
- }
+ };
render = () => {
- const { node, attributes, children } = this.props
+ const { node, attributes, children } = this.props;
const className = this.getAlignClass();
return (
{children}
- )
- }
+ );
+ };
}
diff --git a/src/app/utils/SlateEditor/DemoState.js b/src/app/utils/SlateEditor/DemoState.js
index 7dacf141a595cdf10fc905b0c04db94e7ca4a2ac..e752e8e7a6fb8f231a3bae7e6a01ebfc76fbbeb4 100644
--- a/src/app/utils/SlateEditor/DemoState.js
+++ b/src/app/utils/SlateEditor/DemoState.js
@@ -1,14 +1,14 @@
export default {
- "nodes": [
- {
- "kind": "block",
- "type": "paragraph",
- "nodes": [
+ nodes: [
{
- "kind": "text",
- "text": ""
+ kind: 'block',
+ type: 'paragraph',
+ nodes: [
+ {
+ kind: 'text',
+ text: '',
+ },
+ ],
},
- ]
- }
- ]
-}
+ ],
+};
diff --git a/src/app/utils/SlateEditor/HRule.js b/src/app/utils/SlateEditor/HRule.js
index 774a7ef0a6630f7c42e5e0b836fb0814966c6311..c5cf11dd8ce3d27d7ad4d19c11a3cd8abba44771 100644
--- a/src/app/utils/SlateEditor/HRule.js
+++ b/src/app/utils/SlateEditor/HRule.js
@@ -1,10 +1,10 @@
-import React from 'react'
+import React from 'react';
export default class HRule extends React.Component {
render() {
- const { node, state } = this.props
- const isFocused = state.selection.hasEdgeIn(node)
- const className = isFocused ? 'active' : null
- return
+ const { node, state } = this.props;
+ const isFocused = state.selection.hasEdgeIn(node);
+ const className = isFocused ? 'active' : null;
+ return ;
}
}
diff --git a/src/app/utils/SlateEditor/Helpers.js b/src/app/utils/SlateEditor/Helpers.js
index 2e85d72931b89fff55083eca6d9c9f4e9fc65d6d..d9b3d123905596c7877d305b3e0ab2f6360f5d49 100644
--- a/src/app/utils/SlateEditor/Helpers.js
+++ b/src/app/utils/SlateEditor/Helpers.js
@@ -2,17 +2,23 @@ const findParentTag = (el, tag, depth = 0) => {
if (!el) return null;
if (el.tagName == tag) return el;
return findParentTag(el.parentNode, tag, depth + 1);
-}
+};
export const getCollapsedClientRect = () => {
const selection = document.getSelection();
- if (selection.rangeCount === 0 || !selection.getRangeAt || !selection.getRangeAt(0) || !selection.getRangeAt(0).startContainer || !selection.getRangeAt(0).startContainer.getBoundingClientRect) {
+ if (
+ selection.rangeCount === 0 ||
+ !selection.getRangeAt ||
+ !selection.getRangeAt(0) ||
+ !selection.getRangeAt(0).startContainer ||
+ !selection.getRangeAt(0).startContainer.getBoundingClientRect
+ ) {
return null;
}
const node = selection.getRangeAt(0).startContainer;
- if(! findParentTag(node, 'P')) return; // only show sidebar at the beginning of an empty
+ if (!findParentTag(node, 'P')) return; // only show sidebar at the beginning of an empty
const rect = node.getBoundingClientRect();
return rect;
-}
+};
diff --git a/src/app/utils/SlateEditor/Iframe.js b/src/app/utils/SlateEditor/Iframe.js
index f1dd15eae88c411bf4fca9dc7e2b7cdfb3d0ca39..822081d2c7a8e2fc31086ec1e52ab3e19a5bae3a 100644
--- a/src/app/utils/SlateEditor/Iframe.js
+++ b/src/app/utils/SlateEditor/Iframe.js
@@ -1,60 +1,59 @@
-import React from 'react'
-import linksRe from 'app/utils/Links'
+import React from 'react';
+import linksRe from 'app/utils/Links';
export default class Iframe extends React.Component {
-
- normalizeEmbedUrl = (url) => {
+ normalizeEmbedUrl = url => {
let match;
// Detect youtube URLs
- match = url.match(linksRe.youTubeId)
- if(match && match.length >= 2) {
- return 'https://www.youtube.com/embed/' + match[1]
+ match = url.match(linksRe.youTubeId);
+ if (match && match.length >= 2) {
+ return 'https://www.youtube.com/embed/' + match[1];
}
// Detect vimeo
- match = url.match(linksRe.vimeoId)
- if(match && match.length >= 2) {
- return 'https://player.vimeo.com/video/' + match[1]
+ match = url.match(linksRe.vimeoId);
+ if (match && match.length >= 2) {
+ return 'https://player.vimeo.com/video/' + match[1];
}
- console.log("unable to auto-detect embed url", url)
- return null
- }
+ console.log('unable to auto-detect embed url', url);
+ return null;
+ };
- onChange = (e) => {
- const { node, state, editor } = this.props
- const value = e.target.value
+ onChange = e => {
+ const { node, state, editor } = this.props;
+ const value = e.target.value;
- const src = this.normalizeEmbedUrl(value) || value
+ const src = this.normalizeEmbedUrl(value) || value;
const next = editor
.getState()
.transform()
- .setNodeByKey(node.key, {data: {src}})
- .apply()
+ .setNodeByKey(node.key, { data: { src } })
+ .apply();
- editor.onChange(next)
- }
+ editor.onChange(next);
+ };
- onClick = (e) => {
+ onClick = e => {
// stop propagation so that the void node itself isn't focused, since that would unfocus the input.
- e.stopPropagation()
- }
+ e.stopPropagation();
+ };
render = () => {
- const { node, state, attributes } = this.props
- const isFocused = state.selection.hasEdgeIn(node)
- const className = isFocused ? 'active' : null
+ const { node, state, attributes } = this.props;
+ const isFocused = state.selection.hasEdgeIn(node);
+ const className = isFocused ? 'active' : null;
const lockStyle = {
position: 'absolute',
- top: '0px',
- left: '0px',
- width: '100%',
- height: '100%',
+ top: '0px',
+ left: '0px',
+ width: '100%',
+ height: '100%',
background: 'rgba(0,0,0,0.1)',
- }
+ };
return (
@@ -65,50 +64,50 @@ export default class Iframe extends React.Component {
- )
- }
+ );
+ };
renderFrame = () => {
- let src = this.props.node.data.get('src')
- src = this.normalizeEmbedUrl(src) || src
+ let src = this.props.node.data.get('src');
+ src = this.normalizeEmbedUrl(src) || src;
return (
- )
- }
+ );
+ };
renderInput = () => {
- const src = this.props.node.data.get('src')
+ const src = this.props.node.data.get('src');
const style = {
fontFamily: 'Arial',
- margin: '200px auto',
- width: '90%',
- padding: '1rem 0.5rem',
+ margin: '200px auto',
+ width: '90%',
+ padding: '1rem 0.5rem',
background: 'rgba(255,255,255,0.9)',
- display: 'block',
- textAlign: 'center',
- color: 'black',
+ display: 'block',
+ textAlign: 'center',
+ color: 'black',
borderRadius: '5px',
- }
+ };
return (
- )
- }
+ );
+ };
}
diff --git a/src/app/utils/SlateEditor/Image.js b/src/app/utils/SlateEditor/Image.js
index 2c297d5c927b6affdc26b7fac15824c88c17eeaa..df535244fe9ca2c9207a6399ad4b82674425d627 100644
--- a/src/app/utils/SlateEditor/Image.js
+++ b/src/app/utils/SlateEditor/Image.js
@@ -1,5 +1,5 @@
-import React from 'react'
-import {connect} from 'react-redux'
+import React from 'react';
+import { connect } from 'react-redux';
export default connect(
(state, ownProps) => ownProps,
@@ -7,111 +7,132 @@ export default connect(
uploadImage: (file, dataUrl, filename, progress) => {
dispatch({
type: 'user/UPLOAD_IMAGE',
- payload: {file, dataUrl, filename, progress},
- })
+ payload: { file, dataUrl, filename, progress },
+ });
},
})
)(
+ class Image extends React.Component {
+ state = {
+ progress: {},
+ };
+
+ componentWillMount() {
+ const file = this.props.node.data.get('file');
+ // Save `file` for "Retry"
+ // Try to load incase data url was loaded from a draft
+ this.setState({ file });
+ }
-class Image extends React.Component {
- state = {
- progress: {},
- };
-
- componentWillMount() {
- const file = this.props.node.data.get('file')
- // Save `file` for "Retry"
- // Try to load incase data url was loaded from a draft
- this.setState({ file })
- }
-
- componentDidMount() {
- console.log("** image mounted..", this.state, this.props)
- this.load()
- }
-
- setImageSrc(src, filename) {
- const {editor, node} = this.props
- const state = editor.getState();
- const next = state
- .transform()
- .setNodeByKey(node.key, { data: { src, alt: filename } })
- .apply()
- editor.onChange(next)
- }
+ componentDidMount() {
+ console.log('** image mounted..', this.state, this.props);
+ this.load();
+ }
- load = () => {
- let dataUrl, filename
- const {file} = this.state
- if(file) {
- // image dropped -- show a quick preview
- console.log("** image being loaded.. ----->", file)
- const reader = new FileReader()
- reader.addEventListener('load', () => {
- dataUrl = reader.result
- this.setImageSrc(dataUrl, file.name)
- })
- reader.readAsDataURL(file)
- filename = file.name
- } else {
- // draft, recover data using the preview data url
- const {data} = this.props.node
- const src = data.get('src')
- if(/^data:/.test(src)) {
- dataUrl = src
- filename = data.get('alt')
- }
+ setImageSrc(src, filename) {
+ const { editor, node } = this.props;
+ const state = editor.getState();
+ const next = state
+ .transform()
+ .setNodeByKey(node.key, { data: { src, alt: filename } })
+ .apply();
+ editor.onChange(next);
}
- if(!file && !dataUrl) return
- this.setState({ progress: {}, uploading: true}, () => {
- const {uploadImage} = this.props
- uploadImage(file, dataUrl, filename, progress => {
- this.setState({ progress, uploading: false })
- if(progress.url) {
- this.setImageSrc(progress.url, filename)
+ load = () => {
+ let dataUrl, filename;
+ const { file } = this.state;
+ if (file) {
+ // image dropped -- show a quick preview
+ console.log('** image being loaded.. ----->', file);
+ const reader = new FileReader();
+ reader.addEventListener('load', () => {
+ dataUrl = reader.result;
+ this.setImageSrc(dataUrl, file.name);
+ });
+ reader.readAsDataURL(file);
+ filename = file.name;
+ } else {
+ // draft, recover data using the preview data url
+ const { data } = this.props.node;
+ const src = data.get('src');
+ if (/^data:/.test(src)) {
+ dataUrl = src;
+ filename = data.get('alt');
}
- })
- })
- }
-
- render() {
- const { node, state, attributes } = this.props
-
- const isFocused = state.selection.hasEdgeIn(node)
- const className = isFocused ? 'active' : null
-
- const prefix = $STM_Config.img_proxy_prefix ? ($STM_Config.img_proxy_prefix + '0x0/') : ''
-
- const alt = node.data.get('alt')
- const src = node.data.get('src')
-
- console.log("** rendering image... src:", (src ? src.substring(0, 30) + '...' : '(null)'), state)
-
- if(!src) return
Loading Image…
-
- if(/^https?:\/\//.test(src)) return
-
- const img =
-
- const {uploading} = this.state
- if(uploading)
- return
- {img}
-
- Uploading Image…
-
+ }
- const { error } = this.state.progress
- return
- {img}
-
-
- Image was not Saved (retry )
-
- {error}
-
-
-
+ if (!file && !dataUrl) return;
+ this.setState({ progress: {}, uploading: true }, () => {
+ const { uploadImage } = this.props;
+ uploadImage(file, dataUrl, filename, progress => {
+ this.setState({ progress, uploading: false });
+ if (progress.url) {
+ this.setImageSrc(progress.url, filename);
+ }
+ });
+ });
+ };
+
+ render() {
+ const { node, state, attributes } = this.props;
+
+ const isFocused = state.selection.hasEdgeIn(node);
+ const className = isFocused ? 'active' : null;
+
+ const prefix = $STM_Config.img_proxy_prefix
+ ? $STM_Config.img_proxy_prefix + '0x0/'
+ : '';
+
+ const alt = node.data.get('alt');
+ const src = node.data.get('src');
+
+ console.log(
+ '** rendering image... src:',
+ src ? src.substring(0, 30) + '...' : '(null)',
+ state
+ );
+
+ if (!src)
+ return
Loading Image… ;
+
+ if (/^https?:\/\//.test(src))
+ return (
+
+ );
+
+ const img =
;
+
+ const { uploading } = this.state;
+ if (uploading)
+ return (
+
+ {img}
+
+ Uploading Image…
+
+ );
+
+ const { error } = this.state.progress;
+ return (
+
+ {img}
+
+
+ Image was not Saved (
+ retry
+ )
+
+ {error}
+
+
+
+ );
+ }
}
-})
+);
diff --git a/src/app/utils/SlateEditor/Link.js b/src/app/utils/SlateEditor/Link.js
index 76593e33a19b26bb28bb2d165f33b77e283e09a2..b3a3b77293d436d17016eb1dc2962ca9c1611baa 100644
--- a/src/app/utils/SlateEditor/Link.js
+++ b/src/app/utils/SlateEditor/Link.js
@@ -1,18 +1,21 @@
-import React from 'react'
+import React from 'react';
export default class Link extends React.Component {
state = {};
- componentDidMount() {
- }
+ componentDidMount() {}
render() {
- const { node, state, attributes, children } = this.props
+ const { node, state, attributes, children } = this.props;
- const isFocused = state.selection.hasEdgeIn(node)
- const className = isFocused ? 'active' : null
- const href = node.data.get('href')
+ const isFocused = state.selection.hasEdgeIn(node);
+ const className = isFocused ? 'active' : null;
+ const href = node.data.get('href');
- return
{children}
+ return (
+
+ {children}
+
+ );
}
}
diff --git a/src/app/utils/SlateEditor/Schema.js b/src/app/utils/SlateEditor/Schema.js
index afda68eedffd293622cd39be2cd4d225ed4a19b6..c513527eacc55bad90a5569900463ac1f5e1a232 100644
--- a/src/app/utils/SlateEditor/Schema.js
+++ b/src/app/utils/SlateEditor/Schema.js
@@ -1,9 +1,9 @@
-import React from 'react'
-import Link from 'app/utils/SlateEditor/Link'
-import Image from 'app/utils/SlateEditor/Image'
-import Iframe from 'app/utils/SlateEditor/Iframe'
-import HRule from 'app/utils/SlateEditor/HRule'
-import Align from 'app/utils/SlateEditor/Align'
+import React from 'react';
+import Link from 'app/utils/SlateEditor/Link';
+import Image from 'app/utils/SlateEditor/Image';
+import Iframe from 'app/utils/SlateEditor/Iframe';
+import HRule from 'app/utils/SlateEditor/HRule';
+import Align from 'app/utils/SlateEditor/Align';
const $ = require('cheerio');
@@ -13,13 +13,27 @@ const $ = require('cheerio');
export const schema = {
defaultNode: 'paragraph',
toolbarMarks: [
- { type: 'bold', label:
B },
- { type: 'italic', label:
i },
+ { type: 'bold', label:
B },
+ { type: 'italic', label:
i },
//{ type: 'underline', label:
U },
//{ type: 'strike', label:
S },
- { type: 'code', label:
{'{}'} },
- { type: 'sup', label:
x2 },
- { type: 'sub', label:
x2 },
+ { type: 'code', label:
{'{}'} },
+ {
+ type: 'sup',
+ label: (
+
+ x2
+
+ ),
+ },
+ {
+ type: 'sub',
+ label: (
+
+ x2
+
+ ),
+ },
],
// blockTypes: {...Blocks,},
@@ -27,40 +41,67 @@ export const schema = {
// sidebarTypes: [],
nodes: {
- 'paragraph': ({ children, attributes }) =>
{children}
,
- 'code-block': ({ children, attributes }) =>
{children},
- 'block-quote': ({ children, attributes }) =>
{children} ,
- 'bulleted-list': ({ children, attributes }) =>
,
- 'numbered-list': ({ children, attributes }) =>
{children} ,
- 'heading-one': ({ children, attributes }) =>
{children} ,
- 'heading-two': ({ children, attributes }) =>
{children} ,
- 'heading-three': ({ children, attributes }) =>
{children} ,
- 'heading-four': ({ children, attributes }) =>
{children} ,
- 'list-item': ({ children, attributes }) =>
{children} ,
- 'table': ({ children, attributes }) =>
,
- 'thead': ({ children, attributes }) =>
{children} ,
- 'tbody': ({ children, attributes }) =>
{children} ,
- 'tr': ({ children, attributes }) =>
{children} ,
- 'td': ({ children, attributes }) =>
{children} ,
- 'th': ({ children, attributes }) =>
{children} ,
- 'hr': HRule,
- 'image': Image,
- 'link': Link,
- 'embed': Iframe,
- 'align': Align,
+ paragraph: ({ children, attributes }) => (
+
{children}
+ ),
+ 'code-block': ({ children, attributes }) => (
+
+ {children}
+
+ ),
+ 'block-quote': ({ children, attributes }) => (
+
{children}
+ ),
+ 'bulleted-list': ({ children, attributes }) => (
+
+ ),
+ 'numbered-list': ({ children, attributes }) => (
+
{children}
+ ),
+ 'heading-one': ({ children, attributes }) => (
+
{children}
+ ),
+ 'heading-two': ({ children, attributes }) => (
+
{children}
+ ),
+ 'heading-three': ({ children, attributes }) => (
+
{children}
+ ),
+ 'heading-four': ({ children, attributes }) => (
+
{children}
+ ),
+ 'list-item': ({ children, attributes }) => (
+
{children}
+ ),
+ table: ({ children, attributes }) => (
+
+ ),
+ thead: ({ children, attributes }) => (
+
{children}
+ ),
+ tbody: ({ children, attributes }) => (
+
{children}
+ ),
+ tr: ({ children, attributes }) =>
{children} ,
+ td: ({ children, attributes }) =>
{children} ,
+ th: ({ children, attributes }) =>
{children} ,
+ hr: HRule,
+ image: Image,
+ link: Link,
+ embed: Iframe,
+ align: Align,
},
marks: {
- bold: props =>
{props.children} ,
- code: props =>
{props.children},
- italic: props =>
{props.children} ,
+ bold: props =>
{props.children} ,
+ code: props =>
{props.children},
+ italic: props =>
{props.children} ,
underline: props =>
{props.children} ,
- strike: props =>
{props.children},
- sub: props =>
{props.children} ,
- sup: props =>
{props.children} ,
+ strike: props =>
{props.children},
+ sub: props =>
{props.children} ,
+ sup: props =>
{props.children} ,
},
-}
-
+};
/**
* Rules for de/serializing editor state to and from HTML
@@ -68,37 +109,37 @@ export const schema = {
// Map html --> block type
const BLOCK_TAGS = {
- p: 'paragraph',
+ p: 'paragraph',
blockquote: 'block-quote',
- pre: 'code-block',
- h1: 'heading-one',
- h2: 'heading-two',
- h3: 'heading-three',
- h4: 'heading-four',
- ul: 'bulleted-list',
- ol: 'numbered-list',
- li: 'list-item',
- hr: 'hr',
- table: 'table',
- thead: 'thead',
- tbody: 'tbody',
- tr: 'tr',
- td: 'td',
- th: 'th',
-}
+ pre: 'code-block',
+ h1: 'heading-one',
+ h2: 'heading-two',
+ h3: 'heading-three',
+ h4: 'heading-four',
+ ul: 'bulleted-list',
+ ol: 'numbered-list',
+ li: 'list-item',
+ hr: 'hr',
+ table: 'table',
+ thead: 'thead',
+ tbody: 'tbody',
+ tr: 'tr',
+ td: 'td',
+ th: 'th',
+};
// Map HTML --> mark type
const MARK_TAGS = {
- em: 'italic',
- i: 'italic',
+ em: 'italic',
+ i: 'italic',
strong: 'bold',
- b: 'bold',
- u: 'underline',
- del: 'strike',
+ b: 'bold',
+ u: 'underline',
+ del: 'strike',
strike: 'strike',
- sup: 'sup',
- sub: 'sub',
-}
+ sup: 'sup',
+ sub: 'sub',
+};
const validAligns = [
'pull-right',
@@ -106,14 +147,14 @@ const validAligns = [
'text-justify',
'text-rtl',
'text-center',
- 'text-right']
+ 'text-right',
+];
/**
* Rules for converting from and to HTML. The first rules are highest priority,
* with unmatched cases (i.e. null return) falling through to those below.
*/
export const HtmlRules = [
-
// Catch-all debug wrapper
{
//deserialize: (el, next) => console.log("** deserialize: ", $.html(el).replace(/\n/g, "\\n")),
@@ -123,219 +164,279 @@ export const HtmlRules = [
// Alignment wrapper
{
deserialize: (el, next) => {
- if(el.tagName == 'center') {
+ if (el.tagName == 'center') {
return {
kind: 'block',
type: 'align',
- data: {align: 'text-center'},
- nodes: next(el.children)}
+ data: { align: 'text-center' },
+ nodes: next(el.children),
+ };
}
- if(el.tagName == 'div') {
- const align = el.attribs.class
- if(! validAligns.includes(align)) return;
+ if (el.tagName == 'div') {
+ const align = el.attribs.class;
+ if (!validAligns.includes(align)) return;
return {
kind: 'block',
type: 'align',
- data: {align},
- nodes: next(el.children)}
+ data: { align },
+ nodes: next(el.children),
+ };
}
},
serialize: (object, children) => {
- if(object.kind == 'block' && object.type == 'align') {
- const align = object.data.get('align')
- return
{children}
+ if (object.kind == 'block' && object.type == 'align') {
+ const align = object.data.get('align');
+ return
{children}
;
}
- }
+ },
},
// Block rules
{
deserialize: (el, next) => {
- const type = BLOCK_TAGS[el.tagName]
- if (!type) return
+ const type = BLOCK_TAGS[el.tagName];
+ if (!type) return;
// Special case for
: ignore its inner element.
- const code = el.tagName == 'pre' ? el.children[0] : null
- let children = code && code.tagName == 'code' ? code.children : el.children
+ const code = el.tagName == 'pre' ? el.children[0] : null;
+ let children =
+ code && code.tagName == 'code' ? code.children : el.children;
// due to disabled/broken whitespace normalization in cheerio/htmlparser2, perform basic cleaning...
// i.e. removal of text nodes where they are invalid -- otherwise they may convert to s in bad places
- const noTextChildren = 'ol,ul,table,thead,tbody,tr'.split(',')
- if(noTextChildren.includes(el.tagName)) {
- children = children.filter(el => el.type !== 'text')
+ const noTextChildren = 'ol,ul,table,thead,tbody,tr'.split(',');
+ if (noTextChildren.includes(el.tagName)) {
+ children = children.filter(el => el.type !== 'text');
}
// If this block-level node contains *any* tags, strip them out and wrap-align node
let center = false;
- children = children.reduce( (out, child) => {
- if(child.tagName == 'center') {
+ children = children.reduce((out, child) => {
+ if (child.tagName == 'center') {
center = true;
//child.children.map(c => out.push(c))
- out.push(...child.children)
+ out.push(...child.children);
} else {
- out.push(child)
+ out.push(child);
}
- return out
- }, [])
+ return out;
+ }, []);
// Generate output block with clean children
const block = {
kind: 'block',
type: type,
- isVoid: (type == 'hr'),
- nodes: next(children)
- }
+ isVoid: type == 'hr',
+ nodes: next(children),
+ };
// Wrap output block with align node if needed
- if(center) {
- console.log("** force-centering node")
+ if (center) {
+ console.log('** force-centering node');
return {
kind: 'block',
type: 'align',
- data: {align: 'text-center'},
- nodes: [block]
- }
+ data: { align: 'text-center' },
+ nodes: [block],
+ };
}
// Otherwise return plain block
- return block
+ return block;
},
serialize: (object, children) => {
- if(object.kind !== 'block') return
- switch(object.type) {
- case 'paragraph': return {children}
- case 'block-quote': return {children}
- case 'code-block': return {children}
- case 'heading-one': return {children}
- case 'heading-two': return {children}
- case 'heading-three': return {children}
- case 'heading-four': return {children}
- case 'bulleted-list': return
- case 'numbered-list': return {children}
- case 'list-item': return {children}
- case 'hr': return
- case 'table': return
- case 'thead': return {children}
- case 'tbody': return {children}
- case 'tr': return {children}
- case 'td': return {children}
- case 'th': return {children}
+ if (object.kind !== 'block') return;
+ switch (object.type) {
+ case 'paragraph':
+ return {children}
;
+ case 'block-quote':
+ return {children} ;
+ case 'code-block':
+ return (
+
+ {children}
+
+ );
+ case 'heading-one':
+ return {children} ;
+ case 'heading-two':
+ return {children} ;
+ case 'heading-three':
+ return {children} ;
+ case 'heading-four':
+ return {children} ;
+ case 'bulleted-list':
+ return ;
+ case 'numbered-list':
+ return {children} ;
+ case 'list-item':
+ return {children} ;
+ case 'hr':
+ return ;
+ case 'table':
+ return ;
+ case 'thead':
+ return {children} ;
+ case 'tbody':
+ return {children} ;
+ case 'tr':
+ return {children} ;
+ case 'td':
+ return {children} ;
+ case 'th':
+ return {children} ;
}
- }
+ },
},
// Mark rules
{
deserialize: (el, next) => {
- const type = MARK_TAGS[el.tagName]
- if (!type) return
+ const type = MARK_TAGS[el.tagName];
+ if (!type) return;
return {
kind: 'mark',
type: type,
- nodes: next(el.children)
- }
+ nodes: next(el.children),
+ };
},
serialize: (object, children) => {
- if(object.kind !== 'mark') return;
- switch(object.type) {
- case 'bold': return {children}
- case 'italic': return {children}
- case 'underline': return {children}
- case 'strike': return {children}
- case 'code': return {children}
- case 'sup': return {children}
- case 'sub': return {children}
+ if (object.kind !== 'mark') return;
+ switch (object.type) {
+ case 'bold':
+ return {children} ;
+ case 'italic':
+ return {children} ;
+ case 'underline':
+ return {children} ;
+ case 'strike':
+ return {children};
+ case 'code':
+ return {children};
+ case 'sup':
+ return {children} ;
+ case 'sub':
+ return {children} ;
}
- }
+ },
},
// Custom
{
deserialize: (el, next) => {
- switch(el.tagName) {
+ switch (el.tagName) {
case 'iframe':
return {
kind: 'block',
type: 'embed',
isVoid: true,
- data: {src: el.attribs.src},
- nodes: next(el.children)
- }
+ data: { src: el.attribs.src },
+ nodes: next(el.children),
+ };
case 'img':
return {
kind: 'inline',
type: 'image',
isVoid: true,
- data: {src: el.attribs.src,
- alt: el.attribs.alt},
- nodes: next(el.children)
- }
+ data: {
+ src: el.attribs.src,
+ alt: el.attribs.alt,
+ },
+ nodes: next(el.children),
+ };
case 'a':
return {
kind: 'inline',
type: 'link',
- data: {href: el.attribs.href},
- nodes: next(el.children)
- }
+ data: { href: el.attribs.href },
+ nodes: next(el.children),
+ };
case 'br':
return {
- "kind": "text",
- "ranges": [{"text": "\n"}]
- }
+ kind: 'text',
+ ranges: [{ text: '\n' }],
+ };
case 'code':
// may not be necessary after pr #406
- if($(el).closest('pre').length == 0) {
+ if ($(el).closest('pre').length == 0) {
return {
kind: 'mark',
type: 'code',
- nodes: next(el.children)
- }
+ nodes: next(el.children),
+ };
} else {
- console.log("** skipping within a ")
+ console.log('** skipping within a ');
}
}
},
serialize: (object, children) => {
- if(object.kind == 'string') return;
- if(object.kind == 'inline' && object.type == 'link') {
- const href = object.data.get('href')
- return {children}
+ if (object.kind == 'string') return;
+ if (object.kind == 'inline' && object.type == 'link') {
+ const href = object.data.get('href');
+ return {children} ;
}
- if(object.kind == 'block' && object.type == 'embed') {
- const src = object.data.get('src')
- return
+ if (object.kind == 'block' && object.type == 'embed') {
+ const src = object.data.get('src');
+ return ;
}
- if(object.kind == 'inline' && object.type == 'image') {
- const src = object.data.get('src')
- const alt = object.data.get('alt')
- if(!src) console.log("** ERR: serializing image with no src...", JSON.stringify(object))
- return
+ if (object.kind == 'inline' && object.type == 'image') {
+ const src = object.data.get('src');
+ const alt = object.data.get('alt');
+ if (!src)
+ console.log(
+ '** ERR: serializing image with no src...',
+ JSON.stringify(object)
+ );
+ return ;
}
- }
+ },
},
// debug uncaught nodes/elements
{
- deserialize: (el, next) => {if(el.type !== 'text') console.log("** no deserializer for: ", $.html(el).replace(/\n/g, "\\n"))},
- serialize: (object, children) => {if(object.kind != 'string') console.log("** no serializer for:", object.type, object.kind, 'data:', JSON.stringify(object))}
+ deserialize: (el, next) => {
+ if (el.type !== 'text')
+ console.log(
+ '** no deserializer for: ',
+ $.html(el).replace(/\n/g, '\\n')
+ );
+ },
+ serialize: (object, children) => {
+ if (object.kind != 'string')
+ console.log(
+ '** no serializer for:',
+ object.type,
+ object.kind,
+ 'data:',
+ JSON.stringify(object)
+ );
+ },
},
-]
+];
-export const getMarkdownType = (chars) => {
+export const getMarkdownType = chars => {
switch (chars) {
case '1.':
case '*':
- case '-': return 'list-item';
- case '>': return 'block-quote';
- case '#': return 'heading-one';
- case '##': return 'heading-two';
- case '###': return 'heading-three';
- case '####': return 'heading-four';
- case ' ': return 'code-block';
- case '---': return 'hr';
- default: return null;
+ case '-':
+ return 'list-item';
+ case '>':
+ return 'block-quote';
+ case '#':
+ return 'heading-one';
+ case '##':
+ return 'heading-two';
+ case '###':
+ return 'heading-three';
+ case '####':
+ return 'heading-four';
+ case ' ':
+ return 'code-block';
+ case '---':
+ return 'hr';
+ default:
+ return null;
}
-}
-
+};
diff --git a/src/app/utils/StateFunctions.js b/src/app/utils/StateFunctions.js
index d15eb2ddd952359b2b381585ace7d71cd54111de..7dffeb5531fd466e9dee8eb3536eac468d57c47b 100644
--- a/src/app/utils/StateFunctions.js
+++ b/src/app/utils/StateFunctions.js
@@ -1,147 +1,191 @@
import assert from 'assert';
import constants from 'app/redux/constants';
-import {parsePayoutAmount, repLog10} from 'app/utils/ParsersAndFormatters';
-import {Long} from 'bytebuffer';
-import {VEST_TICKER, LIQUID_TICKER} from 'app/client_config'
-import {fromJS} from 'immutable';
+import { parsePayoutAmount, repLog10 } from 'app/utils/ParsersAndFormatters';
+import { Long } from 'bytebuffer';
+import { VEST_TICKER, LIQUID_TICKER } from 'app/client_config';
+import { fromJS } from 'immutable';
-export const numberWithCommas = (x) => x.replace(/\B(?=(\d{3})+(?!\d))/g, ",")
+export const numberWithCommas = x => x.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
export function vestsToSpf(state, vesting_shares) {
- const {global} = state
- let vests = vesting_shares
+ const { global } = state;
+ let vests = vesting_shares;
if (typeof vesting_shares === 'string') {
- vests = assetFloat(vesting_shares, VEST_TICKER)
+ vests = assetFloat(vesting_shares, VEST_TICKER);
}
- const total_vests = assetFloat(global.getIn(['props', 'total_vesting_shares']), VEST_TICKER)
- const total_vest_steem = assetFloat(global.getIn(['props', 'total_vesting_fund_steem']), LIQUID_TICKER)
- return total_vest_steem * (vests / total_vests)
+ const total_vests = assetFloat(
+ global.getIn(['props', 'total_vesting_shares']),
+ VEST_TICKER
+ );
+ const total_vest_steem = assetFloat(
+ global.getIn(['props', 'total_vesting_fund_steem']),
+ LIQUID_TICKER
+ );
+ return total_vest_steem * (vests / total_vests);
}
export function vestsToSp(state, vesting_shares) {
- return vestsToSpf(state, vesting_shares).toFixed(3)
+ return vestsToSpf(state, vesting_shares).toFixed(3);
}
export function spToVestsf(state, steem_power) {
- const {global} = state
- let power = steem_power
+ const { global } = state;
+ let power = steem_power;
if (typeof power === 'string') {
- power = assetFloat(power, LIQUID_TICKER)
+ power = assetFloat(power, LIQUID_TICKER);
}
- const total_vests = assetFloat(global.getIn(['props', 'total_vesting_shares']), VEST_TICKER)
- const total_vest_steem = assetFloat(global.getIn(['props', 'total_vesting_fund_steem']), LIQUID_TICKER)
- return (steem_power / total_vest_steem) * total_vests
+ const total_vests = assetFloat(
+ global.getIn(['props', 'total_vesting_shares']),
+ VEST_TICKER
+ );
+ const total_vest_steem = assetFloat(
+ global.getIn(['props', 'total_vesting_fund_steem']),
+ LIQUID_TICKER
+ );
+ return steem_power / total_vest_steem * total_vests;
}
export function spToVests(state, vesting_shares) {
- return spToVestsf(state, vesting_shares).toFixed(6)
+ return spToVestsf(state, vesting_shares).toFixed(6);
}
export function vestingSteem(account, gprops) {
- const vests = parseFloat(account.vesting_shares.split( ' ' )[0]);
- const total_vests = parseFloat(gprops.total_vesting_shares.split( ' ' )[0]);
- const total_vest_steem = parseFloat(gprops.total_vesting_fund_steem.split( ' ' )[0]);
+ const vests = parseFloat(account.vesting_shares.split(' ')[0]);
+ const total_vests = parseFloat(gprops.total_vesting_shares.split(' ')[0]);
+ const total_vest_steem = parseFloat(
+ gprops.total_vesting_fund_steem.split(' ')[0]
+ );
const vesting_steemf = total_vest_steem * (vests / total_vests);
return vesting_steemf;
}
// How much STEEM this account has delegated out (minus received).
export function delegatedSteem(account, gprops) {
- const delegated_vests = parseFloat(account.delegated_vesting_shares.split( ' ' )[0]);
- const received_vests = parseFloat(account.received_vesting_shares.split( ' ' )[0]);
+ const delegated_vests = parseFloat(
+ account.delegated_vesting_shares.split(' ')[0]
+ );
+ const received_vests = parseFloat(
+ account.received_vesting_shares.split(' ')[0]
+ );
const vests = delegated_vests - received_vests;
- const total_vests = parseFloat(gprops.total_vesting_shares.split( ' ' )[0]);
- const total_vest_steem = parseFloat(gprops.total_vesting_fund_steem.split( ' ' )[0]);
+ const total_vests = parseFloat(gprops.total_vesting_shares.split(' ')[0]);
+ const total_vest_steem = parseFloat(
+ gprops.total_vesting_fund_steem.split(' ')[0]
+ );
const vesting_steemf = total_vest_steem * (vests / total_vests);
return vesting_steemf;
}
export function assetFloat(str, asset) {
try {
- assert.equal(typeof str, 'string')
- assert.equal(typeof asset, 'string')
- assert(new RegExp(`^\\d+(\\.\\d+)? ${asset}$`).test(str), 'Asset should be formatted like 99.99 ' + asset + ': ' + str)
- return parseFloat(str.split(' ')[0])
- } catch(e) {
+ assert.equal(typeof str, 'string');
+ assert.equal(typeof asset, 'string');
+ assert(
+ new RegExp(`^\\d+(\\.\\d+)? ${asset}$`).test(str),
+ 'Asset should be formatted like 99.99 ' + asset + ': ' + str
+ );
+ return parseFloat(str.split(' ')[0]);
+ } catch (e) {
console.log(e);
- return undefined
+ return undefined;
}
}
export function isFetchingOrRecentlyUpdated(global_status, order, category) {
- const status = global_status ? global_status.getIn([category || '', order]) : null;
+ const status = global_status
+ ? global_status.getIn([category || '', order])
+ : null;
if (!status) return false;
if (status.fetching) return true;
if (status.last_fetch) {
- const res = new Date() - status.last_fetch < constants.FETCH_DATA_EXPIRE_SEC * 1000;
+ const res =
+ new Date() - status.last_fetch <
+ constants.FETCH_DATA_EXPIRE_SEC * 1000;
return res;
}
return false;
}
export function contentStats(content) {
- if(!content) return {}
- if(!(content instanceof Map)) content = fromJS(content);
+ if (!content) return {};
+ if (!(content instanceof Map)) content = fromJS(content);
- let net_rshares_adj = Long.ZERO
- let neg_rshares = Long.ZERO
+ let net_rshares_adj = Long.ZERO;
+ let neg_rshares = Long.ZERO;
let total_votes = 0;
let up_votes = 0;
- content.get('active_votes').forEach((v) => {
- const sign = Math.sign(v.get('percent'))
- if(sign === 0) return;
- total_votes += 1
- if(sign > 0) up_votes += 1
+ // TODO: breaks if content has no active_votes attribute.
- const rshares = String(v.get('rshares'))
+ content.get('active_votes').forEach(v => {
+ const sign = Math.sign(v.get('percent'));
+ if (sign === 0) return;
+ total_votes += 1;
+ if (sign > 0) up_votes += 1;
+
+ const rshares = String(v.get('rshares'));
// For flag weight: count total neg rshares
- if(sign < 0) {
- neg_rshares = neg_rshares.add(rshares)
+ if (sign < 0) {
+ neg_rshares = neg_rshares.add(rshares);
}
// For graying: sum up total rshares from voters with non-neg reputation.
- if(String(v.get('reputation')).substring(0, 1) !== '-') {
+ if (String(v.get('reputation')).substring(0, 1) !== '-') {
// And also ignore tiny downvotes (9 digits or less)
- if(!(rshares.substring(0, 1) === '-' && rshares.length < 11)) {
- net_rshares_adj = net_rshares_adj.add(rshares)
+ if (!(rshares.substring(0, 1) === '-' && rshares.length < 11)) {
+ net_rshares_adj = net_rshares_adj.add(rshares);
}
}
});
// take negative rshares, divide by 2, truncate 10 digits (plus neg sign), count digits.
// creates a cheap log10, stake-based flag weight. 1 = approx $400 of downvoting stake; 2 = $4,000; etc
- const flagWeight = Math.max(String(neg_rshares.div(2)).length - 11, 0)
+ const flagWeight = Math.max(String(neg_rshares.div(2)).length - 11, 0);
// post must have non-trivial negative rshares to be grayed out. (more than 10 digits)
- const grayThreshold = -9999999999
- const meetsGrayThreshold = net_rshares_adj.compare(grayThreshold) < 0
+ const grayThreshold = -9999999999;
+ const meetsGrayThreshold = net_rshares_adj.compare(grayThreshold) < 0;
// to be eligible for deletion, a comment must have non-positive rshares and no replies
- const hasPositiveRshares = Long.fromString(String(content.get('net_rshares'))).gt(Long.ZERO)
- const allowDelete = !hasPositiveRshares && content.get('children') === 0
- const hasPendingPayout = parsePayoutAmount(content.get('pending_payout_value')) >= 0.02
- const authorRepLog10 = repLog10(content.get('author_reputation'))
-
- const gray = !hasPendingPayout && (authorRepLog10 < 1 || meetsGrayThreshold)
- const hide = !hasPendingPayout && (authorRepLog10 < 0) // rephide
+ const hasPositiveRshares = Long.fromString(
+ String(content.get('net_rshares'))
+ ).gt(Long.ZERO);
+ const allowDelete = !hasPositiveRshares && content.get('children') === 0;
+ const hasPendingPayout =
+ parsePayoutAmount(content.get('pending_payout_value')) >= 0.02;
+ const authorRepLog10 = repLog10(content.get('author_reputation'));
+
+ const gray =
+ !hasPendingPayout && (authorRepLog10 < 1 || meetsGrayThreshold);
+ const hide = !hasPendingPayout && authorRepLog10 < 0; // rephide
// Combine tags+category to check nsfw status
- const json = content.get('json_metadata')
- let tags = []
+ const json = content.get('json_metadata');
+ let tags = [];
try {
tags = (json && JSON.parse(json).tags) || [];
- if(typeof tags == 'string') {
+ if (typeof tags == 'string') {
tags = [tags];
- } if(!Array.isArray(tags)) {
+ }
+ if (!Array.isArray(tags)) {
tags = [];
}
- } catch(e) {
- tags = []
+ } catch (e) {
+ tags = [];
}
- tags.push(content.get('category'))
+ tags.push(content.get('category'));
const isNsfw = tags.filter(tag => tag && tag.match(/^nsfw$/i)).length > 0;
- return {hide, gray, authorRepLog10, allowDelete, isNsfw, flagWeight, total_votes, up_votes, hasPendingPayout}
+ return {
+ hide,
+ gray,
+ authorRepLog10,
+ allowDelete,
+ isNsfw,
+ flagWeight,
+ total_votes,
+ up_votes,
+ hasPendingPayout,
+ };
}
diff --git a/src/app/utils/UserUtil.js b/src/app/utils/UserUtil.js
index b8eb39aa0f790538b5375c0288374db96ca8124e..510c21a61a978550f4243501d716bc1fe3846082 100644
--- a/src/app/utils/UserUtil.js
+++ b/src/app/utils/UserUtil.js
@@ -1,67 +1,10 @@
/**
- * This file replicates and extends the contents of User.js in branches new-url-scheme && notifications-ui.
- * Additions here need to be added to ./User.js when those are merged. Imports should pull that file, and this one should be deleted.
- */
-
-
-let store = false;
-const MSG_STORE_NOT_SET = 'store is not set';
-
-export const setStore = (theStore) => {
- if(!store) {
- store = theStore;
- } else {
- throw Error("Routes.setStore - store has already been set.");
- }
-}
-
-/**
- * returns the current user's username *if* there is one.
*
- * later can be modified to return full user object if passed *true* for 1st argument
* @returns {boolean}
*/
-export const currentUser = () => {
- if (store) {
- const state = store.getState();
- if (state.user) {
- const current = state.user.getIn(['current']);
- if (current) {
- return current;
- }
- }
- } else {
- console.warn(MSG_STORE_NOT_SET);
- }
- return false;
-}
-/**
- * returns the current user's username *if* there is one.
- *
- * later can be modified to return full user object if passed *true* for 1st argument
- * @returns {boolean}
- */
-export const currentUsername = () => {
- if (store) {
- const state = store.getState();
- if (state.user) {
- const uName = state.user.getIn(['current', 'username']);
- if (uName) {
- return uName;
- }
- }
- } else {
- console.warn(MSG_STORE_NOT_SET);
- }
- return false;
-}
+export const isLoggedIn = () =>
+ typeof localStorage !== 'undefined' && !!localStorage.getItem('autopost2');
-export const isOwnAccount = (username) => {
- return (username === currentUsername());
-}
-
-/**
- *
- * @returns {boolean}
- */
-export const isLoggedIn = () => typeof localStorage !== 'undefined' && !!localStorage.getItem('autopost2');
+export default {
+ isLoggedIn,
+};
diff --git a/src/app/utils/VerifiedExchangeList.js b/src/app/utils/VerifiedExchangeList.js
index 0a86b57a233f603040120dd9862ead61d14c7853..3e1cf10bb99b2884674c8ec56b52169886beaa08 100644
--- a/src/app/utils/VerifiedExchangeList.js
+++ b/src/app/utils/VerifiedExchangeList.js
@@ -1,6 +1,9 @@
const list = `
poloniex
bittrex
-`.trim().split('\n');
+changelly
+`
+ .trim()
+ .split('\n');
export default list;
diff --git a/src/app/utils/shouldComponentUpdate.js b/src/app/utils/shouldComponentUpdate.js
index fc4b0cf52e8f1b76104fdbd7b835bfaf83b6d142..0d701cbdbe21c099326849811467c9645d1334b6 100644
--- a/src/app/utils/shouldComponentUpdate.js
+++ b/src/app/utils/shouldComponentUpdate.js
@@ -1,50 +1,57 @@
-import PureRenderMixin from 'react-addons-pure-render-mixin'
-import {Iterable} from 'immutable'
+import PureRenderMixin from 'react-addons-pure-render-mixin';
+import { Iterable } from 'immutable';
/**
Wrapper for PureRenderMixin.
This allows debugging that will show which properties changed.
*/
-export default function (instance, name) {
- const mixin = PureRenderMixin.shouldComponentUpdate.bind(instance)
- if (process.env.BROWSER && window.steemDebug_shouldComponentUpdate === undefined) {
- window.steemDebug_shouldComponentUpdate = false // console command line completion
+export default function(instance, name) {
+ const mixin = PureRenderMixin.shouldComponentUpdate.bind(instance);
+ if (
+ process.env.BROWSER &&
+ window.steemDebug_shouldComponentUpdate === undefined
+ ) {
+ window.steemDebug_shouldComponentUpdate = false; // console command line completion
}
return (nextProps, nextState) => {
- const upd = mixin(nextProps, nextState)
+ const upd = mixin(nextProps, nextState);
// Usage: steemDebug_shouldComponentUpdate = true
// Or: steemDebug_shouldComponentUpdate = /Comment/
- if (upd && process.env.BROWSER && window.steemDebug_shouldComponentUpdate) {
- const filter = window.steemDebug_shouldComponentUpdate
- if(filter.test) {
- if(!filter.test(name))
- return upd
+ if (
+ upd &&
+ process.env.BROWSER &&
+ window.steemDebug_shouldComponentUpdate
+ ) {
+ const filter = window.steemDebug_shouldComponentUpdate;
+ if (filter.test) {
+ if (!filter.test(name)) return upd;
}
- compare(name, instance.props, nextProps)
- compare(name, instance.state, nextState)
+ compare(name, instance.props, nextProps);
+ compare(name, instance.state, nextState);
}
- return upd
- }
+ return upd;
+ };
}
export function compare(name, a, b) {
- const aKeys = new Set(a && Object.keys(a))
- const bKeys = new Set(b && Object.keys(b))
- const ab = new Set([...aKeys, ...aKeys])
+ const aKeys = new Set(a && Object.keys(a));
+ const bKeys = new Set(b && Object.keys(b));
+ const ab = new Set([...aKeys, ...aKeys]);
ab.forEach(key => {
- const hasA = aKeys.has(key)
- const hasB = bKeys.has(key)
- if (!hasA && !hasB) return
- if (hasA && hasB && a[key] === b[key]) return
- const desc = !hasA ? 'added' : !hasB ? 'removed' : 'changed'
- console.log(name, key, desc)
- const aKey = a[key]
- const bKey = b[key]
- if (typeof aKey !== 'function' && typeof bKey !== 'function') { //functions are too verbose
- console.log(key, 'was', a && toJS(aKey))
- console.log(key, 'is', b && toJS(bKey))
+ const hasA = aKeys.has(key);
+ const hasB = bKeys.has(key);
+ if (!hasA && !hasB) return;
+ if (hasA && hasB && a[key] === b[key]) return;
+ const desc = !hasA ? 'added' : !hasB ? 'removed' : 'changed';
+ console.log(name, key, desc);
+ const aKey = a[key];
+ const bKey = b[key];
+ if (typeof aKey !== 'function' && typeof bKey !== 'function') {
+ //functions are too verbose
+ console.log(key, 'was', a && toJS(aKey));
+ console.log(key, 'is', b && toJS(bKey));
}
- })
+ });
}
-const toJS = o => (Iterable.isIterable(o) ? o.toJS() : o)
+const toJS = o => (Iterable.isIterable(o) ? o.toJS() : o);
diff --git a/src/app/utils/userIllegalContent.js b/src/app/utils/userIllegalContent.js
index 0cceeda9d3158a2e37aaac707a4bf9f88d8a1ee1..d4c18515bfb1d51757228edcc00c8a32cb6cd8d9 100644
--- a/src/app/utils/userIllegalContent.js
+++ b/src/app/utils/userIllegalContent.js
@@ -1,5 +1,7 @@
const list = `
aplomb
-`.trim().split('\n');
+`
+ .trim()
+ .split('\n');
export default list;
diff --git a/src/db/config/config.json b/src/db/config/config.json
index 601e2878860e41f36cb065fe89870b162f611fff..b54ddcf8d10c007712c149bca6ea809dd93410e2 100644
--- a/src/db/config/config.json
+++ b/src/db/config/config.json
@@ -1,9 +1,9 @@
{
- "development": {
- "username": "root",
- "password": "password",
- "database": "steemit_dev",
- "host": "127.0.0.1",
- "dialect": "mysql"
- }
+ "development": {
+ "username": "root",
+ "password": "password",
+ "database": "steemit_dev",
+ "host": "127.0.0.1",
+ "dialect": "mysql"
+ }
}
diff --git a/src/db/migrations/20160419161331-create-user.js b/src/db/migrations/20160419161331-create-user.js
index a683d252648d581ca0b4073af80aee0446aa2baa..bb9c17f1cf8604ac6e4e3ac411e76bdb1fd8f598 100644
--- a/src/db/migrations/20160419161331-create-user.js
+++ b/src/db/migrations/20160419161331-create-user.js
@@ -1,71 +1,75 @@
module.exports = {
- up: function (queryInterface, Sequelize) {
- return queryInterface.createTable('users', {
- id: {
- allowNull: false,
- autoIncrement: true,
- primaryKey: true,
- type: Sequelize.INTEGER
- },
- name: {
- type: Sequelize.STRING
- },
- email: {
- type: Sequelize.STRING,
- },
- uid: {
- type: Sequelize.STRING(64)
- },
- first_name: {
- type: Sequelize.STRING
- },
- last_name: {
- type: Sequelize.STRING
- },
- birthday: {
- type: Sequelize.DATE
- },
- gender: {
- type: Sequelize.STRING(8)
- },
- picture_small: {
- type: Sequelize.STRING
- },
- picture_large: {
- type: Sequelize.STRING
- },
- location_id: {
- type: Sequelize.BIGINT.UNSIGNED
- },
- location_name: {
- type: Sequelize.STRING
- },
- locale: {
- type: Sequelize.STRING(12)
- },
- timezone: {
- type: Sequelize.INTEGER
- },
- verified: {
- type: Sequelize.BOOLEAN
- },
- bot: {
- type: Sequelize.BOOLEAN
- },
- created_at: {
- allowNull: false,
- type: Sequelize.DATE
- },
- updated_at: {
- allowNull: false,
- type: Sequelize.DATE
- }
- }).then(function () {
- queryInterface.addIndex('users', ['email']);
- queryInterface.addIndex('users', ['uid'], {indicesType: 'UNIQUE'});
- });
+ up: function(queryInterface, Sequelize) {
+ return queryInterface
+ .createTable('users', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: Sequelize.INTEGER,
+ },
+ name: {
+ type: Sequelize.STRING,
+ },
+ email: {
+ type: Sequelize.STRING,
+ },
+ uid: {
+ type: Sequelize.STRING(64),
+ },
+ first_name: {
+ type: Sequelize.STRING,
+ },
+ last_name: {
+ type: Sequelize.STRING,
+ },
+ birthday: {
+ type: Sequelize.DATE,
+ },
+ gender: {
+ type: Sequelize.STRING(8),
+ },
+ picture_small: {
+ type: Sequelize.STRING,
+ },
+ picture_large: {
+ type: Sequelize.STRING,
+ },
+ location_id: {
+ type: Sequelize.BIGINT.UNSIGNED,
+ },
+ location_name: {
+ type: Sequelize.STRING,
+ },
+ locale: {
+ type: Sequelize.STRING(12),
+ },
+ timezone: {
+ type: Sequelize.INTEGER,
+ },
+ verified: {
+ type: Sequelize.BOOLEAN,
+ },
+ bot: {
+ type: Sequelize.BOOLEAN,
+ },
+ created_at: {
+ allowNull: false,
+ type: Sequelize.DATE,
+ },
+ updated_at: {
+ allowNull: false,
+ type: Sequelize.DATE,
+ },
+ })
+ .then(function() {
+ queryInterface.addIndex('users', ['email']);
+ queryInterface.addIndex('users', ['uid'], {
+ indicesType: 'UNIQUE',
+ });
+ });
},
- down: function (queryInterface, Sequelize) {
+ down: function(queryInterface, Sequelize) {
return queryInterface.dropTable('users');
- }
+ },
};
diff --git a/src/db/migrations/20160420133848-create-identity.js b/src/db/migrations/20160420133848-create-identity.js
index e3e622942503b9659dd47a35287d863484230fd9..bcd1d962c93ecf369e28e30cbf02323aa0370b75 100644
--- a/src/db/migrations/20160420133848-create-identity.js
+++ b/src/db/migrations/20160420133848-create-identity.js
@@ -1,60 +1,62 @@
module.exports = {
- up: function (queryInterface, Sequelize) {
- return queryInterface.createTable('identities', {
- id: {
- allowNull: false,
- autoIncrement: true,
- primaryKey: true,
- type: Sequelize.INTEGER
- },
- user_id: {
- type: Sequelize.INTEGER,
- references: {
- model: 'users',
- key: 'id'
- },
- onUpdate: 'cascade',
- onDelete: 'cascade'
- },
- provider: {
- type: Sequelize.STRING
- },
- provider_user_id: {
- type: Sequelize.STRING
- },
- name: {
- type: Sequelize.STRING
- },
- email: {
- type: Sequelize.STRING
- },
- phone: {
- type: Sequelize.STRING(32)
- },
- confirmation_code: {
- type: Sequelize.STRING
- },
- verified: {
- type: Sequelize.BOOLEAN
- },
- score: {
- type: Sequelize.INTEGER
- },
- created_at: {
- allowNull: false,
- type: Sequelize.DATE
- },
- updated_at: {
- allowNull: false,
- type: Sequelize.DATE
- }
- }).then(function () {
- queryInterface.addIndex('identities', ['email']);
- queryInterface.addIndex('identities', ['phone']);
- queryInterface.addIndex('identities', ['confirmation_code']);
- });
+ up: function(queryInterface, Sequelize) {
+ return queryInterface
+ .createTable('identities', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: Sequelize.INTEGER,
+ },
+ user_id: {
+ type: Sequelize.INTEGER,
+ references: {
+ model: 'users',
+ key: 'id',
+ },
+ onUpdate: 'cascade',
+ onDelete: 'cascade',
+ },
+ provider: {
+ type: Sequelize.STRING,
+ },
+ provider_user_id: {
+ type: Sequelize.STRING,
+ },
+ name: {
+ type: Sequelize.STRING,
+ },
+ email: {
+ type: Sequelize.STRING,
+ },
+ phone: {
+ type: Sequelize.STRING(32),
+ },
+ confirmation_code: {
+ type: Sequelize.STRING,
+ },
+ verified: {
+ type: Sequelize.BOOLEAN,
+ },
+ score: {
+ type: Sequelize.INTEGER,
+ },
+ created_at: {
+ allowNull: false,
+ type: Sequelize.DATE,
+ },
+ updated_at: {
+ allowNull: false,
+ type: Sequelize.DATE,
+ },
+ })
+ .then(function() {
+ queryInterface.addIndex('identities', ['email']);
+ queryInterface.addIndex('identities', ['phone']);
+ queryInterface.addIndex('identities', ['confirmation_code']);
+ });
},
- down: function (queryInterface, Sequelize) {
+ down: function(queryInterface, Sequelize) {
return queryInterface.dropTable('identities');
- }
+ },
};
diff --git a/src/db/migrations/20160420151336-create-account.js b/src/db/migrations/20160420151336-create-account.js
index bb3d3d475f420badc63d1ae71081ac5cb801edd3..b63bd625a8011510d39be6a075bbdae7e3fa60cd 100644
--- a/src/db/migrations/20160420151336-create-account.js
+++ b/src/db/migrations/20160420151336-create-account.js
@@ -1,67 +1,71 @@
module.exports = {
- up: function (queryInterface, Sequelize) {
- return queryInterface.createTable('accounts', {
- id: {
- allowNull: false,
- autoIncrement: true,
- primaryKey: true,
- type: Sequelize.INTEGER
- },
- user_id: {
- type: Sequelize.INTEGER,
- references: {
- model: 'users',
- key: 'id'
+ up: function(queryInterface, Sequelize) {
+ return queryInterface
+ .createTable('accounts', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: Sequelize.INTEGER,
},
- onUpdate: 'cascade',
- onDelete: 'cascade'
- },
- name: {
- type: Sequelize.STRING
- },
- owner_key: {
- type: Sequelize.STRING
- },
- active_key: {
- type: Sequelize.STRING
- },
- posting_key: {
- type: Sequelize.STRING
- },
- memo_key: {
- type: Sequelize.STRING
- },
- referrer: {
- type: Sequelize.STRING
- },
- refcode: {
- type: Sequelize.STRING
- },
- remote_ip: {
- type: Sequelize.STRING
- },
- ignored: {
- type: Sequelize.BOOLEAN,
- defaultValue: false,
- allowNull: false
- },
- created_at: {
- allowNull: false,
- type: Sequelize.DATE
- },
- updated_at: {
- allowNull: false,
- type: Sequelize.DATE
- }
- }).then(function () {
- queryInterface.addIndex('accounts', ['name'], {indicesType: 'UNIQUE'});
- queryInterface.addIndex('accounts', ['owner_key']);
- queryInterface.addIndex('accounts', ['active_key']);
- queryInterface.addIndex('accounts', ['posting_key']);
- queryInterface.addIndex('accounts', ['memo_key']);
- });
+ user_id: {
+ type: Sequelize.INTEGER,
+ references: {
+ model: 'users',
+ key: 'id',
+ },
+ onUpdate: 'cascade',
+ onDelete: 'cascade',
+ },
+ name: {
+ type: Sequelize.STRING,
+ },
+ owner_key: {
+ type: Sequelize.STRING,
+ },
+ active_key: {
+ type: Sequelize.STRING,
+ },
+ posting_key: {
+ type: Sequelize.STRING,
+ },
+ memo_key: {
+ type: Sequelize.STRING,
+ },
+ referrer: {
+ type: Sequelize.STRING,
+ },
+ refcode: {
+ type: Sequelize.STRING,
+ },
+ remote_ip: {
+ type: Sequelize.STRING,
+ },
+ ignored: {
+ type: Sequelize.BOOLEAN,
+ defaultValue: false,
+ allowNull: false,
+ },
+ created_at: {
+ allowNull: false,
+ type: Sequelize.DATE,
+ },
+ updated_at: {
+ allowNull: false,
+ type: Sequelize.DATE,
+ },
+ })
+ .then(function() {
+ queryInterface.addIndex('accounts', ['name'], {
+ indicesType: 'UNIQUE',
+ });
+ queryInterface.addIndex('accounts', ['owner_key']);
+ queryInterface.addIndex('accounts', ['active_key']);
+ queryInterface.addIndex('accounts', ['posting_key']);
+ queryInterface.addIndex('accounts', ['memo_key']);
+ });
},
- down: function (queryInterface, Sequelize) {
+ down: function(queryInterface, Sequelize) {
return queryInterface.dropTable('accounts');
- }
+ },
};
diff --git a/src/db/migrations/20160506223257-create-web-events.js b/src/db/migrations/20160506223257-create-web-events.js
index 037618cac38244ffec304fa77dae749cc2836ad7..f5cb09ec75b7d1864020bf86b19af5d442ccb9c5 100644
--- a/src/db/migrations/20160506223257-create-web-events.js
+++ b/src/db/migrations/20160506223257-create-web-events.js
@@ -1,47 +1,49 @@
'use strict';
module.exports = {
- up: function (queryInterface, Sequelize) {
- return queryInterface.createTable('web_events', {
- id: {
- allowNull: false,
- autoIncrement: true,
- primaryKey: true,
- type: Sequelize.INTEGER
- },
- event_type: {type: Sequelize.STRING(64)},
- value: {type: Sequelize.STRING(1024)},
- user_id: {type: Sequelize.INTEGER},
- uid: {type: Sequelize.STRING(32)},
- account_name: {type: Sequelize.STRING(64)},
- first_visit: {type: Sequelize.BOOLEAN},
- new_session: {type: Sequelize.BOOLEAN},
- ip: {type: Sequelize.STRING(48)},
- refurl: {type: Sequelize.STRING},
- user_agent: {type: Sequelize.STRING},
- status: {type: Sequelize.INTEGER},
- city: {type: Sequelize.STRING(64)},
- state: {type: Sequelize.STRING(64)},
- country: {type: Sequelize.STRING(64)},
- channel: {type: Sequelize.STRING(64)},
- referrer: {type: Sequelize.STRING(64)},
- refcode: {type: Sequelize.STRING(64)},
- campaign: {type: Sequelize.STRING(64)},
- adgroupid: {type: Sequelize.INTEGER},
- adid: {type: Sequelize.INTEGER},
- keywordid: {type: Sequelize.INTEGER},
- contentid: {type: Sequelize.INTEGER},
- created_at: {
- allowNull: false,
- type: Sequelize.DATE
- }
- }).then(function () {
- queryInterface.addIndex('web_events', ['event_type']);
- queryInterface.addIndex('web_events', ['user_id']);
- queryInterface.addIndex('web_events', ['uid']);
- queryInterface.addIndex('web_events', ['account_name']);
- });
+ up: function(queryInterface, Sequelize) {
+ return queryInterface
+ .createTable('web_events', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: Sequelize.INTEGER,
+ },
+ event_type: { type: Sequelize.STRING(64) },
+ value: { type: Sequelize.STRING(1024) },
+ user_id: { type: Sequelize.INTEGER },
+ uid: { type: Sequelize.STRING(32) },
+ account_name: { type: Sequelize.STRING(64) },
+ first_visit: { type: Sequelize.BOOLEAN },
+ new_session: { type: Sequelize.BOOLEAN },
+ ip: { type: Sequelize.STRING(48) },
+ refurl: { type: Sequelize.STRING },
+ user_agent: { type: Sequelize.STRING },
+ status: { type: Sequelize.INTEGER },
+ city: { type: Sequelize.STRING(64) },
+ state: { type: Sequelize.STRING(64) },
+ country: { type: Sequelize.STRING(64) },
+ channel: { type: Sequelize.STRING(64) },
+ referrer: { type: Sequelize.STRING(64) },
+ refcode: { type: Sequelize.STRING(64) },
+ campaign: { type: Sequelize.STRING(64) },
+ adgroupid: { type: Sequelize.INTEGER },
+ adid: { type: Sequelize.INTEGER },
+ keywordid: { type: Sequelize.INTEGER },
+ contentid: { type: Sequelize.INTEGER },
+ created_at: {
+ allowNull: false,
+ type: Sequelize.DATE,
+ },
+ })
+ .then(function() {
+ queryInterface.addIndex('web_events', ['event_type']);
+ queryInterface.addIndex('web_events', ['user_id']);
+ queryInterface.addIndex('web_events', ['uid']);
+ queryInterface.addIndex('web_events', ['account_name']);
+ });
},
- down: function (queryInterface, Sequelize) {
+ down: function(queryInterface, Sequelize) {
return queryInterface.dropTable('web_events');
- }
+ },
};
diff --git a/src/db/migrations/20160519211043-users-waiting-list.js b/src/db/migrations/20160519211043-users-waiting-list.js
index 05ef0617780014211c61878e698c086c68d32b83..a1af0324df0a8d710bd35edf7c52badc972180b0 100644
--- a/src/db/migrations/20160519211043-users-waiting-list.js
+++ b/src/db/migrations/20160519211043-users-waiting-list.js
@@ -1,13 +1,13 @@
'use strict';
module.exports = {
- up: function (queryInterface, Sequelize) {
+ up: function(queryInterface, Sequelize) {
queryInterface.addColumn('users', 'waiting_list', Sequelize.BOOLEAN);
queryInterface.addColumn('users', 'remote_ip', Sequelize.STRING);
},
- down: function (queryInterface, Sequelize) {
+ down: function(queryInterface, Sequelize) {
queryInterface.removeColumn('users', 'waiting_list');
queryInterface.removeColumn('users', 'remote_ip');
- }
+ },
};
diff --git a/src/db/migrations/20160715233035-account-recovery-request.js b/src/db/migrations/20160715233035-account-recovery-request.js
index ae2b8f2c503af9f8cb8bf6e57d45f3328842fbf2..b25304b276838b94119d7dbe9dd9f1a5e742f68d 100644
--- a/src/db/migrations/20160715233035-account-recovery-request.js
+++ b/src/db/migrations/20160715233035-account-recovery-request.js
@@ -1,54 +1,54 @@
'use strict';
module.exports = {
- up: function (queryInterface, Sequelize) {
- return queryInterface.createTable('arecs', {
- id: {
- allowNull: false,
- autoIncrement: true,
- primaryKey: true,
- type: Sequelize.INTEGER
- },
- user_id: {type: Sequelize.INTEGER},
- uid: {type: Sequelize.STRING(32)},
- contact_email: {type: Sequelize.STRING(256)},
- account_name: {type: Sequelize.STRING(64)},
- provider: {type: Sequelize.STRING(64)},
- email_confirmation_code: {type: Sequelize.STRING(64)},
- validation_code: {type: Sequelize.STRING(64)},
- request_submitted_at: {type: Sequelize.DATE},
- owner_key: {
- type: Sequelize.STRING
- },
- old_owner_key: {
- type: Sequelize.STRING
- },
- new_owner_key: {
- type: Sequelize.STRING
- },
- remote_ip: {
- type: Sequelize.STRING
- },
- status: {
- type: Sequelize.STRING
- },
- created_at: {
- allowNull: false,
- type: Sequelize.DATE
- },
- updated_at: {
- allowNull: false,
- type: Sequelize.DATE
- }
- }).then(function () {
- queryInterface.addIndex('arecs', ['user_id']);
- queryInterface.addIndex('arecs', ['uid']);
- queryInterface.addIndex('arecs', ['account_name']);
- queryInterface.addIndex('arecs', ['contact_email']);
- });
- },
+ up: function(queryInterface, Sequelize) {
+ return queryInterface
+ .createTable('arecs', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: Sequelize.INTEGER,
+ },
+ user_id: { type: Sequelize.INTEGER },
+ uid: { type: Sequelize.STRING(32) },
+ contact_email: { type: Sequelize.STRING(256) },
+ account_name: { type: Sequelize.STRING(64) },
+ provider: { type: Sequelize.STRING(64) },
+ email_confirmation_code: { type: Sequelize.STRING(64) },
+ validation_code: { type: Sequelize.STRING(64) },
+ request_submitted_at: { type: Sequelize.DATE },
+ owner_key: {
+ type: Sequelize.STRING,
+ },
+ old_owner_key: {
+ type: Sequelize.STRING,
+ },
+ new_owner_key: {
+ type: Sequelize.STRING,
+ },
+ remote_ip: {
+ type: Sequelize.STRING,
+ },
+ status: {
+ type: Sequelize.STRING,
+ },
+ created_at: {
+ allowNull: false,
+ type: Sequelize.DATE,
+ },
+ updated_at: {
+ allowNull: false,
+ type: Sequelize.DATE,
+ },
+ })
+ .then(function() {
+ queryInterface.addIndex('arecs', ['user_id']);
+ queryInterface.addIndex('arecs', ['uid']);
+ queryInterface.addIndex('arecs', ['account_name']);
+ queryInterface.addIndex('arecs', ['contact_email']);
+ });
+ },
- down: function (queryInterface, Sequelize) {
-
- }
+ down: function(queryInterface, Sequelize) {},
};
diff --git a/src/db/migrations/20160930210310-create-list.js b/src/db/migrations/20160930210310-create-list.js
index bfbf4bb47d9a705ca2fc34b9d156ccccc562b893..d9d1d3d66273a3cc00455bf69291d2d0fec367bb 100644
--- a/src/db/migrations/20160930210310-create-list.js
+++ b/src/db/migrations/20160930210310-create-list.js
@@ -1,32 +1,30 @@
'use strict';
module.exports = {
- up: function (queryInterface, Sequelize) {
- return queryInterface.createTable('lists', {
- id: {
- allowNull: false,
- autoIncrement: true,
- primaryKey: true,
- type: Sequelize.INTEGER
- },
- kk: {type: Sequelize.STRING(64)},
- value: {type: Sequelize.STRING(256)},
- created_at: {
- allowNull: false,
- type: Sequelize.DATE
- }
- }).then(function () {
- queryInterface.addIndex('lists', ['kk']);
- queryInterface.addIndex(
- 'lists',
- ['kk', 'value'],
- {
- indexName: 'KeyValue',
- indicesType: 'UNIQUE'
- }
- )
- });
- },
- down: function (queryInterface, Sequelize) {
- return queryInterface.dropTable('lists');
- }
+ up: function(queryInterface, Sequelize) {
+ return queryInterface
+ .createTable('lists', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: Sequelize.INTEGER,
+ },
+ kk: { type: Sequelize.STRING(64) },
+ value: { type: Sequelize.STRING(256) },
+ created_at: {
+ allowNull: false,
+ type: Sequelize.DATE,
+ },
+ })
+ .then(function() {
+ queryInterface.addIndex('lists', ['kk']);
+ queryInterface.addIndex('lists', ['kk', 'value'], {
+ indexName: 'KeyValue',
+ indicesType: 'UNIQUE',
+ });
+ });
+ },
+ down: function(queryInterface, Sequelize) {
+ return queryInterface.dropTable('lists');
+ },
};
diff --git a/src/db/migrations/20161129170500-create-page.js b/src/db/migrations/20161129170500-create-page.js
index d5fcde139c1d1fc8a3030c9babb7efd78f3b947c..2aa386b83a3d5582711a9179b18abf301e487a39 100644
--- a/src/db/migrations/20161129170500-create-page.js
+++ b/src/db/migrations/20161129170500-create-page.js
@@ -1,24 +1,28 @@
'use strict';
module.exports = {
- up: function (queryInterface, Sequelize) {
- return queryInterface.createTable('pages', {
- id: {
- allowNull: false,
- autoIncrement: true,
- primaryKey: true,
- type: Sequelize.INTEGER
- },
- permlink: {type: Sequelize.STRING(256)},
- views: {type: Sequelize.INTEGER},
- created_at: {
- allowNull: false,
- type: Sequelize.DATE
- }
- }).then(function () {
- queryInterface.addIndex('pages', ['permlink'], {indicesType: 'UNIQUE'});
- });
- },
- down: function (queryInterface, Sequelize) {
- return queryInterface.dropTable('pages');
- }
+ up: function(queryInterface, Sequelize) {
+ return queryInterface
+ .createTable('pages', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: Sequelize.INTEGER,
+ },
+ permlink: { type: Sequelize.STRING(256) },
+ views: { type: Sequelize.INTEGER },
+ created_at: {
+ allowNull: false,
+ type: Sequelize.DATE,
+ },
+ })
+ .then(function() {
+ queryInterface.addIndex('pages', ['permlink'], {
+ indicesType: 'UNIQUE',
+ });
+ });
+ },
+ down: function(queryInterface, Sequelize) {
+ return queryInterface.dropTable('pages');
+ },
};
diff --git a/src/db/migrations/20170426204791-wait-columns.js b/src/db/migrations/20170426204791-wait-columns.js
index 841011a262cb6df7eb312641dbb51b345f3cff23..4b72de6464f7525dd145081683bbec821255e977 100644
--- a/src/db/migrations/20170426204791-wait-columns.js
+++ b/src/db/migrations/20170426204791-wait-columns.js
@@ -1,26 +1,19 @@
'use strict';
module.exports = {
- up: function (queryInterface, Sequelize) {
- queryInterface.addColumn('users', 'account_status',
- {
- type: Sequelize.STRING,
- defaultValue: "waiting",
- allowNull: false
- }
- );
- queryInterface.addColumn('users', 'sign_up_meta',
- {
- type: Sequelize.TEXT
- }
- );
- queryInterface.addColumn('accounts', 'created',
- {
- type: Sequelize.BOOLEAN
- }
- );
+ up: function(queryInterface, Sequelize) {
+ queryInterface.addColumn('users', 'account_status', {
+ type: Sequelize.STRING,
+ defaultValue: 'waiting',
+ allowNull: false,
+ });
+ queryInterface.addColumn('users', 'sign_up_meta', {
+ type: Sequelize.TEXT,
+ });
+ queryInterface.addColumn('accounts', 'created', {
+ type: Sequelize.BOOLEAN,
+ });
},
- down: function (queryInterface, Sequelize) {
- }
+ down: function(queryInterface, Sequelize) {},
};
diff --git a/src/db/migrations/20170511160822-not_unique_account_names.js b/src/db/migrations/20170511160822-not_unique_account_names.js
index c8537a4c91b8246819d5c5f589f3d089974a9373..e34ac022088dc09fa98ee0aa5eb08ca646425a1c 100644
--- a/src/db/migrations/20170511160822-not_unique_account_names.js
+++ b/src/db/migrations/20170511160822-not_unique_account_names.js
@@ -1,11 +1,10 @@
'use strict';
module.exports = {
- up: function (queryInterface, Sequelize) {
- queryInterface.removeIndex('accounts', ['name']);
- queryInterface.addIndex('accounts', ['name']);
- },
+ up: function(queryInterface, Sequelize) {
+ queryInterface.removeIndex('accounts', ['name']);
+ queryInterface.addIndex('accounts', ['name']);
+ },
- down: function (queryInterface, Sequelize) {
- }
+ down: function(queryInterface, Sequelize) {},
};
diff --git a/src/db/migrations/20170518201152-create-attributes.js b/src/db/migrations/20170518201152-create-attributes.js
index 2ee2c7199cde060f287290bb2998e2d34c0710b2..84c0e191a0eab1ab66dfa7cb1fcd730e2c4798fc 100644
--- a/src/db/migrations/20170518201152-create-attributes.js
+++ b/src/db/migrations/20170518201152-create-attributes.js
@@ -1,44 +1,46 @@
'use strict';
module.exports = {
- up: function (queryInterface, Sequelize) {
- return queryInterface.createTable('user_attributes', {
- id: {
- allowNull: false,
- autoIncrement: true,
- primaryKey: true,
- type: Sequelize.INTEGER
- },
- user_id: {
- type: Sequelize.INTEGER
- },
- type_of: {
- type: Sequelize.STRING(64)
- },
- value: {
- type: Sequelize.STRING(256)
- },
- created_at: {
- allowNull: false,
- type: Sequelize.DATE
- },
- updated_at: {
- allowNull: false,
- type: Sequelize.DATE
- }
- }).then(function () {
- queryInterface.addIndex('user_attributes', ['user_id']);
- queryInterface.addIndex('user_attributes', ['type_of']);
- });
+ up: function(queryInterface, Sequelize) {
+ return queryInterface
+ .createTable('user_attributes', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: Sequelize.INTEGER,
+ },
+ user_id: {
+ type: Sequelize.INTEGER,
+ },
+ type_of: {
+ type: Sequelize.STRING(64),
+ },
+ value: {
+ type: Sequelize.STRING(256),
+ },
+ created_at: {
+ allowNull: false,
+ type: Sequelize.DATE,
+ },
+ updated_at: {
+ allowNull: false,
+ type: Sequelize.DATE,
+ },
+ })
+ .then(function() {
+ queryInterface.addIndex('user_attributes', ['user_id']);
+ queryInterface.addIndex('user_attributes', ['type_of']);
+ });
},
- down: function (queryInterface, Sequelize) {
- /*
+ down: function(queryInterface, Sequelize) {
+ /*
Add reverting commands here.
Return a promise to correctly handle asynchronicity.
Example:
return queryInterface.dropTable('users');
*/
- }
+ },
};
diff --git a/src/db/migrations/20180111190510-user-account-creationhash.js b/src/db/migrations/20180111190510-user-account-creationhash.js
new file mode 100644
index 0000000000000000000000000000000000000000..f6a494df1971d8279cee7d42f926b5c3c3bed054
--- /dev/null
+++ b/src/db/migrations/20180111190510-user-account-creationhash.js
@@ -0,0 +1,11 @@
+'use strict';
+
+module.exports = {
+ up: function(queryInterface, Sequelize) {
+ queryInterface.addColumn('users', 'creation_hash', Sequelize.STRING);
+ },
+
+ down: function(queryInterface, Sequelize) {
+ queryInterface.removeColumn('users', 'creation_hash');
+ },
+};
diff --git a/src/db/models/account.js b/src/db/models/account.js
index 5cbeb801a804ce6c08d3bf6320b4c024592ef7e8..b3c23adbd9a88868e60a7132d782cef20eea9b41 100644
--- a/src/db/models/account.js
+++ b/src/db/models/account.js
@@ -1,39 +1,43 @@
-module.exports = function (sequelize, DataTypes) {
- var Account = sequelize.define('Account', {
- UserId: {
- type: DataTypes.INTEGER,
- references: {
- model: 'users',
- key: 'id'
+module.exports = function(sequelize, DataTypes) {
+ var Account = sequelize.define(
+ 'Account',
+ {
+ UserId: {
+ type: DataTypes.INTEGER,
+ references: {
+ model: 'users',
+ key: 'id',
+ },
+ field: 'user_id',
},
- field: 'user_id'
+ name: { type: DataTypes.STRING, unique: true },
+ owner_key: { type: DataTypes.STRING, unique: true },
+ active_key: { type: DataTypes.STRING, unique: true },
+ posting_key: { type: DataTypes.STRING, unique: true },
+ memo_key: { type: DataTypes.STRING, unique: true },
+ referrer: DataTypes.STRING,
+ refcode: DataTypes.STRING,
+ remote_ip: DataTypes.STRING,
+ ignored: { type: DataTypes.BOOLEAN },
+ created: { type: DataTypes.BOOLEAN },
},
- name: {type: DataTypes.STRING, unique: true},
- owner_key: {type: DataTypes.STRING, unique: true},
- active_key: {type: DataTypes.STRING, unique: true},
- posting_key: {type: DataTypes.STRING, unique: true},
- memo_key: {type: DataTypes.STRING, unique: true},
- referrer: DataTypes.STRING,
- refcode: DataTypes.STRING,
- remote_ip: DataTypes.STRING,
- ignored: {type: DataTypes.BOOLEAN},
- created: {type: DataTypes.BOOLEAN}
- }, {
- tableName: 'accounts',
- createdAt : 'created_at',
- updatedAt : 'updated_at',
- timestamps : true,
- underscored : true,
- classMethods: {
- associate: function (models) {
- Account.belongsTo(models.User, {
- onDelete: "CASCADE",
- foreignKey: {
- allowNull: false
- }
- });
- }
+ {
+ tableName: 'accounts',
+ createdAt: 'created_at',
+ updatedAt: 'updated_at',
+ timestamps: true,
+ underscored: true,
+ classMethods: {
+ associate: function(models) {
+ Account.belongsTo(models.User, {
+ onDelete: 'CASCADE',
+ foreignKey: {
+ allowNull: false,
+ },
+ });
+ },
+ },
}
- });
+ );
return Account;
};
diff --git a/src/db/models/account_recovery_request.js b/src/db/models/account_recovery_request.js
index 8c44d3c849a2a15d7a451e7603b7d08440d0e99f..427cfa1e38675350817aeda1ed43aad59db47e44 100644
--- a/src/db/models/account_recovery_request.js
+++ b/src/db/models/account_recovery_request.js
@@ -1,42 +1,49 @@
-module.exports = function (sequelize, DataTypes) {
- var AccountRecoveryRequest = sequelize.define('AccountRecoveryRequest', {
- UserId: {
- type: DataTypes.INTEGER,
- references: {
- model: 'users',
- key: 'id'
+module.exports = function(sequelize, DataTypes) {
+ var AccountRecoveryRequest = sequelize.define(
+ 'AccountRecoveryRequest',
+ {
+ UserId: {
+ type: DataTypes.INTEGER,
+ references: {
+ model: 'users',
+ key: 'id',
+ },
+ field: 'user_id',
},
- field: 'user_id'
+ uid: { type: DataTypes.STRING, unique: false },
+ contact_email: { type: DataTypes.STRING, unique: false },
+ account_name: { type: DataTypes.STRING, unique: false },
+ email_confirmation_code: {
+ type: DataTypes.STRING(64),
+ unique: false,
+ },
+ provider: { type: DataTypes.STRING(64), unique: false },
+ validation_code: { type: DataTypes.STRING(64), unique: false },
+ request_submitted_at: { type: DataTypes.DATE, unique: false },
+ owner_key: { type: DataTypes.STRING, unique: false },
+ old_owner_key: { type: DataTypes.STRING, unique: false },
+ new_owner_key: { type: DataTypes.STRING, unique: false },
+ memo_key: { type: DataTypes.STRING, unique: false },
+ remote_ip: { type: DataTypes.STRING, unique: false },
+ status: { type: DataTypes.STRING, unique: false },
},
- uid: {type: DataTypes.STRING, unique: false},
- contact_email: {type: DataTypes.STRING, unique: false},
- account_name: {type: DataTypes.STRING, unique: false},
- email_confirmation_code: {type: DataTypes.STRING(64), unique: false},
- provider: {type: DataTypes.STRING(64), unique: false},
- validation_code: {type: DataTypes.STRING(64), unique: false},
- request_submitted_at: {type: DataTypes.DATE, unique: false},
- owner_key: {type: DataTypes.STRING, unique: false},
- old_owner_key: {type: DataTypes.STRING, unique: false},
- new_owner_key: {type: DataTypes.STRING, unique: false},
- memo_key: {type: DataTypes.STRING, unique: false},
- remote_ip: {type: DataTypes.STRING, unique: false},
- status: {type: DataTypes.STRING, unique: false},
- }, {
- tableName: 'arecs',
- createdAt : 'created_at',
- updatedAt : 'updated_at',
- timestamps : true,
- underscored : true,
- classMethods: {
- associate: function (models) {
- AccountRecoveryRequest.belongsTo(models.User, {
- onDelete: "SET NULL",
- foreignKey: {
- allowNull: true
- }
- });
- }
+ {
+ tableName: 'arecs',
+ createdAt: 'created_at',
+ updatedAt: 'updated_at',
+ timestamps: true,
+ underscored: true,
+ classMethods: {
+ associate: function(models) {
+ AccountRecoveryRequest.belongsTo(models.User, {
+ onDelete: 'SET NULL',
+ foreignKey: {
+ allowNull: true,
+ },
+ });
+ },
+ },
}
- });
+ );
return AccountRecoveryRequest;
};
diff --git a/src/db/models/identity.js b/src/db/models/identity.js
index a9323d23b03097dfb60eecef6a117043edc959c5..c658b6f19347fd9559a229a6911dfd09c7b66c58 100644
--- a/src/db/models/identity.js
+++ b/src/db/models/identity.js
@@ -1,37 +1,41 @@
-module.exports = function (sequelize, DataTypes) {
- var Identity = sequelize.define('Identity', {
- UserId: {
- type: DataTypes.INTEGER,
- references: {
- model: 'users',
- key: 'id'
+module.exports = function(sequelize, DataTypes) {
+ var Identity = sequelize.define(
+ 'Identity',
+ {
+ UserId: {
+ type: DataTypes.INTEGER,
+ references: {
+ model: 'users',
+ key: 'id',
+ },
+ field: 'user_id',
},
- field: 'user_id'
+ provider: DataTypes.STRING,
+ provider_user_id: { type: DataTypes.STRING },
+ name: DataTypes.STRING,
+ email: { type: DataTypes.STRING },
+ phone: { type: DataTypes.STRING(32) },
+ confirmation_code: { type: DataTypes.STRING, unique: true },
+ verified: DataTypes.BOOLEAN,
+ score: DataTypes.INTEGER,
},
- provider: DataTypes.STRING,
- provider_user_id: {type: DataTypes.STRING},
- name: DataTypes.STRING,
- email: {type: DataTypes.STRING},
- phone: {type: DataTypes.STRING(32)},
- confirmation_code: {type: DataTypes.STRING, unique: true},
- verified: DataTypes.BOOLEAN,
- score: DataTypes.INTEGER
- }, {
- tableName: 'identities',
- createdAt : 'created_at',
- updatedAt : 'updated_at',
- timestamps : true,
- underscored : true,
- classMethods: {
- associate: function (models) {
- Identity.belongsTo(models.User, {
- onDelete: "CASCADE",
- foreignKey: {
- allowNull: false
- }
- });
- }
+ {
+ tableName: 'identities',
+ createdAt: 'created_at',
+ updatedAt: 'updated_at',
+ timestamps: true,
+ underscored: true,
+ classMethods: {
+ associate: function(models) {
+ Identity.belongsTo(models.User, {
+ onDelete: 'CASCADE',
+ foreignKey: {
+ allowNull: false,
+ },
+ });
+ },
+ },
}
- });
+ );
return Identity;
};
diff --git a/src/db/models/index.js b/src/db/models/index.js
index 8b8411932ae5bef3f3f04e40e580cb232ec6f886..925fd61ccb697aed0862584e923754b548fd6659 100644
--- a/src/db/models/index.js
+++ b/src/db/models/index.js
@@ -8,16 +8,21 @@ var db = {};
var sequelize = new Sequelize(config.get('database_url'));
-fs.readdirSync(__dirname)
- .filter(function (file) {
- return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
+fs
+ .readdirSync(__dirname)
+ .filter(function(file) {
+ return (
+ file.indexOf('.') !== 0 &&
+ file !== basename &&
+ file.slice(-3) === '.js'
+ );
})
- .forEach(function (file) {
+ .forEach(function(file) {
var model = sequelize['import'](path.join(__dirname, file));
db[model.name] = model;
});
-Object.keys(db).forEach(function (modelName) {
+Object.keys(db).forEach(function(modelName) {
if (db[modelName].associate) {
db[modelName].associate(db);
}
@@ -26,47 +31,49 @@ Object.keys(db).forEach(function (modelName) {
db.sequelize = sequelize;
db.Sequelize = Sequelize;
-if(env === 'development') {
+if (env === 'development') {
// in dev, sync all table schema automatically for convenience
sequelize.sync();
}
-
function esc(value, max_length = 256) {
if (!value) return '';
if (typeof value === 'number') return value;
if (typeof value === 'boolean') return value;
if (typeof value !== 'string') return '(object)';
- let res = value.substring(0, max_length - max_length * 0.2).replace(/[\0\x08\x09\x1a\n\r"'\\\%]/g, function (char) {
- switch (char) {
- case '\0':
- return '\\0';
- case '\x08':
- return '\\b';
- case '\x09':
- return '\\t';
- case '\x1a': return '\\z';
- case '\n':
- return '\\n';
- case '\r':
- return '\\r';
- // case '\'':
- // case "'":
- // case '"':
- // case '\\':
- // case '%':
- // return '\\' + char; // prepends a backslash to backslash, percent, and double/single quotes
- }
- return '-';
- });
+ let res = value
+ .substring(0, max_length - max_length * 0.2)
+ .replace(/[\0\x08\x09\x1a\n\r"'\\\%]/g, function(char) {
+ switch (char) {
+ case '\0':
+ return '\\0';
+ case '\x08':
+ return '\\b';
+ case '\x09':
+ return '\\t';
+ case '\x1a':
+ return '\\z';
+ case '\n':
+ return '\\n';
+ case '\r':
+ return '\\r';
+ // case '\'':
+ // case "'":
+ // case '"':
+ // case '\\':
+ // case '%':
+ // return '\\' + char; // prepends a backslash to backslash, percent, and double/single quotes
+ }
+ return '-';
+ });
return res.length < max_length ? res : '-';
}
db.esc = esc;
-db.escAttrs = function (attrs) {
+db.escAttrs = function(attrs) {
const res = {};
- Object.keys(attrs).forEach(key => res[key] = esc(attrs[key]));
+ Object.keys(attrs).forEach(key => (res[key] = esc(attrs[key])));
return res;
};
diff --git a/src/db/models/list.js b/src/db/models/list.js
index 1560a50739ac0ca7b3bbcdf98d7a973f11a9c265..4bafcc519c276e3304567ee0104c03704f6ba921 100644
--- a/src/db/models/list.js
+++ b/src/db/models/list.js
@@ -1,13 +1,17 @@
-module.exports = function (sequelize, DataTypes) {
- var List = sequelize.define('List', {
- kk: DataTypes.STRING(64),
- value: DataTypes.STRING(256),
- }, {
- tableName: 'lists',
- createdAt: 'created_at',
- updatedAt: false,
- timestamps : true,
- underscored : true
- });
+module.exports = function(sequelize, DataTypes) {
+ var List = sequelize.define(
+ 'List',
+ {
+ kk: DataTypes.STRING(64),
+ value: DataTypes.STRING(256),
+ },
+ {
+ tableName: 'lists',
+ createdAt: 'created_at',
+ updatedAt: false,
+ timestamps: true,
+ underscored: true,
+ }
+ );
return List;
};
diff --git a/src/db/models/page.js b/src/db/models/page.js
index dfe6fb35940373a074314785ddfe1b51150f8d34..65072d98b0cfbf7eb4151f874e6cf69e36182a78 100644
--- a/src/db/models/page.js
+++ b/src/db/models/page.js
@@ -1,13 +1,17 @@
-module.exports = function (sequelize, DataTypes) {
- var Page = sequelize.define('Page', {
- permlink: DataTypes.STRING(256),
- views: DataTypes.INTEGER,
- }, {
- tableName: 'pages',
- createdAt: 'created_at',
- updatedAt: false,
- timestamps : true,
- underscored : true
- });
+module.exports = function(sequelize, DataTypes) {
+ var Page = sequelize.define(
+ 'Page',
+ {
+ permlink: DataTypes.STRING(256),
+ views: DataTypes.INTEGER,
+ },
+ {
+ tableName: 'pages',
+ createdAt: 'created_at',
+ updatedAt: false,
+ timestamps: true,
+ underscored: true,
+ }
+ );
return Page;
};
diff --git a/src/db/models/user.js b/src/db/models/user.js
index ab47219f44d9b7db05c36b015958e0eefaf2c486..6366dd7c309ccdf02bc220e625ffa5f8b16a6636 100644
--- a/src/db/models/user.js
+++ b/src/db/models/user.js
@@ -1,38 +1,43 @@
-module.exports = function (sequelize, DataTypes) {
- var User = sequelize.define('User', {
- name: DataTypes.STRING,
- email: {type: DataTypes.STRING},
- uid: {type: DataTypes.STRING(64)},
- first_name: DataTypes.STRING,
- last_name: DataTypes.STRING,
- birthday: DataTypes.DATE,
- gender: DataTypes.STRING(8),
- picture_small: DataTypes.STRING,
- picture_large: DataTypes.STRING,
- location_id: DataTypes.BIGINT.UNSIGNED,
- location_name: DataTypes.STRING,
- locale: DataTypes.STRING(12),
- timezone: DataTypes.INTEGER,
- remote_ip: DataTypes.STRING,
- verified: DataTypes.BOOLEAN,
- waiting_list: DataTypes.BOOLEAN,
- bot: DataTypes.BOOLEAN,
- sign_up_meta: DataTypes.TEXT,
- account_status: DataTypes.STRING,
- settings: DataTypes.TEXT
- }, {
- tableName: 'users',
- createdAt : 'created_at',
- updatedAt : 'updated_at',
- timestamps : true,
- underscored : true,
- classMethods: {
- associate: function (models) {
- User.hasMany(models.Identity);
- User.hasMany(models.Account);
- User.hasMany(models.UserAttribute);
- }
+module.exports = function(sequelize, DataTypes) {
+ var User = sequelize.define(
+ 'User',
+ {
+ name: DataTypes.STRING,
+ email: { type: DataTypes.STRING },
+ uid: { type: DataTypes.STRING(64) },
+ first_name: DataTypes.STRING,
+ last_name: DataTypes.STRING,
+ birthday: DataTypes.DATE,
+ gender: DataTypes.STRING(8),
+ picture_small: DataTypes.STRING,
+ picture_large: DataTypes.STRING,
+ location_id: DataTypes.BIGINT.UNSIGNED,
+ location_name: DataTypes.STRING,
+ locale: DataTypes.STRING(12),
+ timezone: DataTypes.INTEGER,
+ remote_ip: DataTypes.STRING,
+ verified: DataTypes.BOOLEAN,
+ waiting_list: DataTypes.BOOLEAN,
+ bot: DataTypes.BOOLEAN,
+ sign_up_meta: DataTypes.TEXT,
+ account_status: DataTypes.STRING,
+ settings: DataTypes.TEXT,
+ creation_hash: DataTypes.STRING,
+ },
+ {
+ tableName: 'users',
+ createdAt: 'created_at',
+ updatedAt: 'updated_at',
+ timestamps: true,
+ underscored: true,
+ classMethods: {
+ associate: function(models) {
+ User.hasMany(models.Identity);
+ User.hasMany(models.Account);
+ User.hasMany(models.UserAttribute);
+ },
+ },
}
- });
+ );
return User;
};
diff --git a/src/db/models/user_attributes.js b/src/db/models/user_attributes.js
index 44e73514ae1a46654eff989ebad6b2822fb5cc0d..af3313b74e86ec9671c812b36e0a0e7d0c466b26 100644
--- a/src/db/models/user_attributes.js
+++ b/src/db/models/user_attributes.js
@@ -1,31 +1,35 @@
-module.exports = function (sequelize, DataTypes) {
- var UserAttribute = sequelize.define('UserAttribute', {
- UserId: {
- type: DataTypes.INTEGER,
- references: {
- model: 'users',
- key: 'id'
+module.exports = function(sequelize, DataTypes) {
+ var UserAttribute = sequelize.define(
+ 'UserAttribute',
+ {
+ UserId: {
+ type: DataTypes.INTEGER,
+ references: {
+ model: 'users',
+ key: 'id',
+ },
+ field: 'user_id',
},
- field: 'user_id'
+ type_of: DataTypes.STRING(64),
+ value: DataTypes.STRING(256),
},
- type_of: DataTypes.STRING(64),
- value: DataTypes.STRING(256)
- }, {
- tableName: 'user_attributes',
- createdAt : 'created_at',
- updatedAt : 'updated_at',
- timestamps : true,
- underscored : true,
- classMethods: {
- associate: function (models) {
- UserAttribute.belongsTo(models.User, {
- onDelete: "CASCADE",
- foreignKey: {
- allowNull: false
- }
- });
- }
+ {
+ tableName: 'user_attributes',
+ createdAt: 'created_at',
+ updatedAt: 'updated_at',
+ timestamps: true,
+ underscored: true,
+ classMethods: {
+ associate: function(models) {
+ UserAttribute.belongsTo(models.User, {
+ onDelete: 'CASCADE',
+ foreignKey: {
+ allowNull: false,
+ },
+ });
+ },
+ },
}
- });
+ );
return UserAttribute;
};
diff --git a/src/db/models/web_event.js b/src/db/models/web_event.js
index 84d5aebd4f43fda306a0318e7475914d1136e0b8..47f7f7bb61a99cf949f940e8f1ed6ed36629d4e4 100644
--- a/src/db/models/web_event.js
+++ b/src/db/models/web_event.js
@@ -1,34 +1,38 @@
-module.exports = function (sequelize, DataTypes) {
- var WebEvent = sequelize.define('WebEvent', {
- event_type: DataTypes.STRING(64),
- value: DataTypes.STRING(1024),
- user_id: DataTypes.INTEGER,
- uid: DataTypes.STRING(32),
- account_name: DataTypes.STRING(64),
- first_visit: DataTypes.BOOLEAN,
- new_session: DataTypes.BOOLEAN,
- ip: DataTypes.STRING(48),
- page: DataTypes.STRING,
- refurl: DataTypes.STRING,
- user_agent: DataTypes.STRING,
- status: DataTypes.INTEGER,
- city: DataTypes.STRING(64),
- state: DataTypes.STRING(64),
- country: DataTypes.STRING(64),
- channel: DataTypes.STRING(64),
- referrer: DataTypes.STRING(64),
- refcode: DataTypes.STRING(64),
- campaign: DataTypes.STRING(64),
- adgroupid: DataTypes.INTEGER,
- adid: DataTypes.INTEGER,
- keywordid: DataTypes.INTEGER,
- messageid: DataTypes.INTEGER,
- }, {
- tableName: 'web_events',
- createdAt: 'created_at',
- updatedAt: false,
- timestamps : true,
- underscored : true
- });
+module.exports = function(sequelize, DataTypes) {
+ var WebEvent = sequelize.define(
+ 'WebEvent',
+ {
+ event_type: DataTypes.STRING(64),
+ value: DataTypes.STRING(1024),
+ user_id: DataTypes.INTEGER,
+ uid: DataTypes.STRING(32),
+ account_name: DataTypes.STRING(64),
+ first_visit: DataTypes.BOOLEAN,
+ new_session: DataTypes.BOOLEAN,
+ ip: DataTypes.STRING(48),
+ page: DataTypes.STRING,
+ refurl: DataTypes.STRING,
+ user_agent: DataTypes.STRING,
+ status: DataTypes.INTEGER,
+ city: DataTypes.STRING(64),
+ state: DataTypes.STRING(64),
+ country: DataTypes.STRING(64),
+ channel: DataTypes.STRING(64),
+ referrer: DataTypes.STRING(64),
+ refcode: DataTypes.STRING(64),
+ campaign: DataTypes.STRING(64),
+ adgroupid: DataTypes.INTEGER,
+ adid: DataTypes.INTEGER,
+ keywordid: DataTypes.INTEGER,
+ messageid: DataTypes.INTEGER,
+ },
+ {
+ tableName: 'web_events',
+ createdAt: 'created_at',
+ updatedAt: false,
+ timestamps: true,
+ underscored: true,
+ }
+ );
return WebEvent;
};
diff --git a/src/db/models/web_events.js b/src/db/models/web_events.js
index 4bb251ba2363a6a70a4d9014286f5cf6ddf3bf28..c5fc334551cc2c139b3f7b751fc296ed45a71c5e 100644
--- a/src/db/models/web_events.js
+++ b/src/db/models/web_events.js
@@ -1,14 +1,18 @@
'use strict';
module.exports = function(sequelize, DataTypes) {
- var web_events = sequelize.define('web_events', {
- event_type: DataTypes.STRING,
- value: DataTypes.STRING
- }, {
- classMethods: {
- associate: function(models) {
- // associations can be defined here
- }
- }
- });
- return web_events;
-};
\ No newline at end of file
+ var web_events = sequelize.define(
+ 'web_events',
+ {
+ event_type: DataTypes.STRING,
+ value: DataTypes.STRING,
+ },
+ {
+ classMethods: {
+ associate: function(models) {
+ // associations can be defined here
+ },
+ },
+ }
+ );
+ return web_events;
+};
diff --git a/src/db/tarantool.js b/src/db/tarantool.js
index be397a90ac81ef5fab0c9807560d00bcc8648266..8db1551129ed9ce55a2a34d178e38f78ff71fcfa 100644
--- a/src/db/tarantool.js
+++ b/src/db/tarantool.js
@@ -1,5 +1,5 @@
-import config from 'config';
-import TarantoolDriver from 'tarantool-driver';
+const config = require('config');
+const TarantoolDriver = require('tarantool-driver');
let instance = null;
@@ -10,12 +10,16 @@ class Tarantool {
const username = config.get('tarantool.username');
const password = config.get('tarantool.password');
- const connection = this.connection = new TarantoolDriver({host, port});
+ const connection = (this.connection = new TarantoolDriver({
+ host,
+ port,
+ }));
this.ready_promise = new Promise((resolve, reject) => {
- connection.connect()
- .then(() => connection.auth(username, password))
- .then(() => resolve())
- .catch(() => resolve(false));
+ connection
+ .connect()
+ .then(() => connection.auth(username, password))
+ .then(() => resolve())
+ .catch(() => resolve(false));
});
}
@@ -24,20 +28,22 @@ class Tarantool {
.then(() => {
const call_time = Date.now();
return new Promise((resolve, reject) => {
- this.connection[call_name].apply(this.connection, args).then(res => {
- resolve(res)
- }).catch(error => reject(error));
+ this.connection[call_name]
+ .apply(this.connection, args)
+ .then(res => {
+ resolve(res);
+ })
+ .catch(error => reject(error));
});
})
.catch(error => {
- if (error.message.indexOf('connect') >= 0)
- instance = null;
+ if (error.message.indexOf('connect') >= 0) instance = null;
return Promise.reject(error);
});
}
select() {
- return this.makeCall('select', arguments);
+ return this.makeCall('select', arguments);
}
delete() {
return this.makeCall('delete', arguments);
@@ -62,9 +68,9 @@ class Tarantool {
}
}
-Tarantool.instance = function () {
+Tarantool.instance = function() {
if (!instance) instance = new Tarantool();
return instance;
};
-export default Tarantool;
+module.exports = Tarantool;
diff --git a/src/db/utils/find_user.js b/src/db/utils/find_user.js
index 54dbae36e430e1cee9a679e5457b34f8e0095cd6..9f288269efb374d202a9d7c5a2e506414f98b174 100644
--- a/src/db/utils/find_user.js
+++ b/src/db/utils/find_user.js
@@ -4,13 +4,13 @@ function findByProvider(provider_user_id, resolve) {
if (!provider_user_id) resolve(null);
const query = {
attributes: ['user_id'],
- where: {provider_user_id}
+ where: { provider_user_id },
};
models.Identity.findOne(query).then(identity => {
if (identity) {
models.User.findOne({
attributes: ['id'],
- where: {id: identity.user_id}
+ where: { id: identity.user_id },
}).then(u => resolve(u));
} else {
resolve(null);
@@ -18,18 +18,32 @@ function findByProvider(provider_user_id, resolve) {
});
}
-export default function findUser({user_id, email, uid, provider_user_id}) {
- console.log('-- findUser -->', user_id, email, uid, provider_user_id);
+export default function findUser({
+ user_id,
+ email,
+ uid,
+ provider_user_id,
+ name,
+}) {
+ console.log(
+ '-- findUser -->',
+ user_id,
+ email,
+ uid,
+ provider_user_id,
+ name
+ );
return new Promise(resolve => {
let query;
const where_or = [];
- if (user_id) where_or.push({id: user_id});
- if (email) where_or.push({email});
- if (uid) where_or.push({uid});
+ if (user_id) where_or.push({ id: user_id });
+ if (email) where_or.push({ email });
+ if (name) where_or.push({ name });
+ if (uid) where_or.push({ uid });
if (where_or.length > 0) {
query = {
attributes: ['id'],
- where: {$or: where_or}
+ where: { $or: where_or },
};
console.log('-- findUser query -->', query);
models.User.findOne(query).then(user => {
diff --git a/src/server/api/account_recovery.js b/src/server/api/account_recovery.js
index cc94eca5d0946eeaa9cd96f1ae8835a1ce222ec4..976e754459b6cc6630e4a657c34f4a27f3918549 100644
--- a/src/server/api/account_recovery.js
+++ b/src/server/api/account_recovery.js
@@ -2,183 +2,234 @@ import koa_router from 'koa-router';
import koa_body from 'koa-body';
import models from 'db/models';
import config from 'config';
-import {esc, escAttrs} from 'db/models';
-import {getRemoteIp, rateLimitReq, checkCSRF} from 'server/utils/misc';
-import {broadcast} from 'steem';
+import { esc, escAttrs } from 'db/models';
+import { getRemoteIp, rateLimitReq, checkCSRF } from 'server/utils/misc';
+import { broadcast } from '@steemit/steem-js';
export default function useAccountRecoveryApi(app) {
const router = koa_router();
app.use(router.routes());
const koaBody = koa_body();
- router.post('/initiate_account_recovery', koaBody, function *() {
+ router.post('/initiate_account_recovery', koaBody, function*() {
if (rateLimitReq(this, this.req)) return;
let params = this.request.body;
- params = typeof(params) === 'string' ? JSON.parse(params) : params;
+ params = typeof params === 'string' ? JSON.parse(params) : params;
if (!checkCSRF(this, params.csrf)) return;
- console.log('-- /initiate_account_recovery -->', this.session.uid, params);
+ console.log(
+ '-- /initiate_account_recovery -->',
+ this.session.uid,
+ params
+ );
this.session.recover_account = null;
if (!params.account_name) {
this.status = 500;
this.body = 'please provide account name';
return;
}
- const attrs = {uid: this.session.uid, status: 'open', ...params};
+ const attrs = { uid: this.session.uid, status: 'open', ...params };
attrs.remote_ip = getRemoteIp(this.req);
- const request = yield models.AccountRecoveryRequest.create(escAttrs(attrs));
- console.log('-- /initiate_account_recovery request id -->', this.session.uid, request.id);
+ const request = yield models.AccountRecoveryRequest.create(
+ escAttrs(attrs)
+ );
+ console.log(
+ '-- /initiate_account_recovery request id -->',
+ this.session.uid,
+ request.id
+ );
this.session.arec = request.id;
this.redirect('/connect/' + params.provider);
});
- router.get('/account_recovery_confirmation/:code', function *() {
+ router.get('/account_recovery_confirmation/:code', function*() {
if (rateLimitReq(this, this.req)) return;
const code = this.params.code;
if (!code) return this.throw('no confirmation code', 404);
const arec = yield models.AccountRecoveryRequest.findOne({
attributes: ['id', 'account_name', 'owner_key'],
- where: {validation_code: esc(code)},
- order: 'id desc'
+ where: { validation_code: esc(code) },
+ order: 'id desc',
});
if (arec) {
this.session.arec = arec.id;
- console.log('-- /account_recovery_confirmation -->', this.session.uid, arec.id, arec.account_name, arec.owner_key);
+ console.log(
+ '-- /account_recovery_confirmation -->',
+ this.session.uid,
+ arec.id,
+ arec.account_name,
+ arec.owner_key
+ );
this.redirect('/recover_account_step_2');
} else {
- console.log('-- /account_recovery_confirmation code not found -->', this.session.uid, code);
+ console.log(
+ '-- /account_recovery_confirmation code not found -->',
+ this.session.uid,
+ code
+ );
this.throw('wrong confirmation code', 404);
this.session.arec = null;
}
this.body = code;
});
- router.post('/api/v1/request_account_recovery', koaBody, function *() {
+ router.post('/api/v1/request_account_recovery', koaBody, function*() {
if (rateLimitReq(this, this.req)) return;
let params = this.request.body;
- params = typeof(params) === 'string' ? JSON.parse(params) : params;
+ params = typeof params === 'string' ? JSON.parse(params) : params;
if (!checkCSRF(this, params.csrf)) return;
try {
if (!this.session.arec) {
- console.log('-- /request_account_recovery --> this.session.arec is empty', this.session.uid);
- this.body = JSON.stringify({error: 'Unauthorized'});
+ console.log(
+ '-- /request_account_recovery --> this.session.arec is empty',
+ this.session.uid
+ );
+ this.body = JSON.stringify({ error: 'Unauthorized' });
this.status = 401;
return;
}
- const account_recovery_record = yield models.AccountRecoveryRequest.findOne({
- attributes: ['id', 'account_name', 'provider', 'status'],
- where: {id: this.session.arec}
- });
+ const account_recovery_record = yield models.AccountRecoveryRequest.findOne(
+ {
+ attributes: ['id', 'account_name', 'provider', 'status'],
+ where: { id: this.session.arec },
+ }
+ );
- if (!account_recovery_record || account_recovery_record.account_name !== params.name) {
- console.log('-- /request_account_recovery --> no arec found or wrong name', this.session.uid, params.name);
- this.body = JSON.stringify({error: 'Unauthorized'});
+ if (
+ !account_recovery_record ||
+ account_recovery_record.account_name !== params.name
+ ) {
+ console.log(
+ '-- /request_account_recovery --> no arec found or wrong name',
+ this.session.uid,
+ params.name
+ );
+ this.body = JSON.stringify({ error: 'Unauthorized' });
this.status = 401;
return;
}
if (account_recovery_record.status !== 'confirmed') {
- console.log('-- /request_account_recovery --> no arec found or wrong name', this.session.uid, params.name);
- this.body = JSON.stringify({error: 'Unauthorized'});
+ console.log(
+ '-- /request_account_recovery --> no arec found or wrong name',
+ this.session.uid,
+ params.name
+ );
+ this.body = JSON.stringify({ error: 'Unauthorized' });
this.status = 401;
return;
}
const recovery_account = config.get('registrar.account');
const signing_key = config.get('registrar.signing_key');
- const {new_owner_authority, old_owner_key, new_owner_key} = params;
+ const {
+ new_owner_authority,
+ old_owner_key,
+ new_owner_key,
+ } = params;
yield requestAccountRecovery({
signing_key,
account_to_recover: params.name,
recovery_account,
- new_owner_authority
+ new_owner_authority,
});
- console.log('-- /request_account_recovery completed -->', this.session.uid, this.session.user, params.name, old_owner_key, new_owner_key);
+ console.log(
+ '-- /request_account_recovery completed -->',
+ this.session.uid,
+ this.session.user,
+ params.name,
+ old_owner_key,
+ new_owner_key
+ );
const attrs = {
old_owner_key: esc(old_owner_key),
new_owner_key: esc(new_owner_key),
- request_submitted_at: new Date()
+ request_submitted_at: new Date(),
};
account_recovery_record.update(attrs);
- this.body = JSON.stringify({status: 'ok'});
+ this.body = JSON.stringify({ status: 'ok' });
} catch (error) {
- console.error('Error in /request_account_recovery api call', this.session.uid, this.session.user, error.toString(), error.stack);
- this.body = JSON.stringify({error: error.message});
+ console.error(
+ 'Error in /request_account_recovery api call',
+ this.session.uid,
+ this.session.user,
+ error.toString(),
+ error.stack
+ );
+ this.body = JSON.stringify({ error: error.message });
this.status = 500;
}
});
- router.post('/api/v1/account_identity_providers', koaBody, function *() {
- if (rateLimitReq(this, this.req)) return;
- try {
+ router.post(
+ '/api/v1/initiate_account_recovery_with_email',
+ koaBody,
+ function*() {
const params = this.request.body;
- const {csrf, name, owner_key} = typeof(params) === 'string' ? JSON.parse(params) : params;
+ const { csrf, contact_email, account_name, owner_key } =
+ typeof params === 'string' ? JSON.parse(params) : params;
if (!checkCSRF(this, csrf)) return;
- console.log('-- /account_identity_providers -->', this.session.uid, name, owner_key);
- const existing_account = yield models.Account.findOne({
- attributes: ['id', 'user_id', 'owner_key'],
- where: {name: esc(name)},
- order: 'id DESC'
+ console.log(
+ '-- /initiate_account_recovery_with_email -->',
+ this.session.uid,
+ contact_email,
+ account_name,
+ owner_key
+ );
+ if (!account_name || !contact_email || !owner_key) {
+ this.body = JSON.stringify({ status: 'error' });
+ return;
+ }
+ const arec = yield models.AccountRecoveryRequest.findOne({
+ attributes: ['id'],
+ where: escAttrs({ account_name, contact_email }),
});
- if (existing_account) {
- if (existing_account.owner_key === owner_key) {
- const identity = yield models.Identity.findOne({
- attributes: ['provider'],
- where: {user_id: existing_account.user_id},
- order: 'id DESC'
- });
- this.body = JSON.stringify({
- status: 'found',
- provider: identity ? (identity.provider === 'phone' ? 'email' : identity.provider) : null});
- } else {
- this.body = JSON.stringify({status: 'found', provider: 'email'});
- }
- } else {
- this.body = JSON.stringify({status: 'not found found', provider: 'email'});
+ if (arec) {
+ this.body = JSON.stringify({ status: 'duplicate' });
+ return;
}
- } catch (error) {
- console.error('Error in /account_identity_providers api call', this.session.uid, error);
- this.body = JSON.stringify({error: error.message});
- this.status = 500;
- }
- });
-
- router.post('/api/v1/initiate_account_recovery_with_email', koaBody, function *() {
- const params = this.request.body;
- const {csrf, contact_email, account_name, owner_key} = typeof(params) === 'string' ? JSON.parse(params) : params;
- if (!checkCSRF(this, csrf)) return;
- console.log('-- /initiate_account_recovery_with_email -->', this.session.uid, contact_email, account_name, owner_key);
- if (!account_name || !contact_email || !owner_key) {
- this.body = JSON.stringify({status: 'error'});
- return;
- }
- const arec = yield models.AccountRecoveryRequest.findOne({
- attributes: ['id'],
- where: escAttrs({account_name, contact_email})
- });
- if (arec) {
- this.body = JSON.stringify({status: 'duplicate'});
- return;
+ const attrs = {
+ uid: this.session.uid,
+ status: 'open',
+ contact_email,
+ account_name,
+ owner_key,
+ provider: 'email',
+ };
+ attrs.remote_ip = getRemoteIp(this.req);
+ const request = yield models.AccountRecoveryRequest.create(
+ escAttrs(attrs)
+ );
+ console.log(
+ '-- initiate_account_recovery_with_email -->',
+ this.session.uid,
+ request.id,
+ account_name,
+ owner_key
+ );
+ this.body = JSON.stringify({ status: 'ok' });
}
- const attrs = {uid: this.session.uid, status: 'open', contact_email, account_name, owner_key, provider: 'email'};
- attrs.remote_ip = getRemoteIp(this.req);
- const request = yield models.AccountRecoveryRequest.create(escAttrs(attrs));
- console.log('-- initiate_account_recovery_with_email -->', this.session.uid, request.id, account_name, owner_key);
- this.body = JSON.stringify({status: 'ok'});
- });
+ );
}
function* requestAccountRecovery({
recovery_account,
account_to_recover,
new_owner_authority,
- signing_key
+ signing_key,
}) {
- const operations = [['request_account_recovery', {
- recovery_account, account_to_recover, new_owner_authority,
- }]];
- yield broadcast.sendAsync({extensions: [], operations}, [signing_key]);
+ const operations = [
+ [
+ 'request_account_recovery',
+ {
+ recovery_account,
+ account_to_recover,
+ new_owner_authority,
+ },
+ ],
+ ];
+ yield broadcast.sendAsync({ extensions: [], operations }, [signing_key]);
}
diff --git a/src/server/api/general.js b/src/server/api/general.js
index b14361a5f1116f7c9c98da09d35b405b827c4a84..24fa19aee21fcbac561f1d20ca5c836a00149b66 100644
--- a/src/server/api/general.js
+++ b/src/server/api/general.js
@@ -1,129 +1,150 @@
/*global $STM_Config */
import koa_router from 'koa-router';
import koa_body from 'koa-body';
+import crypto from 'crypto';
import models from 'db/models';
import findUser from 'db/utils/find_user';
import config from 'config';
import recordWebEvent from 'server/record_web_event';
-import {esc, escAttrs} from 'db/models';
-import {emailRegex, getRemoteIp, rateLimitReq, checkCSRF} from 'server/utils/misc';
+import { esc, escAttrs } from 'db/models';
+import {
+ emailRegex,
+ getRemoteIp,
+ rateLimitReq,
+ checkCSRF,
+} from 'server/utils/misc';
import coBody from 'co-body';
import Mixpanel from 'mixpanel';
-import Tarantool from 'db/tarantool';
-import {PublicKey, Signature, hash} from 'steem/lib/auth/ecc';
-import {api, broadcast} from 'steem';
+import { PublicKey, Signature, hash } from '@steemit/steem-js/lib/auth/ecc';
+import { api, broadcast } from '@steemit/steem-js';
-const mixpanel = config.get('mixpanel') ? Mixpanel.init(config.get('mixpanel')) : null;
+const mixpanel = config.get('mixpanel')
+ ? Mixpanel.init(config.get('mixpanel'))
+ : null;
-const _stringval = (v) => typeof v === 'string' ? v : JSON.stringify(v)
+const _stringval = v => (typeof v === 'string' ? v : JSON.stringify(v));
function logRequest(path, ctx, extra) {
- let d = {ip: getRemoteIp(ctx.req)}
+ let d = { ip: getRemoteIp(ctx.req) };
if (ctx.session) {
if (ctx.session.user) {
- d.user = ctx.session.user
+ d.user = ctx.session.user;
}
if (ctx.session.uid) {
- d.uid = ctx.session.uid
+ d.uid = ctx.session.uid;
}
if (ctx.session.a) {
- d.account = ctx.session.a
+ d.account = ctx.session.a;
}
}
if (extra) {
- Object.keys(extra).forEach((k) => {
- const nk = d[k] ? '_'+k : k
- d[nk] = extra[k]
- })
+ Object.keys(extra).forEach(k => {
+ const nk = d[k] ? '_' + k : k;
+ d[nk] = extra[k];
+ });
}
- const info = Object.keys(d).map((k) => `${ k }=${ _stringval(d[k]) }`).join(' ')
- console.log(`-- /${ path } --> ${ info }`)
+ const info = Object.keys(d)
+ .map(k => `${k}=${_stringval(d[k])}`)
+ .join(' ');
+ console.log(`-- /${path} --> ${info}`);
}
export default function useGeneralApi(app) {
- const router = koa_router({prefix: '/api/v1'});
+ const router = koa_router({ prefix: '/api/v1' });
app.use(router.routes());
const koaBody = koa_body();
- router.post('/accounts_wait', koaBody, function *() {
+ router.post('/accounts_wait', koaBody, function*() {
if (rateLimitReq(this, this.req)) return;
const params = this.request.body;
- const account = typeof(params) === 'string' ? JSON.parse(params) : params;
+ const account =
+ typeof params === 'string' ? JSON.parse(params) : params;
const remote_ip = getRemoteIp(this.req);
if (!checkCSRF(this, account.csrf)) return;
- logRequest('accounts_wait', this, {account});
+ logRequest('accounts_wait', this, { account });
const user_id = this.session.user;
try {
- models.Account.create(escAttrs({
- user_id,
- name: account.name,
- owner_key: account.owner_key,
- active_key: account.active_key,
- posting_key: account.posting_key,
- memo_key: account.memo_key,
- remote_ip,
- referrer: this.session.r,
- created: false
- })).catch(error => {
- console.error('!!! Can\'t create account wait model in /accounts api', this.session.uid, error);
- });
+ models.Account.create(
+ escAttrs({
+ user_id,
+ name: account.name,
+ owner_key: account.owner_key,
+ active_key: account.active_key,
+ posting_key: account.posting_key,
+ memo_key: account.memo_key,
+ remote_ip,
+ referrer: this.session.r,
+ created: false,
+ })
+ ).catch(error => {
+ console.error(
+ "!!! Can't create account wait model in /accounts api",
+ this.session.uid,
+ error
+ );
+ });
if (mixpanel) {
mixpanel.track('Signup WaitList', {
distinct_id: this.session.uid,
- ip: remote_ip
+ ip: remote_ip,
});
- mixpanel.people.set(this.session.uid, {ip: remote_ip});
+ mixpanel.people.set(this.session.uid, { ip: remote_ip });
}
} catch (error) {
console.error('Error in /accounts_wait', error);
}
- this.body = JSON.stringify({status: 'ok'});
- recordWebEvent(this, 'api/accounts_wait', account ? account.name : 'n/a');
+ this.body = JSON.stringify({ status: 'ok' });
+ recordWebEvent(
+ this,
+ 'api/accounts_wait',
+ account ? account.name : 'n/a'
+ );
});
- router.post('/accounts', koaBody, function *() {
+ router.post('/accounts', koaBody, function*() {
if (rateLimitReq(this, this.req)) return;
const params = this.request.body;
- const account = typeof(params) === 'string' ? JSON.parse(params) : params;
+ const account =
+ typeof params === 'string' ? JSON.parse(params) : params;
if (!checkCSRF(this, account.csrf)) return;
- logRequest('accounts', this, {account})
+ logRequest('accounts', this, { account });
if ($STM_Config.disable_signups) {
- this.body = JSON.stringify({error: 'New signups are temporary disabled.'});
+ this.body = JSON.stringify({
+ error: 'New signups are temporary disabled.',
+ });
this.status = 401;
return;
}
const user_id = this.session.user;
- if (!user_id) { // require user to sign in with identity provider
- this.body = JSON.stringify({error: 'Unauthorized'});
+ if (!user_id) {
+ // require user to sign in with identity provider
+ this.body = JSON.stringify({ error: 'Unauthorized' });
this.status = 401;
return;
}
- // acquire global lock so only one account can be created at a time
try {
- const lock_entity_res = yield Tarantool.instance().call('lock_entity', user_id+'');
- if (!lock_entity_res[0][0]) {
- console.log('-- /accounts lock_entity -->', user_id, lock_entity_res[0][0]);
- this.body = JSON.stringify({error: 'Conflict'});
- this.status = 409;
- return;
+ const user = yield models.User.findOne({
+ attributes: ['id', 'creation_hash'],
+ where: { id: user_id, account_status: 'approved' },
+ });
+ if (!user) {
+ throw new Error(
+ "We can't find your sign up request. You either haven't started your sign up application or weren't approved yet."
+ );
}
- } catch (e) {
- console.error('-- /accounts tarantool is not available, fallback to another method', e)
- const rnd_wait_time = Math.random() * 10000;
- console.log('-- /accounts rnd_wait_time -->', rnd_wait_time);
- yield new Promise((resolve) =>
- setTimeout(() => resolve(), rnd_wait_time)
- )
- }
- try {
- const user = yield models.User.findOne(
- {attributes: ['id'], where: {id: user_id, account_status: 'approved'}}
- );
- if (!user) {
- throw new Error("We can't find your sign up request. You either haven't started your sign up application or weren't approved yet.");
+ // Is an account creation already happening for this user, maybe on another request?
+ // If so, throw an error.
+ if (user.creation_hash !== null) {
+ throw new Error('An account creation is in progress');
}
+ // If not, set this user's creation_hash.
+ // We'll check this later on, just before we create the account on chain.
+ const creationHash = hash
+ .sha256(crypto.randomBytes(32))
+ .toString('hex');
+ yield user.update({ creation_hash: creationHash });
// disable session/multi account for now
@@ -138,34 +159,70 @@ export default function useGeneralApi(app) {
const remote_ip = getRemoteIp(this.req);
// rate limit account creation to one per IP every 10 minutes
- const same_ip_account = yield models.Account.findOne(
- {attributes: ['created_at'], where: {remote_ip: esc(remote_ip), created: true}, order: 'id DESC'}
- );
+ const same_ip_account = yield models.Account.findOne({
+ attributes: ['created_at'],
+ where: { remote_ip: esc(remote_ip), created: true },
+ order: 'id DESC',
+ });
if (same_ip_account) {
- const minutes = (Date.now() - same_ip_account.created_at) / 60000;
+ const minutes =
+ (Date.now() - same_ip_account.created_at) / 60000;
if (minutes < 10) {
- console.log(`api /accounts: IP rate limit for user ${this.session.uid} #${user_id}, IP ${remote_ip}`);
- throw new Error('Only one Steem account allowed per IP address every 10 minutes');
+ console.log(
+ `api /accounts: IP rate limit for user ${
+ this.session.uid
+ } #${user_id}, IP ${remote_ip}`
+ );
+ throw new Error(
+ 'Only one Steem account allowed per IP address every 10 minutes'
+ );
}
}
- yield createAccount({
- signingKey: config.get('registrar.signing_key'),
- fee: config.get('registrar.fee'),
- creator: config.get('registrar.account'),
- new_account_name: account.name,
- delegation: config.get('registrar.delegation'),
- owner: account.owner_key,
- active: account.active_key,
- posting: account.posting_key,
- memo: account.memo_key
- });
- console.log('-- create_account_with_keys created -->', this.session.uid, account.name, user.id, account.owner_key);
+ // Ensure another registration is not in progress.
+ // Raw query with SQL_NO_CACHE avoids the MySQL query cache.
+ const newCreationHash = yield models.sequelize.query(
+ 'SELECT SQL_NO_CACHE creation_hash FROM users WHERE id = ?',
+ {
+ replacements: [user.id],
+ type: models.sequelize.QueryTypes.SELECT,
+ }
+ );
+
+ if (newCreationHash[0].creation_hash !== creationHash) {
+ console.log({ newCreationHash, creationHash });
+ throw new Error('Creation hash mismatch');
+ }
+
+ try {
+ yield createAccount({
+ signingKey: config.get('registrar.signing_key'),
+ fee: config.get('registrar.fee'),
+ creator: config.get('registrar.account'),
+ new_account_name: account.name,
+ delegation: config.get('registrar.delegation'),
+ owner: account.owner_key,
+ active: account.active_key,
+ posting: account.posting_key,
+ memo: account.memo_key,
+ });
+ } catch (e) {
+ yield user.update({ creation_hash: null });
+ throw new Error('Account creation error, try again.');
+ }
+
+ console.log(
+ '-- create_account_with_keys created -->',
+ this.session.uid,
+ account.name,
+ user.id,
+ account.owner_key
+ );
- this.body = JSON.stringify({status: 'ok'});
+ this.body = JSON.stringify({ status: 'ok' });
// update user account status
- yield user.update({account_status: 'created'});
+ yield user.update({ account_status: 'created' });
// update or create account record
const account_attrs = escAttrs({
@@ -177,13 +234,13 @@ export default function useGeneralApi(app) {
memo_key: account.memo_key,
remote_ip,
referrer: this.session.r,
- created: true
+ created: true,
});
const existing_account = yield models.Account.findOne({
attributes: ['id'],
- where: {user_id, name: account.name},
- order: 'id DESC'
+ where: { user_id, name: account.name },
+ order: 'id DESC',
});
if (existing_account) {
yield existing_account.update(account_attrs);
@@ -193,145 +250,278 @@ export default function useGeneralApi(app) {
if (mixpanel) {
mixpanel.track('Signup', {
distinct_id: this.session.uid,
- ip: remote_ip
+ ip: remote_ip,
});
- mixpanel.people.set(this.session.uid, {ip: remote_ip});
+ mixpanel.people.set(this.session.uid, { ip: remote_ip });
}
} catch (error) {
- console.error('Error in /accounts api call', this.session.uid, error.toString());
- this.body = JSON.stringify({error: error.message});
+ console.error(
+ 'Error in /accounts api call',
+ this.session.uid,
+ error.toString()
+ );
+ this.body = JSON.stringify({ error: error.message });
this.status = 500;
- } finally {
- // console.log('-- /accounts unlock_entity -->', user_id);
- // release global lock
- try { yield Tarantool.instance().call('unlock_entity', user_id + ''); } catch(e) {/* ram lock */}
}
recordWebEvent(this, 'api/accounts', account ? account.name : 'n/a');
});
- router.post('/update_email', koaBody, function *() {
+ /**
+ * Provides an endpoint to create user, account, and identity records.
+ * Used by faucet.
+ *
+ * HTTP params:
+ * name
+ * email
+ * owner_key
+ * secret
+ */
+ router.post('/create_user', koaBody, function*() {
+ const { name, email, owner_key, secret } =
+ typeof this.request.body === 'string'
+ ? JSON.parse(this.request.body)
+ : this.request.body;
+
+ if (secret !== process.env.CREATE_USER_SECRET)
+ throw new Error('invalid secret');
+
+ logRequest('create_user', this, { name, email, owner_key });
+
+ try {
+ if (!emailRegex.test(email.toLowerCase()))
+ throw new Error('not valid email: ' + email);
+ let user = yield models.User.create({
+ name: esc(name),
+ email: esc(email),
+ });
+ const account = yield models.Account.create({
+ user_id: user.id,
+ name: esc(name),
+ owner_key: esc(owner_key),
+ });
+ const identity = yield models.Identity.create({
+ user_id: user.id,
+ name: esc(name),
+ provider: 'email',
+ verified: true,
+ email: user.email,
+ owner_key: esc(owner_key),
+ });
+ this.body = JSON.stringify({
+ success: true,
+ user,
+ account,
+ identity,
+ });
+ } catch (error) {
+ console.error('Error in /create_user api call', error);
+ this.body = JSON.stringify({ error: error.message });
+ this.status = 500;
+ }
+ recordWebEvent(this, 'api/create_user', { name, email });
+ });
+
+ router.post('/update_email', koaBody, function*() {
if (rateLimitReq(this, this.req)) return;
const params = this.request.body;
- const {csrf, email} = typeof(params) === 'string' ? JSON.parse(params) : params;
+ const { csrf, email } =
+ typeof params === 'string' ? JSON.parse(params) : params;
if (!checkCSRF(this, csrf)) return;
- logRequest('update_email', this, {email});
+ logRequest('update_email', this, { email });
try {
- if (!emailRegex.test(email.toLowerCase())) throw new Error('not valid email: ' + email);
+ if (!emailRegex.test(email.toLowerCase()))
+ throw new Error('not valid email: ' + email);
// TODO: limit by 1/min/ip
- let user = yield findUser({user_id: this.session.user, email: esc(email), uid: this.session.uid});
+ let user = yield findUser({
+ user_id: this.session.user,
+ email: esc(email),
+ uid: this.session.uid,
+ });
if (user) {
- user = yield models.User.update({email: esc(email), waiting_list: true}, {where: {id: user.id}});
+ user = yield models.User.update(
+ { email: esc(email), waiting_list: true },
+ { where: { id: user.id } }
+ );
} else {
- user = yield models.User.create({email: esc(email), waiting_list: true});
+ user = yield models.User.create({
+ email: esc(email),
+ waiting_list: true,
+ });
}
this.session.user = user.id;
- this.body = JSON.stringify({status: 'ok'});
+ this.body = JSON.stringify({ status: 'ok' });
} catch (error) {
- console.error('Error in /update_email api call', this.session.uid, error);
- this.body = JSON.stringify({error: error.message});
+ console.error(
+ 'Error in /update_email api call',
+ this.session.uid,
+ error
+ );
+ this.body = JSON.stringify({ error: error.message });
this.status = 500;
}
recordWebEvent(this, 'api/update_email', email);
});
- router.post('/login_account', koaBody, function *() {
+ router.post('/login_account', koaBody, function*() {
// if (rateLimitReq(this, this.req)) return;
const params = this.request.body;
- const {csrf, account, signatures} = typeof(params) === 'string' ? JSON.parse(params) : params;
+ const { csrf, account, signatures } =
+ typeof params === 'string' ? JSON.parse(params) : params;
if (!checkCSRF(this, csrf)) return;
- logRequest('login_account', this, {account});
+ logRequest('login_account', this, { account });
try {
- const db_account = yield models.Account.findOne(
- {attributes: ['user_id'], where: {name: esc(account)}, logging: false}
- );
+ const db_account = yield models.Account.findOne({
+ attributes: ['user_id'],
+ where: { name: esc(account) },
+ logging: false,
+ });
if (db_account) this.session.user = db_account.user_id;
- if(signatures) {
- if(!this.session.login_challenge) {
- console.error('/login_account missing this.session.login_challenge');
+ if (signatures) {
+ if (!this.session.login_challenge) {
+ console.error(
+ '/login_account missing this.session.login_challenge'
+ );
} else {
- const [chainAccount] = yield api.getAccountsAsync([account])
- if(!chainAccount) {
- console.error('/login_account missing blockchain account', account);
+ const [chainAccount] = yield api.getAccountsAsync([
+ account,
+ ]);
+ if (!chainAccount) {
+ console.error(
+ '/login_account missing blockchain account',
+ account
+ );
} else {
- const auth = {posting: false}
- const bufSha = hash.sha256(JSON.stringify({token: this.session.login_challenge}, null, 0))
- const verify = (type, sigHex, pubkey, weight, weight_threshold) => {
- if(!sigHex) return
- if(weight !== 1 || weight_threshold !== 1) {
- console.error(`/login_account login_challenge unsupported ${type} auth configuration: ${account}`);
+ const auth = { posting: false };
+ const bufSha = hash.sha256(
+ JSON.stringify(
+ { token: this.session.login_challenge },
+ null,
+ 0
+ )
+ );
+ const verify = (
+ type,
+ sigHex,
+ pubkey,
+ weight,
+ weight_threshold
+ ) => {
+ if (!sigHex) return;
+ if (weight !== 1 || weight_threshold !== 1) {
+ console.error(
+ `/login_account login_challenge unsupported ${
+ type
+ } auth configuration: ${account}`
+ );
} else {
- const sig = parseSig(sigHex)
- const public_key = PublicKey.fromString(pubkey)
- const verified = sig.verifyHash(bufSha, public_key)
+ const sig = parseSig(sigHex);
+ const public_key = PublicKey.fromString(pubkey);
+ const verified = sig.verifyHash(
+ bufSha,
+ public_key
+ );
if (!verified) {
- console.error('/login_account verification failed', this.session.uid, account, pubkey)
+ console.error(
+ '/login_account verification failed',
+ this.session.uid,
+ account,
+ pubkey
+ );
}
- auth[type] = verified
+ auth[type] = verified;
}
- }
- const {posting: {key_auths: [[posting_pubkey, weight]], weight_threshold}} = chainAccount
- verify('posting', signatures.posting, posting_pubkey, weight, weight_threshold)
+ };
+ const {
+ posting: {
+ key_auths: [[posting_pubkey, weight]],
+ weight_threshold,
+ },
+ } = chainAccount;
+ verify(
+ 'posting',
+ signatures.posting,
+ posting_pubkey,
+ weight,
+ weight_threshold
+ );
if (auth.posting) this.session.a = account;
}
}
}
- this.body = JSON.stringify({status: 'ok'});
+ this.body = JSON.stringify({ status: 'ok' });
const remote_ip = getRemoteIp(this.req);
if (mixpanel) {
- mixpanel.people.set(this.session.uid, {ip: remote_ip, $ip: remote_ip});
+ mixpanel.people.set(this.session.uid, {
+ ip: remote_ip,
+ $ip: remote_ip,
+ });
mixpanel.people.increment(this.session.uid, 'Logins', 1);
}
} catch (error) {
- console.error('Error in /login_account api call', this.session.uid, error.message);
- this.body = JSON.stringify({error: error.message});
+ console.error(
+ 'Error in /login_account api call',
+ this.session.uid,
+ error.message
+ );
+ this.body = JSON.stringify({ error: error.message });
this.status = 500;
}
recordWebEvent(this, 'api/login_account', account);
});
- router.post('/logout_account', koaBody, function *() {
+ router.post('/logout_account', koaBody, function*() {
// if (rateLimitReq(this, this.req)) return; - logout maybe immediately followed with login_attempt event
const params = this.request.body;
- const {csrf} = typeof(params) === 'string' ? JSON.parse(params) : params;
+ const { csrf } =
+ typeof params === 'string' ? JSON.parse(params) : params;
if (!checkCSRF(this, csrf)) return;
logRequest('logout_account', this);
try {
this.session.a = null;
- this.body = JSON.stringify({status: 'ok'});
+ this.body = JSON.stringify({ status: 'ok' });
} catch (error) {
- console.error('Error in /logout_account api call', this.session.uid, error);
- this.body = JSON.stringify({error: error.message});
+ console.error(
+ 'Error in /logout_account api call',
+ this.session.uid,
+ error
+ );
+ this.body = JSON.stringify({ error: error.message });
this.status = 500;
}
});
- router.post('/record_event', koaBody, function *() {
+ router.post('/record_event', koaBody, function*() {
if (rateLimitReq(this, this.req)) return;
try {
const params = this.request.body;
- const {csrf, type, value} = typeof(params) === 'string' ? JSON.parse(params) : params;
+ const { csrf, type, value } =
+ typeof params === 'string' ? JSON.parse(params) : params;
if (!checkCSRF(this, csrf)) return;
- logRequest('record_event', this, {type, value});
- const str_value = typeof value === 'string' ? value : JSON.stringify(value);
+ logRequest('record_event', this, { type, value });
+ const str_value =
+ typeof value === 'string' ? value : JSON.stringify(value);
if (type.match(/^[A-Z]/)) {
if (mixpanel) {
- mixpanel.track(type, {distinct_id: this.session.uid, Page: str_value});
+ mixpanel.track(type, {
+ distinct_id: this.session.uid,
+ Page: str_value,
+ });
mixpanel.people.increment(this.session.uid, type, 1);
}
} else {
recordWebEvent(this, type, str_value);
}
- this.body = JSON.stringify({status: 'ok'});
+ this.body = JSON.stringify({ status: 'ok' });
} catch (error) {
console.error('Error in /record_event api call', error.message);
- this.body = JSON.stringify({error: error.message});
+ this.body = JSON.stringify({ error: error.message });
this.status = 500;
}
});
- router.post('/csp_violation', function *() {
+ router.post('/csp_violation', function*() {
if (rateLimitReq(this, this.req)) return;
let params;
try {
@@ -341,51 +531,69 @@ export default function useGeneralApi(app) {
}
if (params && params['csp-report']) {
const csp_report = params['csp-report'];
- const value = `${csp_report['document-uri']} : ${csp_report['blocked-uri']}`;
- console.log('-- /csp_violation -->', value, '--', this.req.headers['user-agent']);
+ const value = `${csp_report['document-uri']} : ${
+ csp_report['blocked-uri']
+ }`;
+ console.log(
+ '-- /csp_violation -->',
+ value,
+ '--',
+ this.req.headers['user-agent']
+ );
recordWebEvent(this, 'csp_violation', value);
} else {
- console.log('-- /csp_violation [no csp-report] -->', params, '--', this.req.headers['user-agent']);
+ console.log(
+ '-- /csp_violation [no csp-report] -->',
+ params,
+ '--',
+ this.req.headers['user-agent']
+ );
}
this.body = '';
});
- router.post('/page_view', koaBody, function *() {
+ router.post('/page_view', koaBody, function*() {
const params = this.request.body;
- const {csrf, page, ref} = typeof(params) === 'string' ? JSON.parse(params) : params;
+ const { csrf, page, ref } =
+ typeof params === 'string' ? JSON.parse(params) : params;
if (!checkCSRF(this, csrf)) return;
if (page.match(/\/feed$/)) {
- this.body = JSON.stringify({views: 0});
+ this.body = JSON.stringify({ views: 0 });
return;
}
const remote_ip = getRemoteIp(this.req);
- logRequest('page_view', this, {page});
+ logRequest('page_view', this, { page });
try {
- let views = 1, unique = true;
- if (config.has('tarantool') && config.has('tarantool.host')) {
- try {
- const res = yield Tarantool.instance().call('page_view', page, remote_ip, this.session.uid, ref);
- unique = res[0][0];
- } catch (e) {}
- }
- const page_model = yield models.Page.findOne(
- {attributes: ['id', 'views'], where: {permlink: esc(page)}, logging: false}
- );
+ let views = 1,
+ unique = true;
+ const page_model = yield models.Page.findOne({
+ attributes: ['id', 'views'],
+ where: { permlink: esc(page) },
+ logging: false,
+ });
if (unique) {
if (page_model) {
views = page_model.views + 1;
- yield yield models.Page.update({views}, {where: {id: page_model.id}, logging: false});
+ yield yield models.Page.update(
+ { views },
+ { where: { id: page_model.id }, logging: false }
+ );
} else {
- yield models.Page.create(escAttrs({permlink: page, views}), {logging: false});
+ yield models.Page.create(
+ escAttrs({ permlink: page, views }),
+ { logging: false }
+ );
}
} else {
if (page_model) views = page_model.views;
}
- this.body = JSON.stringify({views});
+ this.body = JSON.stringify({ views });
if (mixpanel) {
let referring_domain = '';
if (ref) {
- const matches = ref.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
+ const matches = ref.match(
+ /^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i
+ );
referring_domain = matches && matches[1];
}
const mp_params = {
@@ -393,54 +601,74 @@ export default function useGeneralApi(app) {
Page: page,
ip: remote_ip,
$referrer: ref,
- $referring_domain: referring_domain
+ $referring_domain: referring_domain,
};
mixpanel.track('PageView', mp_params);
if (!this.session.mp) {
mixpanel.track('FirstVisit', mp_params);
this.session.mp = 1;
}
- if (ref) mixpanel.people.set_once(this.session.uid, '$referrer', ref);
+ if (ref)
+ mixpanel.people.set_once(
+ this.session.uid,
+ '$referrer',
+ ref
+ );
mixpanel.people.set_once(this.session.uid, 'FirstPage', page);
mixpanel.people.increment(this.session.uid, 'PageView', 1);
}
} catch (error) {
- console.error('Error in /page_view api call', this.session.uid, error.message);
- this.body = JSON.stringify({error: error.message});
+ console.error(
+ 'Error in /page_view api call',
+ this.session.uid,
+ error.message
+ );
+ this.body = JSON.stringify({ error: error.message });
this.status = 500;
}
});
- router.post('/save_cords', koaBody, function *() {
+ router.post('/save_cords', koaBody, function*() {
const params = this.request.body;
- const {csrf, x, y} = typeof(params) === 'string' ? JSON.parse(params) : params;
+ const { csrf, x, y } =
+ typeof params === 'string' ? JSON.parse(params) : params;
if (!checkCSRF(this, csrf)) return;
const user = yield models.User.findOne({
- where: { id: this.session.user }
+ where: { id: this.session.user },
});
if (user) {
let data = user.sign_up_meta ? JSON.parse(user.sign_up_meta) : {};
- data["button_screen_x"] = x;
- data["button_screen_y"] = y;
- data["last_step"] = 3;
+ data['button_screen_x'] = x;
+ data['button_screen_y'] = y;
+ data['last_step'] = 3;
try {
user.update({
- sign_up_meta: JSON.stringify(data)
+ sign_up_meta: JSON.stringify(data),
});
} catch (error) {
- console.error('Error in /save_cords api call', this.session.uid, error.message);
- this.body = JSON.stringify({error: error.message});
+ console.error(
+ 'Error in /save_cords api call',
+ this.session.uid,
+ error.message
+ );
+ this.body = JSON.stringify({ error: error.message });
this.status = 500;
}
}
- this.body = JSON.stringify({status: 'ok'});
+ this.body = JSON.stringify({ status: 'ok' });
});
- router.post('/setUserPreferences', koaBody, function *() {
+ router.post('/setUserPreferences', koaBody, function*() {
const params = this.request.body;
- const {csrf, payload} = typeof(params) === 'string' ? JSON.parse(params) : params;
+ const { csrf, payload } =
+ typeof params === 'string' ? JSON.parse(params) : params;
if (!checkCSRF(this, csrf)) return;
- console.log('-- /setUserPreferences -->', this.session.user, this.session.uid, payload);
+ console.log(
+ '-- /setUserPreferences -->',
+ this.session.user,
+ this.session.uid,
+ payload
+ );
if (!this.session.a) {
this.body = 'missing logged in account';
this.status = 500;
@@ -450,10 +678,14 @@ export default function useGeneralApi(app) {
const json = JSON.stringify(payload);
if (json.length > 1024) throw new Error('the data is too long');
this.session.user_prefs = json;
- this.body = JSON.stringify({status: 'ok'});
+ this.body = JSON.stringify({ status: 'ok' });
} catch (error) {
- console.error('Error in /setUserPreferences api call', this.session.uid, error);
- this.body = JSON.stringify({error: error.message});
+ console.error(
+ 'Error in /setUserPreferences api call',
+ this.session.uid,
+ error
+ );
+ this.body = JSON.stringify({ error: error.message });
this.status = 500;
}
});
@@ -463,20 +695,58 @@ export default function useGeneralApi(app) {
@arg signingKey {string|PrivateKey} - WIF or PrivateKey object
*/
function* createAccount({
- signingKey, fee, creator, new_account_name, json_metadata = '', delegation,
- owner, active, posting, memo
+ signingKey,
+ fee,
+ creator,
+ new_account_name,
+ json_metadata = '',
+ delegation,
+ owner,
+ active,
+ posting,
+ memo,
}) {
- const operations = [['account_create_with_delegation', {
- fee, creator, new_account_name, json_metadata, delegation,
- owner: {weight_threshold: 1, account_auths: [], key_auths: [[owner, 1]]},
- active: {weight_threshold: 1, account_auths: [], key_auths: [[active, 1]]},
- posting: {weight_threshold: 1, account_auths: [], key_auths: [[posting, 1]]},
- memo_key: memo,
- }]]
- yield broadcast.sendAsync({
- extensions: [],
- operations
- }, [signingKey])
+ const operations = [
+ [
+ 'account_create_with_delegation',
+ {
+ fee,
+ creator,
+ new_account_name,
+ json_metadata,
+ delegation,
+ owner: {
+ weight_threshold: 1,
+ account_auths: [],
+ key_auths: [[owner, 1]],
+ },
+ active: {
+ weight_threshold: 1,
+ account_auths: [],
+ key_auths: [[active, 1]],
+ },
+ posting: {
+ weight_threshold: 1,
+ account_auths: [],
+ key_auths: [[posting, 1]],
+ },
+ memo_key: memo,
+ },
+ ],
+ ];
+ yield broadcast.sendAsync(
+ {
+ extensions: [],
+ operations,
+ },
+ [signingKey]
+ );
}
-const parseSig = hexSig => {try {return Signature.fromHex(hexSig)} catch(e) {return null}}
+const parseSig = hexSig => {
+ try {
+ return Signature.fromHex(hexSig);
+ } catch (e) {
+ return null;
+ }
+};
diff --git a/src/server/api/notifications.js b/src/server/api/notifications.js
deleted file mode 100644
index 3a99cef53f3ecd24f560bb55424d35525c89b728..0000000000000000000000000000000000000000
--- a/src/server/api/notifications.js
+++ /dev/null
@@ -1,88 +0,0 @@
-import koa_router from 'koa-router';
-import koa_body from 'koa-body';
-import Tarantool from 'db/tarantool';
-import config from 'config';
-import webPush from 'web-push';
-import {checkCSRF} from 'server/utils/misc';
-import sendEmail from "../sendEmail";
-
-if(config.has('notify.gcm_key')) {
- webPush.setGCMAPIKey(config.get('notify.gcm_key'));
-}
-
-function toResArray(result) {
- if (!result || result.length < 1) return [];
- return result[0].slice(1);
-}
-
-export default function useNotificationsApi(app) {
- const router = koa_router({prefix: '/api/v1'});
- app.use(router.routes());
- const koaBody = koa_body();
-
- // get all notifications for account
- router.get('/notifications/:account', function *() {
- const account = this.params.account;
- console.log('-- GET /notifications/:account -->', this.session.uid, account, status(this, account));
-
- if (!account || account !== this.session.a) {
- this.body = []; return;
- }
- try {
- const res = yield Tarantool.instance().select('notifications', 0, 1, 0, 'eq', account);
- this.body = toResArray(res);
- } catch (error) {
- console.error('-- /notifications/:account error -->', this.session.uid, error.message);
- this.body = [];
- }
- return;
- });
-
- // mark account's notification as read
- router.put('/notifications/:account/:ids', function *() {
- const {account, ids} = this.params;
- console.log('-- PUT /notifications/:account/:id -->', this.session.uid, account, status(this, account));
-
- if (!ids || !account || account !== this.session.a) {
- this.body = []; return;
- }
- const fields = ids.split('-');
- try {
- let res;
- for(const id of fields) {
- res = yield Tarantool.instance().call('notification_read', account, id);
- }
- this.body = toResArray(res);
- } catch (error) {
- console.error('-- /notifications/:account/:id error -->', this.session.uid, error.message);
- this.body = [];
- }
- return;
- });
-
- router.post('/notifications/register', koaBody, function *() {
- this.body = '';
- try {
- const params = this.request.body;
- const {csrf, account, webpush_params} = typeof(params) === 'string' ? JSON.parse(params) : params;
- if (!checkCSRF(this, csrf)) return;
- console.log('-- POST /notifications/register -->', this.session.uid, account, webpush_params);
- if (!account || account !== this.session.a) return;
- if (!webpush_params || !webpush_params.endpoint || !webpush_params.endpoint.match(/^https:\/\/android\.googleapis\.com/)) return;
- if (!webpush_params.keys || !webpush_params.keys.auth) return;
- yield Tarantool.instance().call('webpush_subscribe', account, webpush_params);
- } catch (error) {
- console.error('-- POST /notifications/register error -->', this.session.uid, error.message);
- }
- });
-
- router.post('/notifications/send_confirm', koaBody, function *(email, id) {
- console.log("sendign email", email,id);
- sendEmail("confirm_email", email, { id });
- });
-}
-
-const status = (ctx, account) =>
-ctx.session.a == null ? 'not logged in' :
- account !== ctx.session.a ? 'wrong account' + ctx.session.a :
- '';
diff --git a/src/server/api/oauth.js b/src/server/api/oauth.js
deleted file mode 100644
index df1a2dbbf615d717868442c0d25269a0a8296a94..0000000000000000000000000000000000000000
--- a/src/server/api/oauth.js
+++ /dev/null
@@ -1,266 +0,0 @@
-import route from 'koa-route';
-import Purest from 'purest';
-import models from 'db/models';
-import findUser from 'db/utils/find_user';
-import {esc, escAttrs} from 'db/models';
-
-const facebook = new Purest({provider: 'facebook'});
-const reddit = new Purest({provider: 'reddit'});
-
-function logErrorAndRedirect(ctx, where, error) {
- const s = ctx.session;
- let msg = 'unknown';
- if (error.toString()) msg = error.toString()
- else msg = error.error && error.error.message ? error.error.message : (error.msg || JSON.stringify(error));
- console.error(`oauth error [${where}|${s.user}|${s.uid}]|${ctx.req.headers['user-agent']}: ${msg}`);
- if (process.env.NODE_ENV === 'development') console.log(error.stack);
- ctx.flash = {alert: `${where} error: ${msg}`};
- ctx.redirect('/');
- return null;
-}
-
-function getRemoteIp(req) {
- const remote_address = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
- const ip_match = remote_address ? remote_address.match(/(\d+\.\d+\.\d+\.\d+)/) : null;
- return ip_match ? ip_match[1] : esc(remote_address);
-}
-
-function retrieveFacebookUserData(access_token) {
- return new Promise((resolve, reject) => {
- facebook.query()
- .get('me?fields=name,email,location,picture{url},verified')
- .auth(access_token)
- .request((err, res) => {
- if (err) {
- reject(err);
- } else {
- resolve(res.body);
- }
- });
- });
-}
-
-function* handleFacebookCallback() {
- console.log('-- /handle_facebook_callback -->', this.session.uid, this.query);
- let email = null;
- try {
- if (this.query['error[error][message]']) {
- return logErrorAndRedirect(this, 'facebook:1', this.query['error[error][message]']);
- }
- const u = yield retrieveFacebookUserData(this.query.access_token);
- email = u.email;
- const attrs = {
- uid: this.session.uid,
- name: u.name,
- email: u.email,
- first_name: u.first_name,
- last_name: u.last_name,
- birthday: u.birthday ? new Date(u.birthday) : null,
- gender: u.gender,
- picture_small: u.picture ? u.picture.data.url : null,
- location_id: u.location ? u.location.id : null,
- location_name: u.location ? u.location.name : null,
- locale: u.locale,
- timezone: u.timezone,
- remote_ip: getRemoteIp(this.request.req),
- verified: u.verified,
- waiting_list: false,
- facebook_id: u.id
- };
- const i_attrs = {
- provider: 'facebook',
- uid: u.id,
- name: u.name,
- email: u.email,
- verified: u.verified,
- provider_user_id: u.id
- };
- // const i_attrs_email = {
- // provider: 'email',
- // email: u.email,
- // verified: false
- // };
-
- let user = yield findUser({email: u.email, provider_user_id: u.id});
- console.log('-- /handle_facebook_callback user id -->', this.session.uid, user ? user.id : 'not found');
-
- let account_recovery_record = null;
- const provider = this.session.prv = 'facebook';
- if (this.session.arec) {
- const arec = yield models.AccountRecoveryRequest.findOne({
- attributes: ['id', 'created_at', 'account_name', 'owner_key'],
- where: {id: this.session.arec}
- });
- if (arec) {
- const seconds_ago = (Date.now() - arec.created_at) / 1000;
- console.log('-- /handle_facebook_callback arec -->', this.session.uid, seconds_ago, arec.created_at);
- if (seconds_ago < 600) account_recovery_record = arec;
- }
- }
- if (account_recovery_record) {
- if (user) {
- const existing_account = yield models.Account.findOne({
- attributes: ['id'],
- where: {user_id: user.id, name: account_recovery_record.account_name},
- order: 'id DESC'
- });
- if (existing_account) {
- console.log('-- arec: confirmed user for account -->', this.session.uid, provider, account_recovery_record.id, existing_account.name, this.session.uid, account_recovery_record.owner_key);
- account_recovery_record.update({user_id: user.id, status: 'confirmed'});
- this.redirect('/recover_account_step_2');
- } else {
- console.log('-- arec: failed to confirm user for account (no account) -->', this.session.uid, provider, account_recovery_record.id, user.id, this.session.uid, account_recovery_record.owner_key);
- account_recovery_record.update({user_id: user.id, status: 'account not found'});
- this.body = 'We cannot verify the user account. Please contact support@steemit.com';
- }
- } else {
- console.log('-- arec: failed to confirm user for account (no user) -->', this.session.uid, provider, this.session.uid, this.session.email);
- account_recovery_record.update({status: 'user not found'});
- this.body = 'We cannot verify the user account. Please contact support@steemit.com';
- }
- return null;
- }
- // no longer necessary since there is phone verification now
- // if (!u.email) {
- // console.log('-- /handle_facebook_callback no email -->', this.session.uid, u);
- // this.flash = {alert: 'Facebook login didn\'t provide any email addresses. Please make sure your Facebook account has a primary email address and try again.'};
- // this.redirect('/');
- // return;
- // }
- // if (!u.verified) {
- // throw new Error('Not verified Facebook account. Please verify your Facebook account and try again to sign up to Steemit.');
- // }
-
- if (user) {
- attrs.id = user.id;
- yield models.User.update(attrs, {where: {id: user.id}});
- yield models.Identity.update(i_attrs, {where: {user_id: user.id, provider: 'facebook'}});
- console.log('-- fb updated user -->', this.session.uid, user.id, u.name, u.email);
- } else {
- user = yield models.User.create(attrs);
- i_attrs.user_id = user.id;
- console.log('-- fb created user -->', user.id, u.name, u.email);
- const identity = yield models.Identity.create(i_attrs);
- console.log('-- fb created identity -->', this.session.uid, identity.id);
- // if (i_attrs_email.email) {
- // i_attrs_email.user_id = user.id
- // const email_identity = yield models.Identity.create(i_attrs_email);
- // console.log('-- fb created email identity -->', this.session.uid, email_identity.id);
- // }
- }
- this.session.user = user.id;
- } catch (error) {
- return logErrorAndRedirect(this, 'facebook:2', error);
- }
- this.flash = {success: 'Successfully authenticated with Facebook'};
- this.redirect('/enter_email' + (email ? `?email=${email}` : ''));
- return null;
-}
-
-function retrieveRedditUserData(access_token) {
- return new Promise((resolve, reject) => {
- reddit.query()
- .get('https://oauth.reddit.com/api/v1/me.json?raw_json=1')
- .headers({
- Authorization: `bearer ${access_token}`,
- 'User-Agent': 'Steembot/1.0 (+http://steemit.com)',
- Accept: 'application/json',
- 'Content-type': 'application/json'
- })
- .request((err, res) => {
- if (err) {
- reject(err);
- } else {
- delete res.body.features;
- resolve(res.body);
- }
- });
- });
-}
-
-function* handleRedditCallback() {
- try {
- const u = yield retrieveRedditUserData(this.query.access_token);
- console.log('-- /handle_reddit_callback -->', this.session.uid, u);
- let user = yield findUser({provider_user_id: u.id});
- console.log('-- /handle_reddit_callback user id -->', this.session.uid, user ? user.id : 'not found');
-
- let account_recovery_record = null;
- const provider = this.session.prv = 'reddit';
- if (this.session.arec) {
- const arec = yield models.AccountRecoveryRequest.findOne({
- attributes: ['id', 'created_at', 'account_name', 'owner_key'],
- where: {id: this.session.arec}
- });
- if (arec) {
- const seconds_ago = (Date.now() - arec.created_at) / 1000;
- if (seconds_ago < 600) account_recovery_record = arec;
- }
- }
- if (account_recovery_record) {
- if (user) {
- const existing_account = yield models.Account.findOne({
- attributes: ['id'],
- where: {user_id: user.id, name: account_recovery_record.account_name},
- order: 'id DESC'
- });
- if (existing_account) {
- console.log('-- arec: confirmed user for account -->', this.session.uid, provider, account_recovery_record.id, existing_account.name, this.session.uid, account_recovery_record.owner_key);
- account_recovery_record.update({user_id: user.id, status: 'confirmed'});
- this.redirect('/recover_account_step_2');
- } else {
- console.log('-- arec: failed to confirm user for account (no account) -->', this.session.uid, provider, account_recovery_record.id, user.id, this.session.uid, account_recovery_record.owner_key);
- account_recovery_record.update({user_id: user.id, status: 'account not found'});
- this.body = 'We cannot verify the user account. Please contact support@steemit.com';
- }
- } else {
- console.log('-- arec: failed to confirm user for account (no user) -->', this.session.uid, provider, this.session.arec, this.session.email);
- account_recovery_record.update({status: 'user not found'});
- this.body = 'We cannot verify the user account. Please contact support@steemit.com';
- }
- return null;
- }
-
- const waiting_list = !u.comment_karma || u.comment_karma < 5;
- const i_attrs = {
- provider: 'reddit',
- provider_user_id: u.id,
- name: u.name,
- score: u.comment_karma
- };
- const attrs = {
- id: user ? user.id : null,
- uid: this.session.uid,
- name: u.name,
- remote_ip: getRemoteIp(this.req),
- verified: false
- };
- if (user) {
- if (!waiting_list) attrs.waiting_list = false;
- yield models.User.update(attrs, {where: {id: user.id}});
- yield models.Identity.update(i_attrs, {where: {user_id: user.id, provider: 'reddit'}});
- console.log('-- reddit updated user -->', this.session.uid, user.id, u.name);
- } else {
- attrs.waiting_list = waiting_list;
- user = yield models.User.create(attrs);
- console.log('-- reddit created user -->', this.session.uid, user.id, u.name);
- i_attrs.user_id = user.id;
- const identity = yield models.Identity.create(i_attrs);
- console.log('-- reddit created identity -->', this.session.uid, identity.id);
- }
- this.session.user = user.id;
- if (waiting_list) {
- this.redirect('/waiting_list.html');
- return null;
- }
- } catch (error) {
- return logErrorAndRedirect(this, 'reddit', error);
- }
- this.redirect('/enter_email');
- return null;
-}
-
-export default function useOauthLogin(app) {
- app.use(route.get('/handle_facebook_callback', handleFacebookCallback));
- app.use(route.get('/handle_reddit_callback', handleRedditCallback));
-}
diff --git a/src/server/app_render.jsx b/src/server/app_render.jsx
index 5d6ccf476cf054114a51b9d8bf076ae4a6c2b3c7..87383a5cee21184fe92f2c2743c97b721655f1e3 100644
--- a/src/server/app_render.jsx
+++ b/src/server/app_render.jsx
@@ -1,23 +1,25 @@
import React from 'react';
import { renderToString } from 'react-dom/server';
import Tarantool from 'db/tarantool';
+import { VIEW_MODE_WHISTLE, PARAM_VIEW_MODE } from '../shared/constants';
import ServerHTML from './server-html';
import universalRender from '../shared/UniversalRender';
import models from 'db/models';
import secureRandom from 'secure-random';
import ErrorPage from 'server/server-error';
import fs from 'fs';
+import { determineViewMode } from '../app/utils/Links';
const path = require('path');
const ROOT = path.join(__dirname, '../..');
-
-const DB_RECONNECT_TIMEOUT = process.env.NODE_ENV === 'development' ? 1000 * 60 * 60 : 1000 * 60 * 10;
+const DB_RECONNECT_TIMEOUT =
+ process.env.NODE_ENV === 'development' ? 1000 * 60 * 60 : 1000 * 60 * 10;
function getSupportedLocales() {
const locales = [];
const files = fs.readdirSync(path.join(ROOT, 'src/app/locales'));
for (const filename of files) {
- const match_res = filename.match(/(\w+)\.json?$/)
+ const match_res = filename.match(/(\w+)\.json?$/);
if (match_res) locales.push(match_res[1]);
}
return locales;
@@ -33,7 +35,11 @@ async function appRender(ctx) {
try {
userPreferences = JSON.parse(ctx.session.user_prefs);
} catch (err) {
- console.error('cannot parse user preferences:', ctx.session.uid, err);
+ console.error(
+ 'cannot parse user preferences:',
+ ctx.session.uid,
+ err
+ );
}
}
if (!userPreferences.locale) {
@@ -55,24 +61,46 @@ async function appRender(ctx) {
account: ctx.session.a,
config: $STM_Config,
uid: ctx.session.uid,
- login_challenge
+ login_challenge,
};
const user_id = ctx.session.user;
if (user_id) {
let user = null;
- if (appRender.dbStatus.ok || (new Date() - appRender.dbStatus.lastAttempt) > DB_RECONNECT_TIMEOUT) {
+ if (
+ appRender.dbStatus.ok ||
+ new Date() - appRender.dbStatus.lastAttempt >
+ DB_RECONNECT_TIMEOUT
+ ) {
try {
user = await models.User.findOne({
- attributes: ['name', 'email', 'picture_small', 'account_status'],
- where: {id: user_id},
- include: [{model: models.Account, attributes: ['name', 'ignored', 'created', 'owner_key']}],
+ attributes: [
+ 'name',
+ 'email',
+ 'picture_small',
+ 'account_status',
+ ],
+ where: { id: user_id },
+ include: [
+ {
+ model: models.Account,
+ attributes: [
+ 'name',
+ 'ignored',
+ 'created',
+ 'owner_key',
+ ],
+ },
+ ],
order: 'Accounts.id desc',
- logging: false
+ logging: false,
});
- appRender.dbStatus = {ok: true};
+ appRender.dbStatus = { ok: true };
} catch (e) {
- appRender.dbStatus = {ok: false, lastAttempt: new Date()};
- console.error('WARNING! mysql query failed: ', e.toString());
+ appRender.dbStatus = { ok: false, lastAttempt: new Date() };
+ console.error(
+ 'WARNING! mysql query failed: ',
+ e.toString()
+ );
offchain.serverBusy = true;
}
} else {
@@ -93,29 +121,47 @@ async function appRender(ctx) {
offchain.user = {
id: user_id,
name: user.name,
- email: user.email,
picture: user.picture_small,
prv: ctx.session.prv,
account_status: user.account_status,
account,
- account_has_keys
- }
+ account_has_keys,
+ };
}
}
if (ctx.session.arec) {
- const account_recovery_record = await models.AccountRecoveryRequest.findOne({
- attributes: ['id', 'account_name', 'status', 'provider'],
- where: {id: ctx.session.arec, status: 'confirmed'}
- });
+ const account_recovery_record = await models.AccountRecoveryRequest.findOne(
+ {
+ attributes: ['id', 'account_name', 'status', 'provider'],
+ where: { id: ctx.session.arec, status: 'confirmed' },
+ }
+ );
if (account_recovery_record) {
offchain.recover_account = account_recovery_record.account_name;
}
}
+ const initial_state = {
+ app: {
+ viewMode: determineViewMode(ctx.request.search),
+ },
+ };
- const { body, title, statusCode, meta } = await universalRender({location: ctx.request.url, store, offchain, ErrorPage, tarantool: Tarantool.instance(), userPreferences});
+ const { body, title, statusCode, meta } = await universalRender({
+ initial_state,
+ location: ctx.request.url,
+ store,
+ offchain,
+ ErrorPage,
+ tarantool: Tarantool.instance(),
+ userPreferences,
+ });
// Assets name are found in `webpack-stats` file
- const assets_filename = ROOT + (process.env.NODE_ENV === 'production' ? '/tmp/webpack-stats-prod.json' : '/tmp/webpack-stats-dev.json');
+ const assets_filename =
+ ROOT +
+ (process.env.NODE_ENV === 'production'
+ ? '/tmp/webpack-stats-prod.json'
+ : '/tmp/webpack-stats-dev.json');
const assets = require(assets_filename);
// Don't cache assets name on dev
@@ -123,9 +169,10 @@ async function appRender(ctx) {
delete require.cache[require.resolve(assets_filename)];
}
- const props = {body, assets, title, meta};
+ const props = { body, assets, title, meta };
ctx.status = statusCode;
- ctx.body = '' + renderToString( );
+ ctx.body =
+ '' + renderToString( );
} catch (err) {
// Render 500 error page from server
const { error, redirect } = err;
@@ -141,5 +188,5 @@ async function appRender(ctx) {
}
}
-appRender.dbStatus = {ok: true};
+appRender.dbStatus = { ok: true };
module.exports = appRender;
diff --git a/src/server/hardwarestats.js b/src/server/hardwarestats.js
index b1e81c82e6a42ccb1f3dfd347e7da000ba217e92..2e45ba1674c5c06019bbee7a360faeb5ec175602 100644
--- a/src/server/hardwarestats.js
+++ b/src/server/hardwarestats.js
@@ -14,43 +14,42 @@ function handleError(err) {
function startPromise() {
return new Promise(function(resolve, reject) {
resolve();
- });
+ });
}
function getCpuUsage() {
- return new Promise(function(resolve, reject) {
- cpuStat.usagePercent(function(err, percent, seconds) {
- if (err)
- return err;
- stats.cpuPercent = percent;
- resolve();
- });
- });
+ return new Promise(function(resolve, reject) {
+ cpuStat.usagePercent(function(err, percent, seconds) {
+ if (err) return err;
+ stats.cpuPercent = percent;
+ resolve();
+ });
+ });
}
function getMemoryUsage() {
- return new Promise(function(resolve, reject) {
- stats.memoryStatsInGiB = memStat.allStats('GiB');
- resolve();
- });
+ return new Promise(function(resolve, reject) {
+ stats.memoryStatsInGiB = memStat.allStats('GiB');
+ resolve();
+ });
}
function getDiskUsage() {
- return new Promise(function(resolve, reject) {
- stats.diskStats = diskStat.raw();
- resolve();
- });
+ return new Promise(function(resolve, reject) {
+ stats.diskStats = diskStat.raw();
+ resolve();
+ });
}
function hardwareStats() {
- return startPromise()
- .then(getCpuUsage, handleError)
- .then(getMemoryUsage, handleError)
- .then(getDiskUsage, handleError)
- .then(function () {
- console.log(JSON.stringify(stats));
- }, handleError)
- .then(null, function(err) {
- console.log('error getting hardware stats: ' + err);
- });
-}
\ No newline at end of file
+ return startPromise()
+ .then(getCpuUsage, handleError)
+ .then(getMemoryUsage, handleError)
+ .then(getDiskUsage, handleError)
+ .then(function() {
+ console.log(JSON.stringify(stats));
+ }, handleError)
+ .then(null, function(err) {
+ console.log('error getting hardware stats: ' + err);
+ });
+}
diff --git a/src/server/index.js b/src/server/index.js
index b619f3d56df3dd925d2a4b68a5c5037ffe804c15..948ca9bfe7b76caefba1b66f65565eccb46e3001 100644
--- a/src/server/index.js
+++ b/src/server/index.js
@@ -1,6 +1,6 @@
import config from 'config';
-import * as steem from 'steem';
+import * as steem from '@steemit/steem-js';
const path = require('path');
const ROOT = path.join(__dirname, '../..');
@@ -9,7 +9,7 @@ const ROOT = path.join(__dirname, '../..');
// it will avoid `../../../../../` require strings
// use Object.assign to bypass transform-inline-environment-variables-babel-plugin (process.env.NODE_PATH= will not work)
-Object.assign(process.env, {NODE_PATH: path.resolve(__dirname, '..')});
+Object.assign(process.env, { NODE_PATH: path.resolve(__dirname, '..') });
require('module').Module._initPaths();
@@ -17,9 +17,10 @@ require('module').Module._initPaths();
// require('utils/intl-polyfill')(require('./config/init').locales);
global.$STM_Config = {
- fb_app: config.get('grant.facebook.key'),
+ fb_app: config.get('facebook_app_id'),
steemd_connection_client: config.get('steemd_connection_client'),
steemd_connection_server: config.get('steemd_connection_server'),
+ steemd_use_appbase: config.get('steemd_use_appbase'),
chain_id: config.get('chain_id'),
address_prefix: config.get('address_prefix'),
img_proxy_prefix: config.get('img_proxy_prefix'),
@@ -30,29 +31,30 @@ global.$STM_Config = {
upload_image: config.get('upload_image'),
site_domain: config.get('site_domain'),
facebook_app_id: config.get('facebook_app_id'),
- google_analytics_id: config.get('google_analytics_id')
+ google_analytics_id: config.get('google_analytics_id'),
};
const WebpackIsomorphicTools = require('webpack-isomorphic-tools');
-const WebpackIsomorphicToolsConfig = require(
- '../../webpack/webpack-isotools-config'
-);
+const WebpackIsomorphicToolsConfig = require('../../webpack/webpack-isotools-config');
global.webpackIsomorphicTools = new WebpackIsomorphicTools(
WebpackIsomorphicToolsConfig
);
global.webpackIsomorphicTools.server(ROOT, () => {
- steem.api.setOptions({ url: config.steemd_connection_server });
- steem.config.set('address_prefix', config.get('address_prefix'));
- steem.config.set('chain_id', config.get('chain_id'));
-
- // const CliWalletClient = require('shared/api_client/CliWalletClient').default;
- // if (process.env.NODE_ENV === 'production') connect_promises.push(CliWalletClient.instance().connect_promise());
- try {
- require('./server');
- } catch (error) {
- console.error(error);
- process.exit(1);
- }
+ steem.api.setOptions({
+ url: config.steemd_connection_client,
+ useAppbaseApi: !!config.steemd_use_appbase,
+ });
+ steem.config.set('address_prefix', config.get('address_prefix'));
+ steem.config.set('chain_id', config.get('chain_id'));
+
+ // const CliWalletClient = require('shared/api_client/CliWalletClient').default;
+ // if (process.env.NODE_ENV === 'production') connect_promises.push(CliWalletClient.instance().connect_promise());
+ try {
+ require('./server');
+ } catch (error) {
+ console.error(error);
+ process.exit(1);
+ }
});
diff --git a/src/server/json/post_json.jsx b/src/server/json/post_json.jsx
index c9cc82e5e0cfc7e5bc2479a36e14f396812ec0c2..5d605abb3bdb2a5d08a3e47c7baad7e858e080e9 100644
--- a/src/server/json/post_json.jsx
+++ b/src/server/json/post_json.jsx
@@ -1,32 +1,32 @@
import koa_router from 'koa-router';
import React from 'react';
-import {routeRegex} from "app/ResolveRoute";
-import {api} from 'steem'
+import { routeRegex } from 'app/ResolveRoute';
+import { api } from '@steemit/steem-js';
export default function usePostJson(app) {
const router = koa_router();
app.use(router.routes());
- router.get(routeRegex.PostJson, function *() {
+ router.get(routeRegex.PostJson, function*() {
// validate and build post details in JSON
const author = this.url.match(/(\@[\w\d\.-]+)/)[0].replace('@', '');
const permalink = this.url.match(/(\@[\w\d\.-]+)\/?([\w\d-]+)/)[2];
- let status = "";
+ let status = '';
let post = yield api.getContentAsync(author, permalink);
if (post.author) {
- status = "200";
+ status = '200';
// try parse for post metadata
try {
post.json_metadata = JSON.parse(post.json_metadata);
- } catch(e) {
- post.json_metadata = "";
+ } catch (e) {
+ post.json_metadata = '';
}
} else {
- post = "No post found";
- status = "404";
+ post = 'No post found';
+ status = '404';
}
// return response and status code
- this.body = {post, status};
+ this.body = { post, status };
});
}
diff --git a/src/server/json/user_json.jsx b/src/server/json/user_json.jsx
index a296e535b26121d94ec18e422d525e939f329f93..1d57e555aaeb4ea5b48f08845a33391f17ea0dad 100644
--- a/src/server/json/user_json.jsx
+++ b/src/server/json/user_json.jsx
@@ -1,18 +1,20 @@
import koa_router from 'koa-router';
import React from 'react';
-import {routeRegex} from "app/ResolveRoute";
-import {api} from 'steem'
+import { routeRegex } from 'app/ResolveRoute';
+import { api } from '@steemit/steem-js';
export default function useUserJson(app) {
const router = koa_router();
app.use(router.routes());
- router.get(routeRegex.UserJson, function *() {
+ router.get(routeRegex.UserJson, function*() {
// validate and build user details in JSON
const segments = this.url.split('/');
- const user_name = segments[1].match(routeRegex.UserNameJson)[0].replace('@', '');
- let user = "";
- let status = "";
+ const user_name = segments[1]
+ .match(routeRegex.UserNameJson)[0]
+ .replace('@', '');
+ let user = '';
+ let status = '';
const [chainAccount] = yield api.getAccountsAsync([user_name]);
@@ -21,14 +23,14 @@ export default function useUserJson(app) {
try {
user.json_metadata = JSON.parse(user.json_metadata);
} catch (e) {
- user.json_metadata = "";
+ user.json_metadata = '';
}
- status = "200";
+ status = '200';
} else {
- user = "No account found";
- status = "404";
+ user = 'No account found';
+ status = '404';
}
// return response and status code
- this.body = {user, status};
+ this.body = { user, status };
});
}
diff --git a/src/server/prod_logger.js b/src/server/prod_logger.js
index 28003d8af33f9a0beb339f170f5a52441610889d..d6a1327c4c2baf24494bec73311c64c27071111f 100644
--- a/src/server/prod_logger.js
+++ b/src/server/prod_logger.js
@@ -4,14 +4,22 @@ var bytes = require('bytes');
module.exports = prod_logger;
function prod_logger() {
- return function *logger(next) {
+ return function* logger(next) {
// request
- var start = new Date;
- var asset = this.originalUrl.indexOf('/assets/') === 0
- || this.originalUrl.indexOf('/images/') === 0
- || this.originalUrl.indexOf('/favicon.ico') === 0;
+ var start = new Date();
+ var asset =
+ this.originalUrl.indexOf('/assets/') === 0 ||
+ this.originalUrl.indexOf('/images/') === 0 ||
+ this.originalUrl.indexOf('/favicon.ico') === 0;
if (!asset)
- console.log(' <-- ' + this.method + ' ' + this.originalUrl + ' ' + (this.session.uid || ''));
+ console.log(
+ ' <-- ' +
+ this.method +
+ ' ' +
+ this.originalUrl +
+ ' ' +
+ (this.session.uid || '')
+ );
try {
yield next;
} catch (err) {
@@ -20,13 +28,11 @@ function prod_logger() {
}
var length = this.response.length;
log(this, start, length, null, asset);
- }
+ };
}
function log(ctx, start, len, err, asset) {
- var status = err
- ? (err.status || 500)
- : (ctx.status || 404);
+ var status = err ? err.status || 500 : ctx.status || 404;
var length;
if (~[204, 205, 304].indexOf(status)) {
@@ -39,19 +45,20 @@ function log(ctx, start, len, err, asset) {
var upstream = err ? 'xxx' : '-->';
- if (!asset || err || ctx.status > 400) console.log(' ' + upstream + ' %s %s %s %s %s %s',
- ctx.method,
- ctx.originalUrl,
- status,
- time(start),
- length,
- ctx.session.uid || '');
+ if (!asset || err || ctx.status > 400)
+ console.log(
+ ' ' + upstream + ' %s %s %s %s %s %s',
+ ctx.method,
+ ctx.originalUrl,
+ status,
+ time(start),
+ length,
+ ctx.session.uid || ''
+ );
}
function time(start) {
- var delta = new Date - start;
- delta = delta < 10000
- ? delta + 'ms'
- : Math.round(delta / 1000) + 's';
+ var delta = new Date() - start;
+ delta = delta < 10000 ? delta + 'ms' : Math.round(delta / 1000) + 's';
return humanize(delta);
}
diff --git a/src/server/record_web_event.js b/src/server/record_web_event.js
index 67a538b19e5ca456f165310b0fc433a2a807310a..012445aad2162bbeece00351522825e004ad0ac3 100644
--- a/src/server/record_web_event.js
+++ b/src/server/record_web_event.js
@@ -1,4 +1,4 @@
-import {WebEvent, esc} from 'db/models';
+import { WebEvent, esc } from 'db/models';
export default function recordWebEvent(ctx, event_type, value) {
if (ctx.state.isBot) return;
@@ -6,10 +6,13 @@ export default function recordWebEvent(ctx, event_type, value) {
const r = ctx.req;
let new_session = true;
if (ctx.last_visit) {
- new_session = ((new Date()).getTime() / 1000 - ctx.last_visit) > 1800;
+ new_session = new Date().getTime() / 1000 - ctx.last_visit > 1800;
}
- const remote_address = r.headers['x-forwarded-for'] || r.connection.remoteAddress;
- const ip_match = remote_address ? remote_address.match(/(\d+\.\d+\.\d+\.\d+)/) : null;
+ const remote_address =
+ r.headers['x-forwarded-for'] || r.connection.remoteAddress;
+ const ip_match = remote_address
+ ? remote_address.match(/(\d+\.\d+\.\d+\.\d+)/)
+ : null;
const d = {
event_type: esc(event_type, 1000),
user_id: s.user,
@@ -24,9 +27,9 @@ export default function recordWebEvent(ctx, event_type, value) {
status: ctx.status,
channel: esc(s.ch, 64),
referrer: esc(s.r, 64),
- campaign: esc(s.cn, 64)
+ campaign: esc(s.cn, 64),
};
- WebEvent.create(d, {logging: false}).catch(error => {
- console.error('!!! Can\'t create web event record', error);
+ WebEvent.create(d, { logging: false }).catch(error => {
+ console.error("!!! Can't create web event record", error);
});
}
diff --git a/src/server/redirects.js b/src/server/redirects.js
index dc8253594a484d4d67e3364fd95a95e0e71f8fdf..21420fcd02e25767eea75b02f2349c4bea9285fb 100644
--- a/src/server/redirects.js
+++ b/src/server/redirects.js
@@ -2,7 +2,8 @@ import koa_router from 'koa-router';
const redirects = [
// example: [/\/about(\d+)-(.+)/, '/about?$0:$1', 302],
- [/^\/recent\/?$/, '/created']
+ [/^\/recent\/?$/, '/created'],
+ [/^\/pick_account.*/, 'https://signup.steemit.com'],
];
export default function useRedirects(app) {
@@ -11,9 +12,14 @@ export default function useRedirects(app) {
app.use(router.routes());
redirects.forEach(r => {
- router.get(r[0], function *() {
- const dest = Object.keys(this.params).reduce((value, key) => value.replace('$' + key, this.params[key]), r[1]);
- console.log(`server redirect: [${r[0]}] ${this.request.url} -> ${dest}`);
+ router.get(r[0], function*() {
+ const dest = Object.keys(this.params).reduce(
+ (value, key) => value.replace('$' + key, this.params[key]),
+ r[1]
+ );
+ console.log(
+ `server redirect: [${r[0]}] ${this.request.url} -> ${dest}`
+ );
this.status = r[2] || 301;
this.redirect(dest);
});
diff --git a/src/server/requesttimings.js b/src/server/requesttimings.js
index 671cabf7635cd002215c0c0dd605f4f8e39e1902..0cf874608a4fdf6e5e7ce8b18e1af30e7003ea28 100644
--- a/src/server/requesttimings.js
+++ b/src/server/requesttimings.js
@@ -1,16 +1,21 @@
function requestTime(numProcesses) {
let number_of_requests = 0;
- return function *(next) {
+ return function*(next) {
number_of_requests += 1;
const start = Date.now();
yield* next;
const delta = Math.ceil(Date.now() - start);
// log all requests that take longer than 150ms
if (delta > 150)
- console.log(`Request took too long! ${delta}ms: ${this.request.method} ${this.request.path}. Number of parallel requests: ${number_of_requests}, number of processes: ${numProcesses}`);
+ console.log(
+ `Request took too long! ${delta}ms: ${this.request.method} ${
+ this.request.path
+ }. Number of parallel requests: ${
+ number_of_requests
+ }, number of processes: ${numProcesses}`
+ );
number_of_requests -= 1;
- }
+ };
}
module.exports = requestTime;
-
diff --git a/src/server/sendEmail.js b/src/server/sendEmail.js
index 2c83c5dcff292bfe3297c2ea93acb4b8065b7452..9e8295bd306b5bc3f120e1972eae3df63cf40fbf 100644
--- a/src/server/sendEmail.js
+++ b/src/server/sendEmail.js
@@ -5,7 +5,11 @@ const sg = sendgrid(config.get('sendgrid.key'));
export default function sendEmail(template, to, params, from = null) {
if (process.env.NODE_ENV !== 'production') {
- console.log(`mail: to <${to}>, from <${from}>, template ${template} (not sent due to not production env)`);
+ console.log(
+ `mail: to <${to}>, from <${from}>, template ${
+ template
+ } (not sent due to not production env)`
+ );
return;
}
const tmpl_id = config.get('sendgrid.templates')[template];
@@ -17,18 +21,27 @@ export default function sendEmail(template, to, params, from = null) {
body: {
template_id: tmpl_id,
personalizations: [
- {to: [{email: to}],
- substitutions: params},
+ {
+ to: [{ email: to }],
+ substitutions: params,
+ },
],
- from: {email: from || config.get('sendgrid.from')}
- }
+ from: { email: from || config.get('sendgrid.from') },
+ },
});
- sg.API(request)
- .then(response => {
- console.log(`sent '${template}' email to '${to}'`, response.statusCode);
- })
- .catch(error => {
- console.error(`failed to send '${template}' email to '${to}'`, error);
- });
+ sg
+ .API(request)
+ .then(response => {
+ console.log(
+ `sent '${template}' email to '${to}'`,
+ response.statusCode
+ );
+ })
+ .catch(error => {
+ console.error(
+ `failed to send '${template}' email to '${to}'`,
+ error
+ );
+ });
}
diff --git a/src/server/server-error.jsx b/src/server/server-error.jsx
index 5f0eff4c2441efacc8064634045466dfc5edc6b1..3253b67b3ce2b3f53fd07bc0f8a7b5798b33146c 100644
--- a/src/server/server-error.jsx
+++ b/src/server/server-error.jsx
@@ -1,20 +1,31 @@
import React, { Component } from 'react';
class ServerError extends Component {
-
render() {
return (
-
+
-
+
Sorry.
Looks like something went wrong on our end.
-
Head back to Steemit homepage.
+
+ Head back to Steemit homepage.
+
);
}
-
}
export default ServerError;
diff --git a/src/server/server-html.jsx b/src/server/server-html.jsx
index 1699ca56484bb0ec25f5fe3740cf2c9bef7810fc..54f572b87faa23f36ab35e52b7c1155faeec8b6f 100644
--- a/src/server/server-html.jsx
+++ b/src/server/server-html.jsx
@@ -4,58 +4,180 @@ export default function ServerHTML({ body, assets, locale, title, meta }) {
let page_title = title;
return (
-
-
-
- {
- meta && meta.map(m => {
- if (m.title) {
- page_title = m.title;
+
+
+
+ {meta &&
+ meta.map(m => {
+ if (m.title) {
+ page_title = m.title;
+ return null;
+ }
+ if (m.canonical)
+ return (
+
+ );
+ if (m.name && m.content)
+ return (
+
+ );
+ if (m.property && m.content)
+ return (
+
+ );
+ if (m.name && m.content)
+ return (
+
+ );
return null;
- }
- if (m.canonical)
- return
;
- if (m.name && m.content)
- return
;
- if (m.property && m.content)
- return
;
- if (m.name && m.content)
- return
;
- return null;
- })
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { assets.style.map((href, idx) =>
-
) }
-
{page_title}
-
-
-
- {assets.script.map((href, idx) => ) }
-
+ })}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {assets.style.map((href, idx) => (
+
+ ))}
+
{page_title}
+
+
+
+ {assets.script.map((href, idx) => (
+
+ ))}
+
);
}
diff --git a/src/server/server.js b/src/server/server.js
index 35729152c5e7e5306b7c010a1a0099d0e0d2013c..5cde9aff4c1b4b3d422e98d514e5464e2b8f0cac 100644
--- a/src/server/server.js
+++ b/src/server/server.js
@@ -12,10 +12,8 @@ import prod_logger from './prod_logger';
import favicon from 'koa-favicon';
import staticCache from 'koa-static-cache';
import useRedirects from './redirects';
-import useOauthLogin from './api/oauth';
import useGeneralApi from './api/general';
import useAccountRecoveryApi from './api/account_recovery';
-import useNotificationsApi from './api/notifications';
import useEnterAndConfirmEmailPages from './sign_up_pages/enter_confirm_email';
import useEnterAndConfirmMobilePages from './sign_up_pages/enter_confirm_mobile';
import useUserJson from './json/user_json';
@@ -25,17 +23,14 @@ import session from '@steem/crypto-session';
import csrf from 'koa-csrf';
import flash from 'koa-flash';
import minimist from 'minimist';
-import Grant from 'grant-koa';
import config from 'config';
import { routeRegex } from 'app/ResolveRoute';
import secureRandom from 'secure-random';
import userIllegalContent from 'app/utils/userIllegalContent';
import koaLocale from 'koa-locale';
-if(cluster.isMaster)
- console.log('application server starting, please wait.');
+if (cluster.isMaster) console.log('application server starting, please wait.');
-const grant = new Grant(config.grant);
// import uploadImage from 'server/upload-image' //medium-editor
const app = new Koa();
@@ -56,31 +51,25 @@ const crypto_key = config.get('server_session_secret');
session(app, {
maxAge: 1000 * 3600 * 24 * 60,
crypto_key,
- key: config.get('session_cookie_key')
+ key: config.get('session_cookie_key'),
});
csrf(app);
-app.use(mount(grant));
app.use(flash({ key: 'flash' }));
koaLocale(app);
function convertEntriesToArrays(obj) {
return Object.keys(obj).reduce((result, key) => {
- result[key] = obj[key].split(/\s+/);
- return result;
-}, {});
+ result[key] = obj[key].split(/\s+/);
+ return result;
+ }, {});
}
-const service_worker_js_content = fs
- .readFileSync(path.join(__dirname, './service-worker.js'))
- .toString();
-
// some redirects and health status
-app.use(function* (next) {
-
+app.use(function*(next) {
if (this.method === 'GET' && this.url === '/.well-known/healthcheck.json') {
this.status = 200;
- this.body = {status: 'ok'};
+ this.body = { status: 'ok' };
return;
}
@@ -94,15 +83,15 @@ app.use(function* (next) {
if (
this.method === 'GET' &&
(routeRegex.UserProfile1.test(this.url) ||
- routeRegex.PostNoCategory.test(this.url) || routeRegex.Post.test(this.url)
- )
+ routeRegex.PostNoCategory.test(this.url) ||
+ routeRegex.Post.test(this.url))
) {
const p = this.originalUrl.toLowerCase();
- let userCheck = "";
+ let userCheck = '';
if (routeRegex.Post.test(this.url)) {
- userCheck = p.split("/")[2].slice(1);
+ userCheck = p.split('/')[2].slice(1);
} else {
- userCheck = p.split("/")[1].slice(1);
+ userCheck = p.split('/')[1].slice(1);
}
if (userIllegalContent.includes(userCheck)) {
console.log('Illegal content user found blocked', userCheck);
@@ -133,10 +122,10 @@ app.use(function* (next) {
// remember ch, cn, r url params in the session and remove them from url
if (this.method === 'GET' && /\?[^\w]*(ch=|cn=|r=)/.test(this.url)) {
let redir = this.url.replace(/((ch|cn|r)=[^&]+)/gi, r => {
- const p = r.split('=');
- if (p.length === 2) this.session[p[0]] = p[1];
- return '';
- });
+ const p = r.split('=');
+ if (p.length === 2) this.session[p[0]] = p[1];
+ return '';
+ });
redir = redir.replace(/&&&?/, '');
redir = redir.replace(/\?&?$/, '');
console.log(`server redirect ${this.url} -> ${redir}`);
@@ -161,7 +150,11 @@ if (env === 'production') {
app.use(koa_logger());
}
-app.use(helmet());
+app.use(
+ helmet({
+ hsts: false,
+ })
+);
app.use(
mount(
@@ -178,24 +171,11 @@ app.use(
})
);
-app.use(
- mount('/service-worker.js', function*() {
- this.set('Cache-Control', 'public, max-age=7200000');
- this.type = 'application/javascript';
- // TODO: use APP_URL from client_config.js
- // actually use a config value for it
- this.body = service_worker_js_content.replace(
- /\{DEFAULT_URL\}/i,
- 'https://' + this.request.header.host
- );
- })
-);
-
// set user's uid - used to identify users in logs and some other places
// FIXME SECURITY PRIVACY cycle this uid after a period of time
app.use(function*(next) {
const last_visit = this.session.last_visit;
- this.session.last_visit = new Date().getTime() / 1000 | 0;
+ this.session.last_visit = (new Date().getTime() / 1000) | 0;
const from_link = this.request.headers.referer;
if (!this.session.uid) {
this.session.uid = secureRandom.randomBuffer(13).toString('hex');
@@ -217,9 +197,7 @@ useUserJson(app);
usePostJson(app);
useAccountRecoveryApi(app);
-useOauthLogin(app);
useGeneralApi(app);
-useNotificationsApi(app);
// helmet wants some things as bools and some as lists, makes config difficult.
// our config uses strings, this splits them to lists on whitespace.
@@ -228,7 +206,7 @@ if (env === 'production') {
const helmetConfig = {
directives: convertEntriesToArrays(config.get('helmet.directives')),
reportOnly: config.get('helmet.reportOnly'),
- setAllHeaders: config.get('helmet.setAllHeaders')
+ setAllHeaders: config.get('helmet.setAllHeaders'),
};
helmetConfig.directives.reportUri = helmetConfig.directives.reportUri[0];
if (helmetConfig.directives.reportUri === '-') {
@@ -264,9 +242,9 @@ if (env === 'development') {
const proxyhost = 'http://0.0.0.0:' + webpack_dev_port;
console.log('proxying to webpack dev server at ' + proxyhost);
const proxy = require('koa-proxy')({
- host: proxyhost,
- map: filePath => 'assets/' + filePath
-});
+ host: proxyhost,
+ map: filePath => 'assets/' + filePath,
+ });
app.use(mount('/assets', proxy));
} else {
app.use(
@@ -285,7 +263,9 @@ if (env !== 'test') {
const bot = this.state.isBot;
if (bot) {
console.log(
- ` --> ${this.method} ${this.originalUrl} ${this.status} (BOT '${bot}')`
+ ` --> ${this.method} ${this.originalUrl} ${
+ this.status
+ } (BOT '${bot}')`
);
}
});
@@ -294,24 +274,25 @@ if (env !== 'test') {
const port = process.env.PORT ? parseInt(process.env.PORT) : 8080;
- if(env === 'production') {
- if(cluster.isMaster) {
- for(var i = 0; i < numProcesses; i++) {
+ if (env === 'production') {
+ if (cluster.isMaster) {
+ for (var i = 0; i < numProcesses; i++) {
cluster.fork();
}
// if a worker dies replace it so application keeps running
- cluster.on('exit', function (worker) {
- console.log('error: worker %d died, starting a new one', worker.id);
+ cluster.on('exit', function(worker) {
+ console.log(
+ 'error: worker %d died, starting a new one',
+ worker.id
+ );
cluster.fork();
});
- }
- else {
+ } else {
app.listen(port);
if (process.send) process.send('online');
console.log(`Worker process started for port ${port}`);
}
- }
- else {
+ } else {
// spawn a single thread if not running in production mode
app.listen(port);
if (process.send) process.send('online');
@@ -321,7 +302,7 @@ if (env !== 'test') {
// set PERFORMANCE_TRACING to the number of seconds desired for
// logging hardware stats to the console
-if(process.env.PERFORMANCE_TRACING)
- setInterval(hardwareStats, (1000*process.env.PERFORMANCE_TRACING));
+if (process.env.PERFORMANCE_TRACING)
+ setInterval(hardwareStats, 1000 * process.env.PERFORMANCE_TRACING);
module.exports = app;
diff --git a/src/server/server.test.js b/src/server/server.test.js
deleted file mode 100644
index c9f9ff195fa532b9afaff061dbece91bc207f7ba..0000000000000000000000000000000000000000
--- a/src/server/server.test.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*global describe, it, before, beforeEach, after, afterEach */
-
-require('co-mocha');
-import server from './server';
-import {agent} from 'co-supertest';
-import chai from 'chai';
-import dirtyChai from 'dirty-chai';
-const expect = chai.expect;
-const request = agent(server.listen());
-
-chai.use(dirtyChai);
-
-describe('/favicon.ico', function () {
-/* not maintained
- it('should return image', function *() {
- const res = yield request.get('/favicon.ico').end();
- expect(res.status).to.equal(200);
- expect(res.body).to.be.ok();
- expect(res.headers['content-type']).to.equal('image/x-icon');
- });
-*/
-});
diff --git a/src/server/service-worker.js b/src/server/service-worker.js
deleted file mode 100644
index 77e16d7401173a839d7d225f226d737fb09ba730..0000000000000000000000000000000000000000
--- a/src/server/service-worker.js
+++ /dev/null
@@ -1,30 +0,0 @@
-self.addEventListener('install', function(event) {
- event.waitUntil(self.skipWaiting());
-});
-self.addEventListener('activate', function(event) {
- event.waitUntil(self.clients.claim());
-});
-var clickUrl;
-self.addEventListener('push', function(event) {
- var payload = JSON.parse(event.data.text());
- clickUrl = payload.url;
- event.waitUntil(
- self.registration.showNotification(payload.title, {
- body: payload.body,
- icon: payload.icon
- })
- );
-});
-self.addEventListener('notificationclick', function(event) {
- event.waitUntil(
- self.clients.matchAll().then(function(clientList) {
- if (clientList.length > 0) {
- if (clickUrl && 'navigate' in clientList[0]) {
- clientList[0].navigate(clickUrl);
- }
- return clientList[0].focus();
- }
- return self.clients.openWindow(clickUrl || '{DEFAULT_URL}');
- })
- );
-});
diff --git a/src/server/sign_up_pages/enter_confirm_email.jsx b/src/server/sign_up_pages/enter_confirm_email.jsx
index ffe2b623a675c36df18b0937734789e27104ace0..bb23198ff7cf3c4c3883a4bde0a08ee1fae892b4 100644
--- a/src/server/sign_up_pages/enter_confirm_email.jsx
+++ b/src/server/sign_up_pages/enter_confirm_email.jsx
@@ -1,104 +1,135 @@
-import koa_router from "koa-router";
-import koa_body from "koa-body";
-import request from "co-request";
-import React from "react";
-import { renderToString } from "react-dom/server";
-import models from "db/models";
-import ServerHTML from "../server-html";
-import sendEmail from "../sendEmail";
-import { getRemoteIp, checkCSRF } from "server/utils/misc";
-import config from "config";
-import MiniHeader from "app/components/modules/MiniHeader";
-import secureRandom from "secure-random";
-import Mixpanel from "mixpanel";
-import Progress from "react-foundation-components/lib/global/progress-bar";
-import {api} from 'steem';
+import koa_router from 'koa-router';
+import koa_body from 'koa-body';
+import request from 'co-request';
+import React from 'react';
+import { renderToString } from 'react-dom/server';
+import models from 'db/models';
+import { PARAM_VIEW_MODE, VIEW_MODE_WHISTLE } from 'shared/constants';
+import { addToParams, makeParams } from 'app/utils/Links';
+import ServerHTML from '../server-html';
+import sendEmail from '../sendEmail';
+import { getRemoteIp, checkCSRF } from 'server/utils/misc';
+import config from 'config';
+import MiniHeader from 'app/components/modules/MiniHeader';
+import secureRandom from 'secure-random';
+import Mixpanel from 'mixpanel';
+import Progress from 'react-foundation-components/lib/global/progress-bar';
+import { api } from '@steemit/steem-js';
const path = require('path');
const ROOT = path.join(__dirname, '../../..');
// FIXME copy paste code, refactor mixpanel out
let mixpanel = null;
-if (config.has("mixpanel") && config.get("mixpanel")) {
- mixpanel = Mixpanel.init(config.get("mixpanel"));
+if (config.has('mixpanel') && config.get('mixpanel')) {
+ mixpanel = Mixpanel.init(config.get('mixpanel'));
}
-let assets_file = ROOT + "/tmp/webpack-stats-dev.json";
-if (process.env.NODE_ENV === "production") {
- assets_file = ROOT + "/tmp/webpack-stats-prod.json";
+let assets_file = ROOT + '/tmp/webpack-stats-dev.json';
+if (process.env.NODE_ENV === 'production') {
+ assets_file = ROOT + '/tmp/webpack-stats-prod.json';
}
const assets = Object.assign({}, require(assets_file), { script: [] });
-assets.script.push("https://www.google.com/recaptcha/api.js");
-assets.script.push("/enter_email/submit_form.js");
+assets.script.push('https://www.google.com/recaptcha/api.js');
+assets.script.push('/enter_email/submit_form.js');
function* confirmEmailHandler() {
- const confirmation_code = this.params && this.params.code
- ? this.params.code
- : this.request.body.code;
- console.log("-- /confirm_email -->", this.session.uid, this.session.user, confirmation_code);
+ const confirmation_code =
+ this.params && this.params.code
+ ? this.params.code
+ : this.request.body.code;
+ console.log(
+ '-- /confirm_email -->',
+ this.session.uid,
+ this.session.user,
+ confirmation_code
+ );
const eid = yield models.Identity.findOne({
- where: { confirmation_code, provider: "email"}
+ where: { confirmation_code, provider: 'email' },
});
if (!eid) {
- console.log("confirmation code not found", this.session.uid, this.session.user, confirmation_code);
+ console.log(
+ 'confirmation code not found',
+ this.session.uid,
+ this.session.user,
+ confirmation_code
+ );
this.status = 401;
- this.body = "confirmation code not found";
+ this.body = 'confirmation code not found';
return;
}
if (eid.email_verified) {
this.session.user = eid.user_id; // session recovery (user changed browsers)
- this.flash = { success: "Email has already been verified" };
- this.redirect("/approval?confirm_email=true");
+ this.flash = { success: 'Email has already been verified' };
+ this.redirect('/approval?confirm_email=true');
return;
}
const hours_ago = (Date.now() - eid.updated_at) / 1000.0 / 3600.0;
if (hours_ago > 24.0 * 10) {
eid.destroy();
this.status = 401;
- this.body = 'Confirmation code expired. Please
re-submit your email for verification.';
+ this.body =
+ 'Confirmation code expired. Please
re-submit your email for verification.';
return;
}
const number_of_created_accounts = yield models.sequelize.query(
`select count(*) as result from identities i join accounts a on a.user_id=i.user_id where i.provider='email' and i.email=:email and a.created=1 and a.ignored<>1`,
- { replacements: { email: eid.email }, type: models.sequelize.QueryTypes.SELECT }
+ {
+ replacements: { email: eid.email },
+ type: models.sequelize.QueryTypes.SELECT,
+ }
);
- if (number_of_created_accounts && number_of_created_accounts[0].result > 0) {
+ if (
+ number_of_created_accounts &&
+ number_of_created_accounts[0].result > 0
+ ) {
console.log(
- "-- /confirm_email email has already been used -->",
+ '-- /confirm_email email has already been used -->',
this.session.uid,
eid.email
);
- this.flash = {error: 'This email has already been used'};
+ this.flash = { error: 'This email has already been used' };
this.redirect('/pick_account');
return;
}
this.session.user = eid.user_id;
yield eid.update({
- verified: true
- });
- yield models.User.update({ email: eid.email}, {
- where: { id: eid.user_id }
- });
- yield models.User.update({ account_status: 'waiting'}, {
- where: { id: eid.user_id, account_status: 'onhold' }
+ verified: true,
});
+ yield models.User.update(
+ { email: eid.email },
+ {
+ where: { id: eid.user_id },
+ }
+ );
+ yield models.User.update(
+ { account_status: 'waiting' },
+ {
+ where: { id: eid.user_id, account_status: 'onhold' },
+ }
+ );
if (mixpanel)
- mixpanel.track("SignupStepConfirmEmail", { distinct_id: this.session.uid });
+ mixpanel.track('SignupStepConfirmEmail', {
+ distinct_id: this.session.uid,
+ });
const eid_phone = yield models.Identity.findOne({
- where: { user_id: eid.user_id, provider: "phone", verified: true}
+ where: { user_id: eid.user_id, provider: 'phone', verified: true },
});
if (eid_phone) {
// this.flash = { success: "Thanks for confirming your email!" };
- this.redirect("/approval?confirm_email=true");
+ this.redirect('/approval?confirm_email=true');
} else {
- this.flash = { success: "Thanks for confirming your email. Your phone needs to be confirmed before proceeding." };
- this.redirect("/enter_mobile");
+ this.flash = {
+ success:
+ 'Thanks for confirming your email. Your phone needs to be confirmed before proceeding.',
+ };
+ this.redirect('/enter_mobile');
}
// check if the phone is confirmed then redirect to create account - this is useful when we invite users and send them the link
@@ -118,94 +149,157 @@ export default function useEnterAndConfirmEmailPages(app) {
const router = koa_router();
app.use(router.routes());
const koaBody = koa_body();
- const rc_site_key = config.get("recaptcha.site_key");
+ const rc_site_key = config.get('recaptcha.site_key');
- router.get("/start/:code", function*() {
+ router.get('/start/:code', function*() {
const code = this.params.code;
- const eid = yield models.Identity.findOne({ attributes: ["id", "user_id", "verified"], where: { provider: "email", confirmation_code: code }});
- const user = eid ? yield models.User.findOne({
- attributes: ["id", "account_status"],
- where: { id: eid.user_id },
- include: [{model: models.Account, attributes: ['id', 'name', 'ignored', 'created']}],
- }) : null;
+ const eid = yield models.Identity.findOne({
+ attributes: ['id', 'user_id', 'verified'],
+ where: { provider: 'email', confirmation_code: code },
+ });
+ const user = eid
+ ? yield models.User.findOne({
+ attributes: ['id', 'account_status'],
+ where: { id: eid.user_id },
+ include: [
+ {
+ model: models.Account,
+ attributes: ['id', 'name', 'ignored', 'created'],
+ },
+ ],
+ })
+ : null;
// validate there is email identity and user record
if (eid && user) {
// set session based on confirmation code(user from diff device, etc)
this.session.user = user.id;
if (user.uid) this.session.uid = user.uid;
- console.log('-- checking incoming start request -->', this.session.uid, this.session.user);
+ console.log(
+ '-- checking incoming start request -->',
+ this.session.uid,
+ this.session.user
+ );
if (!eid.verified) {
yield eid.update({ verified: true });
}
- if (user.account_status === "approved") {
- console.log("-- approved account for -->", this.session.uid, this.session.user);
- this.redirect("/create_account");
- } else if (user.account_status === "created") {
+ if (user.account_status === 'approved') {
+ console.log(
+ '-- approved account for -->',
+ this.session.uid,
+ this.session.user
+ );
+ this.redirect('/create_account');
+ } else if (user.account_status === 'created') {
// check if account is really created onchain
let there_is_created_account = false;
for (const a of user.Accounts) {
- const check_account_res = yield api.getAccountsAsync([a.name]);
- const account_created = check_account_res && check_account_res.length > 0;
- if (account_created && !a.ignored) there_is_created_account = true;
+ const check_account_res = yield api.getAccountsAsync([
+ a.name,
+ ]);
+ const account_created =
+ check_account_res && check_account_res.length > 0;
+ if (account_created && !a.ignored)
+ there_is_created_account = true;
if (!account_created && a.created) {
- console.log("-- found ghost account -->", this.session.uid, this.session.user, a.name);
- a.update({created: false});
+ console.log(
+ '-- found ghost account -->',
+ this.session.uid,
+ this.session.user,
+ a.name
+ );
+ a.update({ created: false });
}
}
if (there_is_created_account) {
// user clicked expired link - already created account
- this.flash = {alert: "Your account has already been created."};
- this.redirect("/login.html");
+ this.flash = {
+ alert: 'Your account has already been created.',
+ };
+ this.redirect('/login.html');
} else {
- user.update({account_status: 'approved'});
- console.log("-- approved account (ghost) for -->", this.session.uid, this.session.user);
- this.redirect("/create_account");
+ user.update({ account_status: 'approved' });
+ console.log(
+ '-- approved account (ghost) for -->',
+ this.session.uid,
+ this.session.user
+ );
+ this.redirect('/create_account');
}
- } else if (user.account_status === "waiting") {
- this.flash = { error: "Your account has not been approved yet." };
- this.redirect("/");
+ } else if (user.account_status === 'waiting') {
+ this.flash = {
+ error: 'Your account has not been approved yet.',
+ };
+ this.redirect('/');
} else {
- this.flash = { error: "Issue with your sign up status." };
- this.redirect("/");
+ this.flash = { error: 'Issue with your sign up status.' };
+ this.redirect('/');
}
} else {
// no matching identity found redirect
- this.flash = { error: "This is not a valid sign up code. Please click the link in your welcome email." };
- this.redirect("/");
+ this.flash = {
+ error:
+ 'This is not a valid sign up code. Please click the link in your welcome email.',
+ };
+ this.redirect('/');
}
});
- router.get("/enter_email", function*() {
- console.log("-- /enter_email -->", this.session.uid, this.session.user, this.request.query.account);
- const picked_account_name = this.session.picked_account_name = this.request.query.account;
+ router.get('/enter_email', function*() {
+ console.log(
+ '-- /enter_email -->',
+ this.session.uid,
+ this.session.user,
+ this.request.query.account
+ );
+ const params = addToParams({}, this.request.query, PARAM_VIEW_MODE, [
+ VIEW_MODE_WHISTLE,
+ ]);
+ const viewMode = params[PARAM_VIEW_MODE] ? params[PARAM_VIEW_MODE] : '';
+ const picked_account_name = (this.session.picked_account_name = this.request.query.account);
if (!picked_account_name) {
- this.flash = { error: "Please select your account name" };
- this.redirect('/pick_account');
+ this.flash = { error: 'Please select your account name' };
+ this.redirect('/pick_account' + makeParams(params));
return;
}
// check for existing account
- const check_account_res = yield api.getAccountsAsync([picked_account_name]);
+ const check_account_res = yield api.getAccountsAsync([
+ picked_account_name,
+ ]);
if (check_account_res && check_account_res.length > 0) {
- this.flash = { error: `${picked_account_name} is already taken, please try another name` };
- this.redirect('/pick_account');
+ this.flash = {
+ error: `${
+ picked_account_name
+ } is already taken, please try another name`,
+ };
+ this.redirect('/pick_account' + makeParams(params));
return;
}
- let default_email = "";
+ let default_email = '';
if (this.request.query && this.request.query.email)
default_email = this.request.query.email;
const body = renderToString(
-
+ {viewMode !== VIEW_MODE_WHISTLE ?
: null}
-
);
- const props = { body, title: "Email Address", assets, meta: [] };
- this.body = "" +
- renderToString(
);
+ const props = { body, title: 'Email Address', assets, meta: [] };
+ this.body =
+ '' + renderToString(
);
if (mixpanel)
- mixpanel.track("SignupStepEmail", { distinct_id: this.session.uid });
+ mixpanel.track('SignupStepEmail', {
+ distinct_id: this.session.uid,
+ });
});
- router.post("/submit_email", koaBody, function*() {
+ router.post('/submit_email', koaBody, function*() {
if (!checkCSRF(this, this.request.body.csrf)) return;
+ const params = addToParams({}, this.request.query, PARAM_VIEW_MODE, [
+ VIEW_MODE_WHISTLE,
+ ]);
+ let { email, account } = this.request.body;
+ console.log(
+ '-- /submit_email -->',
+ this.session.uid,
+ email,
+ account,
+ this.request.query[PARAM_VIEW_MODE]
+ );
- let {email, account} = this.request.body;
- console.log('-- /submit_email -->', this.session.uid, email, account);
if (!email) {
- this.flash = { error: "Please provide an email address" };
- this.redirect(`/enter_email?account=${account}`);
+ this.flash = { error: 'Please provide an email address' };
+ this.redirect(
+ `/enter_email?account=${account}` + makeParams(params, '&')
+ );
return;
}
- email = email.trim().toLowerCase();
- account = account.trim().toLowerCase();
+ email = params.email = email.trim().toLowerCase();
+ account = params.account = account.trim().toLowerCase();
//recaptcha
if (config.get('recaptcha.site_key')) {
if (!(yield checkRecaptcha(this))) {
console.log(
- "-- /submit_email captcha verification failed -->",
+ '-- /submit_email captcha verification failed -->',
this.session.uid,
email,
this.req.connection.remoteAddress
);
this.flash = {
- error: "Failed captcha verification, please try again"
+ error: 'Failed captcha verification, please try again',
};
- this.redirect(`/enter_email?email=${email}&account=${account}`);
+ this.redirect(`/enter_email` + makeParams(params));
return;
}
}
@@ -286,12 +395,12 @@ export default function useEnterAndConfirmEmailPages(app) {
if (!parsed_email || parsed_email.length < 2) {
console.log(
- "-- /submit_email not valid email -->",
+ '-- /submit_email not valid email -->',
this.session.uid,
email
);
- this.flash = { error: "Not valid email address" };
- this.redirect(`/enter_email?email=${email}&account=${account}`);
+ this.flash = { error: 'Not valid email address' };
+ this.redirect(`/enter_email` + makeParams(params));
return;
}
@@ -302,78 +411,91 @@ export default function useEnterAndConfirmEmailPages(app) {
const user = yield models.User.create({
uid: this.session.uid,
remote_ip: getRemoteIp(this.request.req),
- sign_up_meta: JSON.stringify({last_step: 2}),
- account_status: 'waiting'
+ sign_up_meta: JSON.stringify({ last_step: 2 }),
+ account_status: 'waiting',
});
this.session.user = user.id;
- console.log('-- /submit_email created new user -->', old_uid, this.session.uid, user.id);
+ console.log(
+ '-- /submit_email created new user -->',
+ old_uid,
+ this.session.uid,
+ user.id
+ );
yield models.UserAttribute.create({
user_id: user.id,
value: this.session.r,
- type_of: 'referer'
+ type_of: 'referer',
});
- const confirmation_code = secureRandom.randomBuffer(13).toString("hex");
+ const confirmation_code = secureRandom
+ .randomBuffer(13)
+ .toString('hex');
// create identity
yield models.Identity.create({
user_id: user.id,
provider: 'email',
verified: false,
email,
- confirmation_code
+ confirmation_code,
});
console.log(
- "-- /submit_email ->",
+ '-- /submit_email ->',
this.session.uid,
this.session.user,
email,
confirmation_code
);
- sendEmail("confirm_email", email, { confirmation_code });
+ sendEmail('confirm_email', email, { confirmation_code });
if (account) {
const existing_account = yield models.Account.findOne({
attributes: ['id'],
- where: {user_id: user.id, name: account},
- order: 'id DESC'
+ where: { user_id: user.id, name: account },
+ order: 'id DESC',
});
if (!existing_account) {
yield models.Account.create({
user_id: user.id,
name: account,
- remote_ip: getRemoteIp(this.request.req)
+ remote_ip: getRemoteIp(this.request.req),
});
}
}
} catch (error) {
- this.flash = {error: 'Internal Server Error'};
- this.redirect(`/enter_email?email=${email}&account=${account}`);
- console.error('Error in /submit_email :', this.session.uid, error.toString());
+ this.flash = { error: 'Internal Server Error' };
+ this.redirect('/enter_email' + +makeParams(params));
+ console.error(
+ 'Error in /submit_email :',
+ this.session.uid,
+ error.toString()
+ );
}
// redirect to phone verification
- this.redirect("/enter_mobile");
+ this.redirect('/enter_mobile' + makeParams(params));
});
- router.get("/confirm_email/:code", confirmEmailHandler);
- router.post("/confirm_email", koaBody, confirmEmailHandler);
- router.get("/enter_email/submit_form.js", function*() {
+ router.get('/confirm_email/:code', confirmEmailHandler);
+ router.post('/confirm_email', koaBody, confirmEmailHandler);
+ router.get('/enter_email/submit_form.js', function*() {
this.type = 'application/javascript';
- this.body = "function submit_email_form(){document.getElementById('submit_email').submit()}";
+ this.body =
+ "function submit_email_form(){document.getElementById('submit_email').submit()}";
});
}
function* checkRecaptcha(ctx) {
- if (process.env.NODE_ENV !== "production") return true;
- const recaptcha = ctx.request.body["g-recaptcha-response"];
- const verificationUrl = "https://www.google.com/recaptcha/api/siteverify?secret=" +
- config.get("recaptcha.secret_key") +
- "&response=" +
+ if (process.env.NODE_ENV !== 'production') return true;
+ const recaptcha = ctx.request.body['g-recaptcha-response'];
+ const verificationUrl =
+ 'https://www.google.com/recaptcha/api/siteverify?secret=' +
+ config.get('recaptcha.secret_key') +
+ '&response=' +
recaptcha +
- "&remoteip=" +
+ '&remoteip=' +
ctx.req.connection.remoteAddress;
let captcha_failed;
try {
@@ -383,7 +505,7 @@ function* checkRecaptcha(ctx) {
} catch (e) {
captcha_failed = true;
console.error(
- "-- /submit_email recaptcha request failed -->",
+ '-- /submit_email recaptcha request failed -->',
verificationUrl,
e
);
diff --git a/src/server/sign_up_pages/enter_confirm_mobile.jsx b/src/server/sign_up_pages/enter_confirm_mobile.jsx
index d52aea6e5feb3d976ec6866c21dc1f25c526262e..3ed2ec31be65333383f9974eee44a879977fceba 100644
--- a/src/server/sign_up_pages/enter_confirm_mobile.jsx
+++ b/src/server/sign_up_pages/enter_confirm_mobile.jsx
@@ -1,17 +1,19 @@
-import koa_router from "koa-router";
-import koa_body from "koa-body";
-import React from "react";
-import { renderToString } from "react-dom/server";
-import models from "db/models";
-import ServerHTML from "server/server-html";
+import koa_router from 'koa-router';
+import koa_body from 'koa-body';
+import React from 'react';
+import { renderToString } from 'react-dom/server';
+import models from 'db/models';
+import { PARAM_VIEW_MODE, VIEW_MODE_WHISTLE } from 'shared/constants';
+import { addToParams, makeParams } from 'app/utils/Links';
+import ServerHTML from 'server/server-html';
// import twilioVerify from "server/utils/twilio";
-import teleSignVerify from "server/utils/teleSign";
-import CountryCode from "app/components/elements/CountryCode";
-import { getRemoteIp, checkCSRF } from "server/utils/misc";
-import MiniHeader from "app/components/modules/MiniHeader";
-import secureRandom from "secure-random";
-import config from "config";
-import Mixpanel from "mixpanel";
+import teleSignVerify from 'server/utils/teleSign';
+import CountryCode from 'app/components/elements/CountryCode';
+import { getRemoteIp, checkCSRF } from 'server/utils/misc';
+import MiniHeader from 'app/components/modules/MiniHeader';
+import secureRandom from 'secure-random';
+import config from 'config';
+import Mixpanel from 'mixpanel';
import Progress from 'react-foundation-components/lib/global/progress-bar';
const path = require('path');
@@ -19,13 +21,13 @@ const ROOT = path.join(__dirname, '../../..');
// FIXME copy paste code, refactor mixpanel out
var mixpanel = null;
-if (config.has("mixpanel") && config.get("mixpanel")) {
- mixpanel = Mixpanel.init(config.get("mixpanel"));
+if (config.has('mixpanel') && config.get('mixpanel')) {
+ mixpanel = Mixpanel.init(config.get('mixpanel'));
}
-var assets_file = ROOT + "/tmp/webpack-stats-dev.json";
-if (process.env.NODE_ENV === "production") {
- assets_file = ROOT + "/tmp/webpack-stats-prod.json";
+var assets_file = ROOT + '/tmp/webpack-stats-dev.json';
+if (process.env.NODE_ENV === 'production') {
+ assets_file = ROOT + '/tmp/webpack-stats-prod.json';
}
const assets = Object.assign({}, require(assets_file), { script: [] });
@@ -40,11 +42,17 @@ const assets = Object.assign({}, require(assets_file), { script: [] });
function* confirmMobileHandler(e) {
if (!checkCSRF(this, this.request.body.csrf)) return;
- const confirmation_code = this.params && this.params.code
- ? this.params.code
- : this.request.body.code;
+ const params = addToParams({}, this.request.query, PARAM_VIEW_MODE, [
+ VIEW_MODE_WHISTLE,
+ ]);
+ const enterMobileUrl = `/enter_mobile` + makeParams(params);
+
+ const confirmation_code =
+ this.params && this.params.code
+ ? this.params.code
+ : this.request.body.code;
console.log(
- "-- /confirm_mobile -->",
+ '-- /confirm_mobile -->',
this.session.uid,
this.session.user,
confirmation_code
@@ -52,54 +60,64 @@ function* confirmMobileHandler(e) {
const user = yield models.User.findOne({
attributes: ['id', 'account_status'],
- where: { id: this.session.user }
+ where: { id: this.session.user },
});
if (!user) {
- this.flash = { error: "User session not found, please make sure you have cookies enabled in your browser for this website" };
- this.redirect("/enter_mobile");
+ this.flash = {
+ error:
+ 'User session not found, please make sure you have cookies enabled in your browser for this website',
+ };
+ this.redirect(enterMobileUrl);
return;
}
const mid = yield models.Identity.findOne({
- where: { user_id: user.id, provider: 'phone', confirmation_code }
+ where: { user_id: user.id, provider: 'phone', confirmation_code },
});
if (!mid) {
- this.flash = { error: "Wrong confirmation code" };
- this.redirect("/enter_mobile");
+ this.flash = { error: 'Wrong confirmation code' };
+ this.redirect(enterMobileUrl);
return;
}
const hours_ago = (Date.now() - mid.updated_at) / 1000.0 / 3600.0;
if (hours_ago > 24.0) {
this.status = 401;
- this.flash = { error: "Confirmation code has been expired" };
- this.redirect("/enter_mobile");
+ this.flash = { error: 'Confirmation code has been expired' };
+ this.redirect(enterMobileUrl);
return;
}
const number_of_created_accounts = yield models.sequelize.query(
`select count(*) as result from identities i join accounts a on a.user_id=i.user_id where i.provider='phone' and i.phone=:phone and a.created=1 and a.ignored<>1`,
- { replacements: { phone: mid.phone }, type: models.sequelize.QueryTypes.SELECT }
+ {
+ replacements: { phone: mid.phone },
+ type: models.sequelize.QueryTypes.SELECT,
+ }
);
- if (number_of_created_accounts && number_of_created_accounts[0].result > 0) {
+ if (
+ number_of_created_accounts &&
+ number_of_created_accounts[0].result > 0
+ ) {
console.log(
- "-- /confirm_mobile there are created accounts -->",
+ '-- /confirm_mobile there are created accounts -->',
user.id,
mid.phone
);
- this.flash = { error: "This phone number has already been used" };
- this.redirect('/enter_mobile');
+ this.flash = { error: 'This phone number has already been used' };
+ this.redirect(enterMobileUrl);
return;
}
// successful new verified phone number
yield mid.update({ provider: 'phone', verified: true });
- if (user.account_status === 'onhold') yield user.update({account_status: 'waiting'});
+ if (user.account_status === 'onhold')
+ yield user.update({ account_status: 'waiting' });
if (mixpanel)
- mixpanel.track("SignupStepPhone", { distinct_id: this.session.uid });
+ mixpanel.track('SignupStepPhone', { distinct_id: this.session.uid });
- console.log("--/Success phone redirecting user", this.session.user);
- this.redirect("/approval");
+ console.log('--/Success phone redirecting user', this.session.user);
+ this.redirect('/approval' + makeParams(params));
}
export default function useEnterAndConfirmMobilePages(app) {
@@ -107,45 +125,62 @@ export default function useEnterAndConfirmMobilePages(app) {
app.use(router.routes());
const koaBody = koa_body();
- router.get("/enter_mobile", function*() {
+ router.get('/enter_mobile', function*() {
console.log(
- "-- /enter_mobile -->",
+ '-- /enter_mobile -->',
this.session.uid,
this.session.user
);
+ const params = addToParams({}, this.request.query, PARAM_VIEW_MODE, [
+ VIEW_MODE_WHISTLE,
+ ]);
+ const viewMode = params[PARAM_VIEW_MODE] ? params[PARAM_VIEW_MODE] : '';
const phone = this.query.phone;
const country = this.query.country;
const body = renderToString(
-
+ {viewMode !== VIEW_MODE_WHISTLE ?
: null}
-
+
);
- const props = { body, title: "Phone Number", assets, meta: [] };
- this.body = "" +
- renderToString(
);
+ const props = { body, title: 'Phone Number', assets, meta: [] };
+ this.body =
+ '' + renderToString(
);
if (mixpanel)
- mixpanel.track("SignupStep2", { distinct_id: this.session.uid });
+ mixpanel.track('SignupStep2', { distinct_id: this.session.uid });
});
- router.post("/submit_mobile", koaBody, function*() {
+ router.post('/submit_mobile', koaBody, function*() {
if (!checkCSRF(this, this.request.body.csrf)) return;
const user_id = this.session.user;
+ const country = this.request.body.country;
+ const localPhone = this.request.body.phone;
+ const params = addToParams({}, this.request.query, PARAM_VIEW_MODE, [
+ VIEW_MODE_WHISTLE,
+ ]);
+ const viewMode = params[PARAM_VIEW_MODE] ? params[PARAM_VIEW_MODE] : '';
+
if (!user_id) {
- this.flash = { error: "Your session has been interrupted, please start over" };
- this.redirect('/pick_account');
+ this.flash = {
+ error: 'Your session has been interrupted, please start over',
+ };
+ this.redirect('/pick_account' + makeParams(params));
return;
}
+ params.country = country;
+ params.phone = localPhone;
- const country = this.request.body.country;
- const localPhone = this.request.body.phone;
- const enterMobileUrl = `/enter_mobile?phone=${localPhone}&country=${country}`;
+ const enterMobileUrl = `/enter_mobile` + makeParams(params);
- if (!country || country === "") {
- this.flash = { error: "Please select a country code" };
+ if (!country || country === '') {
+ this.flash = { error: 'Please select a country code' };
this.redirect(enterMobileUrl);
return;
}
if (!localPhone || digits(localPhone).length === 0) {
- this.flash = { error: "Please provide a phone number" };
+ this.flash = { error: 'Please provide a phone number' };
this.redirect(enterMobileUrl);
return;
}
@@ -225,25 +269,25 @@ recovery should your account ever be compromised.
// }
const confirmation_code = parseInt(
- secureRandom.randomBuffer(8).toString("hex"),
+ secureRandom.randomBuffer(8).toString('hex'),
16
)
.toString(10)
.substring(0, 5); // 4 digit code
let mid = yield models.Identity.findOne({
- where: { user_id, provider: "phone" }
+ where: { user_id, provider: 'phone' },
});
if (mid) {
if (mid.verified) {
if (mid.phone === phone) {
- this.flash = { success: "Phone number has been verified" };
+ this.flash = { success: 'Phone number has been verified' };
if (mixpanel)
- mixpanel.track("SignupStep3", {
- distinct_id: this.session.uid
+ mixpanel.track('SignupStep3', {
+ distinct_id: this.session.uid,
});
- this.redirect("/approval");
+ this.redirect('/approval' + makeParams(params));
return;
}
yield mid.update({ verified: false, phone });
@@ -251,7 +295,8 @@ recovery should your account ever be compromised.
const seconds_ago = (Date.now() - mid.updated_at) / 1000.0;
if (seconds_ago < 60) {
this.flash = {
- error: "Confirmation was attempted a moment ago. You can attempt verification again in one minute."
+ error:
+ 'Confirmation was attempted a moment ago. You can attempt verification again in one minute.',
};
this.redirect(enterMobileUrl);
return;
@@ -272,7 +317,7 @@ recovery should your account ever be compromised.
mobile: phone,
confirmation_code,
ip: getRemoteIp(this.req),
- ignore_score: true //twilioResult === 'pass'
+ ignore_score: true, //twilioResult === 'pass'
});
if (verifyResult.error) {
@@ -284,16 +329,20 @@ recovery should your account ever be compromised.
phone = verifyResult.phone;
if (mid) {
- yield mid.update({confirmation_code, phone, score: verifyResult.score});
+ yield mid.update({
+ confirmation_code,
+ phone,
+ score: verifyResult.score,
+ });
} else {
mid = yield models.Identity.create({
- provider: "phone",
+ provider: 'phone',
user_id,
uid: this.session.uid,
phone,
verified: false,
confirmation_code,
- score: verifyResult.score
+ score: verifyResult.score,
});
}
@@ -307,24 +356,23 @@ recovery should your account ever be compromised.
const body = renderToString(
-
+ {viewMode !== VIEW_MODE_WHISTLE ?
: null}
-
+
Thank you for providing your phone number (
{phone}
).
-
To continue please enter the SMS code we've sent you.
-
);
- const props = { body, title: "Phone Confirmation", assets, meta: [] };
- this.body = "" +
- renderToString(
);
+ const props = { body, title: 'Phone Confirmation', assets, meta: [] };
+ this.body =
+ '' + renderToString(
);
});
- router.get("/confirm_mobile/:code", confirmMobileHandler);
- router.post("/confirm_mobile", koaBody, confirmMobileHandler);
+ router.get('/confirm_mobile/:code', confirmMobileHandler);
+ router.post('/confirm_mobile', koaBody, confirmMobileHandler);
}
function digits(text) {
const digitArray = text.match(/\d+/g);
- return digitArray ? digitArray.join("") : "";
+ return digitArray ? digitArray.join('') : '';
}
diff --git a/src/server/utils/misc.js b/src/server/utils/misc.js
index b3bdd73d99d543b6e103329b886a67d23e19e70e..12b8b747e4fe27f0aa95e08554e4f35bf636b004 100644
--- a/src/server/utils/misc.js
+++ b/src/server/utils/misc.js
@@ -1,25 +1,28 @@
-import {esc} from 'db/models';
+import { esc } from 'db/models';
const emailRegex = /^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*$/;
function getRemoteIp(req) {
- const remote_address = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
- const ip_match = remote_address ? remote_address.match(/(\d+\.\d+\.\d+\.\d+)/) : null;
+ const remote_address =
+ req.headers['x-forwarded-for'] || req.connection.remoteAddress;
+ const ip_match = remote_address
+ ? remote_address.match(/(\d+\.\d+\.\d+\.\d+)/)
+ : null;
return ip_match ? ip_match[1] : esc(remote_address);
}
var ip_last_hit = new Map();
function rateLimitReq(ctx, req) {
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
- const now = Date.now()
+ const now = Date.now();
// purge hits older than minutes_max
ip_last_hit.forEach((v, k) => {
const seconds = (now - v) / 1000;
if (seconds > 1) {
- ip_last_hit.delete(ip)
+ ip_last_hit.delete(ip);
}
- })
+ });
let result = false;
// if ip is still in the map, abort
@@ -38,10 +41,17 @@ function rateLimitReq(ctx, req) {
}
function checkCSRF(ctx, csrf) {
- try { ctx.assertCSRF(csrf); } catch (e) {
+ try {
+ ctx.assertCSRF(csrf);
+ } catch (e) {
ctx.status = 403;
ctx.body = 'invalid csrf token';
- console.log('-- invalid csrf token -->', ctx.request.method, ctx.request.url, ctx.session.uid);
+ console.log(
+ '-- invalid csrf token -->',
+ ctx.request.method,
+ ctx.request.url,
+ ctx.session.uid
+ );
return false;
}
return true;
@@ -51,5 +61,5 @@ module.exports = {
emailRegex,
getRemoteIp,
rateLimitReq,
- checkCSRF
+ checkCSRF,
};
diff --git a/src/server/utils/teleSign.js b/src/server/utils/teleSign.js
index ed1131cd6dc9cc2668c8fa766fea20fb0f5e34f3..110851d9447cf37ca093c87a9419a0b4f9e6ebaf 100644
--- a/src/server/utils/teleSign.js
+++ b/src/server/utils/teleSign.js
@@ -16,7 +16,12 @@ const use_case_code = 'BACS'; // Use Case: avoid bulk attack and spammers
// Testing, always blocked: 1-310-555-0100
/** @return {object} - {reference_id} or {error} */
-export default function* verify({ mobile, confirmation_code, ip, ignore_score }) {
+export default function* verify({
+ mobile,
+ confirmation_code,
+ ip,
+ ignore_score,
+}) {
try {
const result = yield getScore(mobile);
const { recommendation, score } = result.risk;
@@ -24,21 +29,28 @@ export default function* verify({ mobile, confirmation_code, ip, ignore_score })
// if (!ignore_score && recommendation !== 'allow') {
if (!ignore_score && (!score || score > 600)) {
console.log(
- `TeleSign did not allow phone ${mobile} ip ${ip}. TeleSign responded: ${recommendation}`
+ `TeleSign did not allow phone ${mobile} ip ${
+ ip
+ }. TeleSign responded: ${recommendation}`
);
return {
- error: 'Unable to verify your phone number. Please try a different phone number.',
- score
+ error:
+ 'Unable to verify your phone number. Please try a different phone number.',
+ score,
};
}
- if (result.numbering && result.numbering.cleansing && result.numbering.cleansing.sms) {
+ if (
+ result.numbering &&
+ result.numbering.cleansing &&
+ result.numbering.cleansing.sms
+ ) {
const sms = result.numbering.cleansing.sms;
phone = sms.country_code + sms.phone_number;
}
const { reference_id } = yield verifySms({
mobile,
confirmation_code,
- ip
+ ip,
});
return { reference_id, score, phone };
} catch (error) {
@@ -49,13 +61,13 @@ export default function* verify({ mobile, confirmation_code, ip, ignore_score })
function getScore(mobile) {
const fields = urlencode({
- ucid: use_case_code
+ ucid: use_case_code,
});
const resource = '/v1/phoneid/score/' + mobile.match(/\d+/g).join('');
const method = 'GET';
return fetch(`https://rest-ww.telesign.com${resource}?${fields}`, {
method,
- headers: authHeaders({ resource, method })
+ headers: authHeaders({ resource, method }),
})
.then(r => r.json())
.catch(error => {
@@ -90,7 +102,7 @@ function verifySms({ mobile, confirmation_code, ip }) {
language: 'en-US',
ucid: use_case_code,
verify_code: confirmation_code,
- template: '$$CODE$$ is your Steemit confirmation code'
+ template: '$$CODE$$ is your Steemit confirmation code',
};
if (ip) f.originating_ip = ip;
const fields = urlencode(f);
@@ -101,12 +113,14 @@ function verifySms({ mobile, confirmation_code, ip }) {
return fetch('https://rest.telesign.com' + resource, {
method,
body: fields,
- headers: authHeaders({ resource, method, fields })
+ headers: authHeaders({ resource, method, fields }),
})
.then(r => r.json())
.catch(error => {
console.error(
- `ERROR: SMS failed to ${mobile} code ${confirmation_code} req ip ${ip} exception`,
+ `ERROR: SMS failed to ${mobile} code ${
+ confirmation_code
+ } req ip ${ip} exception`,
JSON.stringify(error, null, 0)
);
return Promise.reject(error);
@@ -134,13 +148,7 @@ function verifySms({ mobile, confirmation_code, ip }) {
@arg {string} method [GET|POST|PUT]
@arg {string} fields url query string
*/
-function authHeaders(
- {
- resource,
- fields,
- method = 'GET'
- }
-) {
+function authHeaders({ resource, fields, method = 'GET' }) {
const auth_method = 'HMAC-SHA256';
const currDate = new Date().toUTCString();
const nonce = parseInt(
@@ -152,7 +160,9 @@ function authHeaders(
if (/POST|PUT/.test(method))
content_type = 'application/x-www-form-urlencoded';
- let strToSign = `${method}\n${content_type}\n\nx-ts-auth-method:${auth_method}\nx-ts-date:${currDate}\nx-ts-nonce:${nonce}`;
+ let strToSign = `${method}\n${content_type}\n\nx-ts-auth-method:${
+ auth_method
+ }\nx-ts-date:${currDate}\nx-ts-nonce:${nonce}`;
if (fields) {
strToSign += '\n' + fields;
@@ -170,7 +180,7 @@ function authHeaders(
'Content-Type': content_type,
'x-ts-date': currDate,
'x-ts-auth-method': auth_method,
- 'x-ts-nonce': nonce
+ 'x-ts-nonce': nonce,
};
return headers;
}
diff --git a/src/server/utils/twilio.js b/src/server/utils/twilio.js
index 0a9777aadaabce5815500b4d86b8907fe6a2d442..b8653965712ffaf7132c2e523797889559fd8684 100644
--- a/src/server/utils/twilio.js
+++ b/src/server/utils/twilio.js
@@ -21,7 +21,22 @@ function checkEligibility(phone) {
// Hong Kong +852
// Israel +972
- for(const prefix of ['1', '33', '34', '39', '44', '46', '49', '52', '61', '63', '65', '90', '852', '972']) {
+ for (const prefix of [
+ '1',
+ '33',
+ '34',
+ '39',
+ '44',
+ '46',
+ '49',
+ '52',
+ '61',
+ '63',
+ '65',
+ '90',
+ '852',
+ '972',
+ ]) {
if (phone.startsWith(prefix)) return true;
}
return false;
@@ -30,40 +45,60 @@ function checkEligibility(phone) {
export default function verify(phone) {
if (!client) client = new twilio.LookupsClient(accountSid, authToken);
return new Promise(resolve => {
- if (!checkEligibility(phone)) {
- resolve('na');
- return;
- }
- client.phoneNumbers(phone).get({
- type: 'carrier',
- addOns: 'whitepages_pro_phone_rep',
- }, (error, result) => {
- if (error) {
- if (error.code === 20404) {
- console.log('Twilio phone not found ', phone);
- resolve('block');
- } else {
- console.error('Twilio error', JSON.stringify(error, null, 2));
- resolve('error');
- }
- } else {
- if (result.addOns &&
- result.addOns.results &&
- result.addOns.results.whitepages_pro_phone_rep &&
- result.addOns.results.whitepages_pro_phone_rep.result &&
- result.addOns.results.whitepages_pro_phone_rep.result.results &&
- result.addOns.results.whitepages_pro_phone_rep.result.results[0] &&
- result.addOns.results.whitepages_pro_phone_rep.result.results[0].reputation &&
- result.addOns.results.whitepages_pro_phone_rep.result.results[0].reputation.level
- ) {
- const reputation_level = result.addOns.results.whitepages_pro_phone_rep.result.results[0].reputation.level;
- console.log('Twilio reputation level ', phone, reputation_level);
- resolve(reputation_level < 3 ? 'pass' : 'block');
- } else {
- console.error('Twilio result does not contain reputation level:', JSON.stringify(result, null, 2));
- resolve('error');
- }
+ if (!checkEligibility(phone)) {
+ resolve('na');
+ return;
}
- });
- });
+ client.phoneNumbers(phone).get(
+ {
+ type: 'carrier',
+ addOns: 'whitepages_pro_phone_rep',
+ },
+ (error, result) => {
+ if (error) {
+ if (error.code === 20404) {
+ console.log('Twilio phone not found ', phone);
+ resolve('block');
+ } else {
+ console.error(
+ 'Twilio error',
+ JSON.stringify(error, null, 2)
+ );
+ resolve('error');
+ }
+ } else {
+ if (
+ result.addOns &&
+ result.addOns.results &&
+ result.addOns.results.whitepages_pro_phone_rep &&
+ result.addOns.results.whitepages_pro_phone_rep.result &&
+ result.addOns.results.whitepages_pro_phone_rep.result
+ .results &&
+ result.addOns.results.whitepages_pro_phone_rep.result
+ .results[0] &&
+ result.addOns.results.whitepages_pro_phone_rep.result
+ .results[0].reputation &&
+ result.addOns.results.whitepages_pro_phone_rep.result
+ .results[0].reputation.level
+ ) {
+ const reputation_level =
+ result.addOns.results.whitepages_pro_phone_rep
+ .result.results[0].reputation.level;
+ console.log(
+ 'Twilio reputation level ',
+ phone,
+ reputation_level
+ );
+ resolve(reputation_level < 3 ? 'pass' : 'block');
+ } else {
+ console.error(
+ 'Twilio result does not contain reputation level:',
+ JSON.stringify(result, null, 2)
+ );
+ resolve('error');
+ }
+ }
+ }
+ );
+ });
}
diff --git a/src/shared/HtmlReady.js b/src/shared/HtmlReady.js
index 8156ffd553db2c49bcfc84e2970254575952245a..b2370b9660ce72258ea7cca33e2c9d1b973773fa 100644
--- a/src/shared/HtmlReady.js
+++ b/src/shared/HtmlReady.js
@@ -1,16 +1,18 @@
-import xmldom from 'xmldom'
-import tt from 'counterpart'
-import linksRe, { any as linksAny } from 'app/utils/Links'
-import {validate_account_name} from 'app/utils/ChainValidation'
-import proxifyImageUrl from 'app/utils/ProxifyUrl'
+import xmldom from 'xmldom';
+import tt from 'counterpart';
+import linksRe, { any as linksAny } from 'app/utils/Links';
+import { validate_account_name } from 'app/utils/ChainValidation';
+import proxifyImageUrl from 'app/utils/ProxifyUrl';
export const getPhishingWarningMessage = () => tt('g.phishy_message');
+export const getExternalLinkWarningMessage = () =>
+ tt('g.external_link_message');
-const noop = () => {}
+const noop = () => {};
const DOMParser = new xmldom.DOMParser({
- errorHandler: {warning: noop, error: noop}
-})
-const XMLSerializer = new xmldom.XMLSerializer()
+ errorHandler: { warning: noop, error: noop },
+});
+const XMLSerializer = new xmldom.XMLSerializer();
/**
* Functions performed by HTMLReady
@@ -76,71 +78,80 @@ const XMLSerializer = new xmldom.XMLSerializer()
If hideImages and mutate is set to true all images will be replaced
by
elements containing just the image url.
*/
-export default function (html, {mutate = true, hideImages = false} = {}) {
- const state = {mutate}
- state.hashtags = new Set()
- state.usertags = new Set()
- state.htmltags = new Set()
- state.images = new Set()
- state.links = new Set()
+export default function(html, { mutate = true, hideImages = false } = {}) {
+ const state = { mutate };
+ state.hashtags = new Set();
+ state.usertags = new Set();
+ state.htmltags = new Set();
+ state.images = new Set();
+ state.links = new Set();
try {
- const doc = DOMParser.parseFromString(html, 'text/html')
- traverse(doc, state)
- if(mutate) {
+ const doc = DOMParser.parseFromString(html, 'text/html');
+ traverse(doc, state);
+ if (mutate) {
if (hideImages) {
- for (const image of Array.from(doc.getElementsByTagName('img'))) {
- const pre = doc.createElement('pre')
- pre.setAttribute('class', 'image-url-only')
- pre.appendChild(doc.createTextNode(image.getAttribute('src')))
- image.parentNode.replaceChild(pre, image)
+ for (const image of Array.from(
+ doc.getElementsByTagName('img')
+ )) {
+ const pre = doc.createElement('pre');
+ pre.setAttribute('class', 'image-url-only');
+ pre.appendChild(
+ doc.createTextNode(image.getAttribute('src'))
+ );
+ image.parentNode.replaceChild(pre, image);
}
} else {
- proxifyImages(doc)
+ proxifyImages(doc);
}
}
// console.log('state', state)
- if(!mutate) return state
- return {html: (doc) ? XMLSerializer.serializeToString(doc) : '', ...state}
- }catch(error) {
- // Not Used, parseFromString might throw an error in the future
- console.error(error.toString())
- return {html}
+ if (!mutate) return state;
+ return {
+ html: doc ? XMLSerializer.serializeToString(doc) : '',
+ ...state,
+ };
+ } catch (error) {
+ // xmldom error is bad
+ console.log(
+ 'rendering error',
+ JSON.stringify({ error: error.message, html })
+ );
+ return { html: '' };
}
}
function traverse(node, state, depth = 0) {
- if(!node || !node.childNodes) return
+ if (!node || !node.childNodes) return;
Array(...node.childNodes).forEach(child => {
// console.log(depth, 'child.tag,data', child.tagName, child.data)
- const tag = child.tagName ? child.tagName.toLowerCase() : null
- if(tag) state.htmltags.add(tag)
-
- if(tag === 'img')
- img(state, child)
- else if(tag === 'iframe')
- iframe(state, child)
- else if(tag === 'a')
- link(state, child)
- else if(child.nodeName === '#text')
- linkifyNode(child, state)
-
- traverse(child, state, depth + 1)
- })
+ const tag = child.tagName ? child.tagName.toLowerCase() : null;
+ if (tag) state.htmltags.add(tag);
+
+ if (tag === 'img') img(state, child);
+ else if (tag === 'iframe') iframe(state, child);
+ else if (tag === 'a') link(state, child);
+ else if (child.nodeName === '#text') linkifyNode(child, state);
+
+ traverse(child, state, depth + 1);
+ });
}
function link(state, child) {
- const url = child.getAttribute('href')
- if(url) {
- state.links.add(url)
- if(state.mutate) {
- // If this link is not relative, http, or https -- add https.
- if(! /^\/(?!\/)|(https?:)?\/\//.test(url)) {
- child.setAttribute('href', "https://"+url)
+ const url = child.getAttribute('href');
+ if (url) {
+ state.links.add(url);
+ if (state.mutate) {
+ // If this link is not relative, http, https, or steem -- add https.
+ if (!/^((#)|(\/(?!\/))|(((steem|https?):)?\/\/))/.test(url)) {
+ child.setAttribute('href', 'https://' + url);
}
// Unlink potential phishing attempts
- if (child.textContent.match(/https?:\/\/(.*@)?(www\.)?steemit\.com/)
- && !url.match(/https?:\/\/(.*@)?(www\.)?steemit\.com/)) {
+ if (
+ url.indexOf('#') !== 0 && // Allow in-page links
+ (child.textContent.match(/(www\.)?steemit\.com/i) &&
+ !url.match(/https?:\/\/(.*@)?(www\.)?steemit\.com/i))
+ ) {
const phishyDiv = child.ownerDocument.createElement('div');
phishyDiv.textContent = `${child.textContent} / ${url}`;
phishyDiv.setAttribute('title', getPhishingWarningMessage());
@@ -153,37 +164,46 @@ function link(state, child) {
// wrap iframes in div.videoWrapper to control size/aspect ratio
function iframe(state, child) {
- const url = child.getAttribute('src')
- if(url) {
- const {images, links} = state
- const yt = youTubeId(url)
- if(yt && images && links) {
- links.add(yt.url)
- images.add('https://img.youtube.com/vi/' + yt.id + '/0.jpg')
+ const url = child.getAttribute('src');
+ if (url) {
+ const { images, links } = state;
+ const yt = youTubeId(url);
+ if (yt && images && links) {
+ links.add(yt.url);
+ images.add('https://img.youtube.com/vi/' + yt.id + '/0.jpg');
}
}
- const {mutate} = state
- if(!mutate) return
-
- const tag = child.parentNode.tagName ? child.parentNode.tagName.toLowerCase() : child.parentNode.tagName
- if(tag == 'div' && child.parentNode.getAttribute('class') == 'videoWrapper') return;
- const html = XMLSerializer.serializeToString(child)
- child.parentNode.replaceChild(DOMParser.parseFromString(`${html}
`), child)
+ const { mutate } = state;
+ if (!mutate) return;
+
+ const tag = child.parentNode.tagName
+ ? child.parentNode.tagName.toLowerCase()
+ : child.parentNode.tagName;
+ if (
+ tag == 'div' &&
+ child.parentNode.getAttribute('class') == 'videoWrapper'
+ )
+ return;
+ const html = XMLSerializer.serializeToString(child);
+ child.parentNode.replaceChild(
+ DOMParser.parseFromString(`${html}
`),
+ child
+ );
}
function img(state, child) {
- const url = child.getAttribute('src')
- if(url) {
- state.images.add(url)
- if(state.mutate) {
- let url2 = ipfsPrefix(url)
- if(/^\/\//.test(url2)) {
+ const url = child.getAttribute('src');
+ if (url) {
+ state.images.add(url);
+ if (state.mutate) {
+ let url2 = ipfsPrefix(url);
+ if (/^\/\//.test(url2)) {
// Change relative protocol imgs to https
- url2 = "https:" + url2
+ url2 = 'https:' + url2;
}
- if(url2 !== url) {
- child.setAttribute('src', url2)
+ if (url2 !== url) {
+ child.setAttribute('src', url2);
}
}
}
@@ -193,130 +213,162 @@ function img(state, child) {
function proxifyImages(doc) {
if (!doc) return;
[...doc.getElementsByTagName('img')].forEach(node => {
- const url = node.getAttribute('src')
- if(! linksRe.local.test(url))
- node.setAttribute('src', proxifyImageUrl(url, true))
- })
+ const url = node.getAttribute('src');
+ if (!linksRe.local.test(url))
+ node.setAttribute('src', proxifyImageUrl(url, true));
+ });
}
-function linkifyNode(child, state) {try{
- const tag = child.parentNode.tagName ? child.parentNode.tagName.toLowerCase() : child.parentNode.tagName
- if(tag === 'code') return
- if(tag === 'a') return
-
- const {mutate} = state
- if(!child.data) return
- if(embedYouTubeNode(child, state.links, state.images)) return
- if(embedVimeoNode(child, state.links, state.images)) return
-
- const data = XMLSerializer.serializeToString(child)
- const content = linkify(data, state.mutate, state.hashtags, state.usertags, state.images, state.links)
- if(mutate && content !== data) {
- const newChild = DOMParser.parseFromString(`${content} `)
- child.parentNode.replaceChild(newChild, child)
- return newChild;
+function linkifyNode(child, state) {
+ try {
+ const tag = child.parentNode.tagName
+ ? child.parentNode.tagName.toLowerCase()
+ : child.parentNode.tagName;
+ if (tag === 'code') return;
+ if (tag === 'a') return;
+
+ const { mutate } = state;
+ if (!child.data) return;
+ if (embedYouTubeNode(child, state.links, state.images)) return;
+ if (embedVimeoNode(child, state.links, state.images)) return;
+
+ const data = XMLSerializer.serializeToString(child);
+ const content = linkify(
+ data,
+ state.mutate,
+ state.hashtags,
+ state.usertags,
+ state.images,
+ state.links
+ );
+ if (mutate && content !== data) {
+ const newChild = DOMParser.parseFromString(
+ `${content} `
+ );
+ child.parentNode.replaceChild(newChild, child);
+ return newChild;
+ }
+ } catch (error) {
+ console.log(error);
}
-} catch(error) {console.log(error)}}
+}
function linkify(content, mutate, hashtags, usertags, images, links) {
// hashtag
- content = content.replace(/(^|\s)(#[-a-z\d]+)/ig, tag => {
- if(/#[\d]+$/.test(tag)) return tag // Don't allow numbers to be tags
- const space = /^\s/.test(tag) ? tag[0] : ''
- const tag2 = tag.trim().substring(1)
- const tagLower = tag2.toLowerCase()
- if(hashtags) hashtags.add(tagLower)
- if(!mutate) return tag
- return space + `${tag} `
- })
+ content = content.replace(/(^|\s)(#[-a-z\d]+)/gi, tag => {
+ if (/#[\d]+$/.test(tag)) return tag; // Don't allow numbers to be tags
+ const space = /^\s/.test(tag) ? tag[0] : '';
+ const tag2 = tag.trim().substring(1);
+ const tagLower = tag2.toLowerCase();
+ if (hashtags) hashtags.add(tagLower);
+ if (!mutate) return tag;
+ return space + `${tag} `;
+ });
// usertag (mention)
- content = content.replace(/(^|\s)(@[a-z][-\.a-z\d]+[a-z\d])/ig, user => {
- const space = /^\s/.test(user) ? user[0] : ''
- const user2 = user.trim().substring(1)
- const userLower = user2.toLowerCase()
- const valid = validate_account_name(userLower) == null
- if(valid && usertags) usertags.add(userLower)
- if(!mutate) return user
- return space + (valid ?
- `@${user2} ` :
- '@' + user2
- )
- })
+ // Cribbed from https://github.com/twitter/twitter-text/blob/v1.14.7/js/twitter-text.js#L90
+ content = content.replace(
+ /(^|[^a-zA-Z0-9_!#$%&*@@\/]|(^|[^a-zA-Z0-9_+~.-\/]))[@@]([a-z][-\.a-z\d]+[a-z\d])/gi,
+ (match, preceeding1, preceeding2, user) => {
+ const userLower = user.toLowerCase();
+ const valid = validate_account_name(userLower) == null;
+
+ if (valid && usertags) usertags.add(userLower);
+
+ const preceedings = (preceeding1 || '') + (preceeding2 || ''); // include the preceeding matches if they exist
+
+ if (!mutate) return `${preceedings}${user}`;
+
+ return valid
+ ? `${preceedings}@${user} `
+ : '@' + user;
+ }
+ );
content = content.replace(linksAny('gi'), ln => {
- if(linksRe.image.test(ln)) {
- if(images) images.add(ln)
- return ` `
+ if (linksRe.image.test(ln)) {
+ if (images) images.add(ln);
+ return ` `;
}
// do not linkify .exe or .zip urls
- if(/\.(zip|exe)$/i.test(ln)) return ln;
+ if (/\.(zip|exe)$/i.test(ln)) return ln;
- if(links) links.add(ln)
- return `${ln} `
- })
- return content
+ if (links) links.add(ln);
+ return `${ln} `;
+ });
+ return content;
}
-function embedYouTubeNode(child, links, images) { try {
- if(!child.data) return false
- const data = child.data
- const yt = youTubeId(data)
- if(!yt) return false
-
- const v = DOMParser.parseFromString(`~~~ embed:${yt.id} youtube ~~~`)
- child.parentNode.replaceChild(v, child)
- if(links) links.add(yt.url)
- if(images) images.add('https://img.youtube.com/vi/' + yt.id + '/0.jpg')
- return true
-} catch(error) { console.log(error); return false } }
+function embedYouTubeNode(child, links, images) {
+ try {
+ if (!child.data) return false;
+ const data = child.data;
+ const yt = youTubeId(data);
+ if (!yt) return false;
+
+ const v = DOMParser.parseFromString(`~~~ embed:${yt.id} youtube ~~~`);
+ child.parentNode.replaceChild(v, child);
+ if (links) links.add(yt.url);
+ if (images)
+ images.add('https://img.youtube.com/vi/' + yt.id + '/0.jpg');
+ return true;
+ } catch (error) {
+ console.log(error);
+ return false;
+ }
+}
/** @return {id, url} or null */
function youTubeId(data) {
- if(!data) return null
+ if (!data) return null;
- const m1 = data.match(linksRe.youTube)
- const url = m1 ? m1[0] : null
- if(!url) return null
+ const m1 = data.match(linksRe.youTube);
+ const url = m1 ? m1[0] : null;
+ if (!url) return null;
- const m2 = url.match(linksRe.youTubeId)
- const id = m2 && m2.length >= 2 ? m2[1] : null
- if(!id) return null
+ const m2 = url.match(linksRe.youTubeId);
+ const id = m2 && m2.length >= 2 ? m2[1] : null;
+ if (!id) return null;
- return {id, url}
+ return { id, url };
}
-function embedVimeoNode(child, links, /*images*/) {try{
- if(!child.data) return false
- const data = child.data
+function embedVimeoNode(child, links /*images*/) {
+ try {
+ if (!child.data) return false;
+ const data = child.data;
- let id
- {
- const m = data.match(linksRe.vimeoId)
- id = m && m.length >= 2 ? m[1] : null
- }
- if(!id) return false;
+ let id;
+ {
+ const m = data.match(linksRe.vimeoId);
+ id = m && m.length >= 2 ? m[1] : null;
+ }
+ if (!id) return false;
- const url = `https://player.vimeo.com/video/${id}`
- const v = DOMParser.parseFromString(`~~~ embed:${id} vimeo ~~~`)
- child.parentNode.replaceChild(v, child)
- if(links) links.add(url)
+ const url = `https://player.vimeo.com/video/${id}`;
+ const v = DOMParser.parseFromString(`~~~ embed:${id} vimeo ~~~`);
+ child.parentNode.replaceChild(v, child);
+ if (links) links.add(url);
- // Preview image requires a callback.. http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo
- // if(images) images.add('https://.../vi/' + id + '/0.jpg')
+ // Preview image requires a callback.. http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo
+ // if(images) images.add('https://.../vi/' + id + '/0.jpg')
- return true
-} catch(error) {console.log(error); return false}}
+ return true;
+ } catch (error) {
+ console.log(error);
+ return false;
+ }
+}
function ipfsPrefix(url) {
- if($STM_Config.ipfs_prefix) {
+ if ($STM_Config.ipfs_prefix) {
// Convert //ipfs/xxx or /ipfs/xxx into https://steemit.com/ipfs/xxxxx
- if(/^\/?\/ipfs\//.test(url)) {
- const slash = url.charAt(1) === '/' ? 1 : 0
- url = url.substring(slash + '/ipfs/'.length) // start with only 1 /
- return $STM_Config.ipfs_prefix + '/' + url
+ if (/^\/?\/ipfs\//.test(url)) {
+ const slash = url.charAt(1) === '/' ? 1 : 0;
+ url = url.substring(slash + '/ipfs/'.length); // start with only 1 /
+ return $STM_Config.ipfs_prefix + '/' + url;
}
}
- return url
+ return url;
}
diff --git a/src/shared/HtmlReady.test.js b/src/shared/HtmlReady.test.js
index 81faadeb947d9d125b0e412301f45cc183cd1437..44f5ca1f6109e9c37d33799fa0ea8109c6bfe8d1 100644
--- a/src/shared/HtmlReady.test.js
+++ b/src/shared/HtmlReady.test.js
@@ -1,48 +1,145 @@
-/* eslint no-undef:0 no-unused-vars:0 */
/* global describe, it, before, beforeEach, after, afterEach */
-import chai, { expect } from 'chai';
-
import HtmlReady from './HtmlReady';
+beforeEach(() => {
+ global.$STM_Config = {};
+});
+
describe('htmlready', () => {
- before(() => {
- global.$STM_Config = {};
+ it('should return an empty string if input cannot be parsed', () => {
+ const teststring = 'teststring lol'; // this string causes the xmldom parser to fail & error out
+ expect(HtmlReady(teststring).html).toEqual('');
});
- it('should return plain text without html unmolested', () => {
- const teststring = 'teststring lol';
- expect(HtmlReady(teststring).html).to.equal(teststring);
+ it('should allow links where the text portion and href contains steemit.com', () => {
+ const dirty =
+ 'https://steemit.com/signup ';
+ const res = HtmlReady(dirty).html;
+ expect(res).toEqual(dirty);
});
- it('should allow links where the text portion and href contains steemit.com', () => {
- const dirty = 'https://steemit.com/signup ';
+ it('should allow in-page links ', () => {
+ const dirty =
+ 'a link location ';
const res = HtmlReady(dirty).html;
- expect(res).to.equal(dirty);
+ expect(res).toEqual(dirty);
+
+ const externalDomainDirty =
+ 'Another website\'s apple section ';
+ const externalDomainResult = HtmlReady(externalDomainDirty).html;
+ expect(externalDomainResult).toEqual(externalDomainDirty);
});
it('should not allow links where the text portion contains steemit.com but the link does not', () => {
// There isn't an easy way to mock counterpart, even with proxyquire, so we just test for the missing translation message -- ugly but ok
- const dirty = 'https://steemit.com/signup ';
- const cleansed = 'https://steemit.com/signup / https://steamit.com/signup
';
+ const dirty =
+ 'https://steemit.com/signup ';
+ const cleansed =
+ 'https://steemit.com/signup / https://steamit.com/signup
';
const res = HtmlReady(dirty).html;
- expect(res).to.equal(cleansed);
+ expect(res).toEqual(cleansed);
+
+ const cased =
+ 'https://Steemit.com/signup ';
+ const cleansedcased =
+ 'https://Steemit.com/signup / https://steamit.com/signup
';
+ const rescased = HtmlReady(cased).html;
+ expect(rescased).toEqual(cleansedcased);
- const withuser = 'https://official@steemit.com/signup ';
- const cleansedwithuser = 'https://official@steemit.com/signup / https://steamit.com/signup
';
+ const withuser =
+ 'https://official@steemit.com/signup ';
+ const cleansedwithuser =
+ 'https://official@steemit.com/signup / https://steamit.com/signup
';
const reswithuser = HtmlReady(withuser).html;
- expect(reswithuser).to.equal(cleansedwithuser);
+ expect(reswithuser).toEqual(cleansedwithuser);
- const noendingslash = 'https://steemit.com ';
- const cleansednoendingslash = 'https://steemit.com / https://steamit.com
';
+ const noendingslash =
+ 'https://steemit.com ';
+ const cleansednoendingslash =
+ 'https://steemit.com / https://steamit.com
';
const resnoendingslash = HtmlReady(noendingslash).html;
- expect(resnoendingslash).to.equal(cleansednoendingslash);
+ expect(resnoendingslash).toEqual(cleansednoendingslash);
+
+ //make sure extra-domain in-page links are also caught by our phishy link scan.
+ const domainInpage =
+ 'https://steemit.com ';
+ const cleanDomainInpage =
+ 'https://steemit.com / https://steamit.com#really-evil-inpage-component
';
+ const resDomainInpage = HtmlReady(domainInpage).html;
+ expect(resDomainInpage).toEqual(cleanDomainInpage);
+
+ // anchor links including steemit.com should be allowed
+ const inpage =
+ 'Go down lower for https://steemit.com info! ';
+ const cleanInpage =
+ 'Go down lower for https://steemit.com info! ';
+ const resinpage = HtmlReady(inpage).html;
+ expect(resinpage).toEqual(cleanInpage);
+
+ const noprotocol =
+ 'for a good time, visit steemit.com today ';
+ const cleansednoprotocol =
+ 'for a good time, visit steemit.com today / https://steamit.com/
';
+ const resnoprotocol = HtmlReady(noprotocol).html;
+ expect(resnoprotocol).toEqual(cleansednoprotocol);
});
it('should allow more than one link per post', () => {
- const somanylinks = 'https://foo.com and https://blah.com ';
- const htmlified = 'https://foo.com and https://blah.com ';
+ const somanylinks =
+ 'https://foo.com and https://blah.com ';
+ const htmlified =
+ 'https://foo.com and https://blah.com ';
const res = HtmlReady(somanylinks).html;
- expect(res).to.equal(htmlified);
- })
+ expect(res).toEqual(htmlified);
+ });
+
+ it('should link usernames', () => {
+ const textwithmentions =
+ '@username (@a1b2, whatever ';
+ const htmlified =
+ '@username (@a1b2 , whatever ';
+ const res = HtmlReady(textwithmentions).html;
+ expect(res).toEqual(htmlified);
+ });
+
+ it('should detect only valid mentions', () => {
+ const textwithmentions =
+ '@abc @xx (@aaa1) @_x @eee, @fff! https://x.com/@zzz/test';
+ const res = HtmlReady(textwithmentions, { mutate: false });
+ const usertags = Array.from(res.usertags).join(',');
+ expect(usertags).toEqual('abc,aaa1,eee,fff');
+ });
+
+ it('should not link usernames at the front of linked text', () => {
+ const nameinsidelinkfirst =
+ '@hihi ';
+ const htmlified =
+ '@hihi ';
+ const res = HtmlReady(nameinsidelinkfirst).html;
+ expect(res).toEqual(htmlified);
+ });
+
+ it('should not link usernames in the middle of linked text', () => {
+ const nameinsidelinkmiddle =
+ 'hi @hihi ';
+ const htmlified =
+ 'hi @hihi ';
+ const res = HtmlReady(nameinsidelinkmiddle).html;
+ expect(res).toEqual(htmlified);
+ });
+
+ it('should make relative links absolute with https by default', () => {
+ const noRelativeHttpHttpsOrSteem = ' zippy ';
+ const cleansedRelativeHttpHttpsOrSteem = ' zippy ';
+ const resNoRelativeHttpHttpsOrSteem = HtmlReady(noRelativeHttpHttpsOrSteem).html;
+ expect(resNoRelativeHttpHttpsOrSteem).toEqual(cleansedRelativeHttpHttpsOrSteem);
+ });
+
+ it('should allow the steem uri scheme for vessel links', () => {
+ const noRelativeHttpHttpsOrSteem = ' arteries ';
+ const cleansedRelativeHttpHttpsOrSteem = ' arteries ';
+ const resNoRelativeHttpHttpsOrSteem = HtmlReady(noRelativeHttpHttpsOrSteem).html;
+ expect(resNoRelativeHttpHttpsOrSteem).toEqual(cleansedRelativeHttpHttpsOrSteem);
+ });
});
diff --git a/src/shared/UniversalRender.jsx b/src/shared/UniversalRender.jsx
index b6bf72380341257d307bcf9e273e9767acf59efc..7a1c724b1037fbd26df4a5e15a5af080e03d4683 100644
--- a/src/shared/UniversalRender.jsx
+++ b/src/shared/UniversalRender.jsx
@@ -5,36 +5,49 @@ import Iso from 'iso';
import React from 'react';
import { render } from 'react-dom';
import { renderToString } from 'react-dom/server';
-import { Router, RouterContext, match, applyRouterMiddleware, browserHistory } from 'react-router';
+import {
+ Router,
+ RouterContext,
+ match,
+ applyRouterMiddleware,
+ browserHistory,
+} from 'react-router';
import { Provider } from 'react-redux';
import RootRoute from 'app/RootRoute';
-import {createStore, applyMiddleware, compose} from 'redux';
+import * as appActions from 'app/redux/AppReducer';
+import { createStore, applyMiddleware, compose } from 'redux';
import { useScroll } from 'react-router-scroll';
import createSagaMiddleware from 'redux-saga';
import { syncHistoryWithStore } from 'react-router-redux';
import rootReducer from 'app/redux/RootReducer';
-import {fetchDataWatches} from 'app/redux/FetchDataSaga';
-import {marketWatches} from 'app/redux/MarketSaga';
-import {sharedWatches} from 'app/redux/SagaShared';
-import {userWatches} from 'app/redux/UserSaga';
-import {authWatches} from 'app/redux/AuthSaga';
-import {transactionWatches} from 'app/redux/TransactionSaga';
-import PollDataSaga from 'app/redux/PollDataSaga';
-import {component as NotFound} from 'app/components/pages/NotFound';
+import { fetchDataWatches } from 'app/redux/FetchDataSaga';
+import { marketWatches } from 'app/redux/MarketSaga';
+import { sharedWatches } from 'app/redux/SagaShared';
+import { userWatches } from 'app/redux/UserSaga';
+import { authWatches } from 'app/redux/AuthSaga';
+import { transactionWatches } from 'app/redux/TransactionSaga';
+import { component as NotFound } from 'app/components/pages/NotFound';
import extractMeta from 'app/utils/ExtractMeta';
import Translator from 'app/Translator';
-import {notificationsArrayToMap} from 'app/utils/Notifications';
-import {routeRegex} from "app/ResolveRoute";
-import {contentStats} from 'app/utils/StateFunctions';
+import { routeRegex } from 'app/ResolveRoute';
+import { contentStats } from 'app/utils/StateFunctions';
import ScrollBehavior from 'scroll-behavior';
-import {api} from 'steem';
+import { api } from '@steemit/steem-js';
+let get_state_perf,
+ get_content_perf = false;
+if (process.env.OFFLINE_SSR_TEST) {
+ const testDataDir = process.env.OFFLINE_SSR_TEST_DATA_DIR || 'api_mockdata';
+ let uri = `${__dirname}/../../`;
+ get_state_perf = require(uri + testDataDir + '/get_state');
+ get_content_perf = require(uri + testDataDir + '/get_content');
+}
-const calcOffsetRoot = (startEl) => {
+const calcOffsetRoot = startEl => {
let offset = 0;
let el = startEl;
- while(el) {
+ while (el) {
offset += el.offsetTop;
el = el.offsetParent;
}
@@ -42,9 +55,45 @@ const calcOffsetRoot = (startEl) => {
};
//BEGIN: SCROLL CODE
-const SCROLL_TOP_TRIES = 100;
-const SCROLL_TOP_DELAY_MS = 50;
+/**
+ * The maximum number of times to attempt scrolling to the target element/y position
+ * (total seconds of attempted scrolling is given by (SCROLL_TOP_TRIES * SCROLL_TOP_DELAY_MS)/1000 )
+ * @type {number}
+ */
+const SCROLL_TOP_TRIES = 50;
+/**
+ * The number of milliseconds to delay between scroll attempts
+ * (total seconds of attempted scrolling is given by (SCROLL_TOP_TRIES * SCROLL_TOP_DELAY_MS)/1000 )
+ * @type {number}
+ */
+const SCROLL_TOP_DELAY_MS = 100;
+/**
+ * The size of the vertical gap between the bottom of the fixed header and the top of the scrolled-to element.
+ * @type {number}
+ */
const SCROLL_TOP_EXTRA_PIXEL_OFFSET = 3;
+/**
+ * number of pixels the document can move in the 'wrong' direction (opposite of intended scroll) this covers accidental scroll movements by users.
+ * @type {number}
+ */
+const SCROLL_FUDGE_PIXELS = 10;
+/**
+ * if document is being scrolled up this is set for prevDocumentInfo && documentInfo
+ * @type {string}
+ */
+const SCROLL_DIRECTION_UP = 'up';
+/**
+ * if document is being scrolled down this is set for prevDocumentInfo && documentInfo
+ * @type {string}
+ */
+const SCROLL_DIRECTION_DOWN = 'down';
+
+/**
+ * If an element with this id is present, the page does not want us to detect navigation history direction (clicking links/forward button or back button)
+ * @type {string}
+ */
+const DISABLE_ROUTER_HISTORY_NAV_DIRECTION_EL_ID =
+ 'disable_router_nav_history_direction_check';
let scrollTopTimeout = null;
@@ -63,37 +112,85 @@ const scrollTop = (el, topOffset, prevDocumentInfo, triesRemaining) => {
const documentInfo = {
scrollHeight: document.body.scrollHeight,
scrollTop: Math.ceil(document.scrollingElement.scrollTop),
- scrollTarget: calcOffsetRoot(el) + topOffset
+ scrollTarget: calcOffsetRoot(el) + topOffset,
+ direction: prevDocumentInfo.direction,
};
+ let doScroll = false;
+ //for both SCROLL_DIRECTION_DOWN, SCROLL_DIRECTION_UP
+ //We scroll if the document has 1. not been deliberately scrolled, AND 2. we have not passed our target scroll,
+ //NOR has the document changed in a meaningful way since we last looked at it
+ if (prevDocumentInfo.direction === SCROLL_DIRECTION_DOWN) {
+ doScroll =
+ prevDocumentInfo.scrollTop <=
+ documentInfo.scrollTop + SCROLL_FUDGE_PIXELS &&
+ (documentInfo.scrollTop < documentInfo.scrollTarget ||
+ prevDocumentInfo.scrollTarget < documentInfo.scrollTarget ||
+ prevDocumentInfo.scrollHeight < documentInfo.scrollHeight);
+ } else if (prevDocumentInfo.direction === SCROLL_DIRECTION_UP) {
+ doScroll =
+ prevDocumentInfo.scrollTop >=
+ documentInfo.scrollTop - SCROLL_FUDGE_PIXELS &&
+ (documentInfo.scrollTop > documentInfo.scrollTarget ||
+ prevDocumentInfo.scrollTarget > documentInfo.scrollTarget ||
+ prevDocumentInfo.scrollHeight > documentInfo.scrollHeight);
+ }
- if(documentInfo.scrollTop < documentInfo.scrollTarget
- || prevDocumentInfo.scrollTarget < documentInfo.scrollTarget
- || prevDocumentInfo.scrollHeight < documentInfo.scrollHeight) {
+ if (doScroll) {
window.scrollTo(0, documentInfo.scrollTarget);
- if(triesRemaining > 0) {
- scrollTopTimeout = setTimeout(() => scrollTop(el, topOffset, documentInfo, (triesRemaining-1)), SCROLL_TOP_DELAY_MS);
+ if (triesRemaining > 0) {
+ scrollTopTimeout = setTimeout(
+ () =>
+ scrollTop(el, topOffset, documentInfo, triesRemaining - 1),
+ SCROLL_TOP_DELAY_MS
+ );
}
}
-}
+};
/**
- * raison d'être: on hash link navigation, calculate the appropriate y-scroll with a fixed position top menu
+ * Custom scrolling behavior needed because we have chunky page loads and a fixed header.
*/
class OffsetScrollBehavior extends ScrollBehavior {
+ /**
+ * Raison d'être: on hash link navigation, assemble the needed info and pass it to scrollTop()
+ * In cases where we're scrolling to a pixel offset, adjust the offset for the current header, and punt to default behavior.
+ */
scrollToTarget(element, target) {
- clearTimeout(scrollTopTimeout);
- const el = (typeof target === 'string') ? document.getElementById(target) : false;
- if(el) {
- const header = document.getElementsByTagName('header')[0]; //this dimension ideally would be pulled from a scss file.
- const topOffset = (((header)? header.offsetHeight : 0) + SCROLL_TOP_EXTRA_PIXEL_OFFSET) * (-1);
+ clearTimeout(scrollTopTimeout); //it's likely this will be called multiple times in succession, so clear and existing scrolling.
+ const header = document.getElementsByTagName('header')[0]; //this dimension ideally would be pulled from a scss file.
+ let topOffset = SCROLL_TOP_EXTRA_PIXEL_OFFSET * -1;
+ if (header) {
+ topOffset += header.offsetHeight * -1;
+ }
+ const newTarget = []; //x coordinate
+ let el = false;
+ if (typeof target === 'string') {
+ el = document.getElementById(target.substr(1));
+ if (!el) {
+ el = document.getElementById(target);
+ }
+ } else {
+ newTarget.push(target[0]);
+ if (target[1] + topOffset > 0) {
+ newTarget.push(target[1] + topOffset);
+ } else {
+ newTarget.push(0);
+ }
+ }
+
+ if (el) {
const documentInfo = {
scrollHeight: document.body.scrollHeight,
scrollTop: Math.ceil(document.scrollingElement.scrollTop),
- scrollTarget: 0
+ scrollTarget: calcOffsetRoot(el) + topOffset,
};
- scrollTop(el, topOffset, documentInfo, SCROLL_TOP_TRIES);
+ documentInfo.direction =
+ documentInfo.scrollTop < documentInfo.scrollTarget
+ ? SCROLL_DIRECTION_DOWN
+ : SCROLL_DIRECTION_UP;
+ scrollTop(el, topOffset, documentInfo, SCROLL_TOP_TRIES); //this function does the actual work of scrolling.
} else {
- super.scrollToTarget(element, target);
+ super.scrollToTarget(element, newTarget);
}
}
}
@@ -111,24 +208,31 @@ const sagaMiddleware = createSagaMiddleware(
let middleware;
if (process.env.BROWSER && process.env.NODE_ENV === 'development') {
- const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; // eslint-disable-line no-underscore-dangle
- middleware = composeEnhancers(
- applyMiddleware(sagaMiddleware)
- );
+ const composeEnhancers =
+ window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; // eslint-disable-line no-underscore-dangle
+ middleware = composeEnhancers(applyMiddleware(sagaMiddleware));
} else {
middleware = applyMiddleware(sagaMiddleware);
}
const runRouter = (location, routes) => {
- return new Promise((resolve) =>
- match({routes, location}, (...args) => resolve(args)));
+ return new Promise(resolve =>
+ match({ routes, location }, (...args) => resolve(args))
+ );
};
-const onRouterError = (error) => {
+const onRouterError = error => {
console.error('onRouterError', error);
};
-async function universalRender({ location, initial_state, offchain, ErrorPage, tarantool, userPreferences }) {
+async function universalRender({
+ location,
+ initial_state,
+ offchain,
+ ErrorPage,
+ tarantool,
+ userPreferences,
+}) {
let error, redirect, renderProps;
try {
[error, redirect, renderProps] = await runRouter(location, RootRoute);
@@ -137,7 +241,9 @@ async function universalRender({ location, initial_state, offchain, ErrorPage, t
return {
title: 'Routing error - Steemit',
statusCode: 500,
- body: renderToString(ErrorPage ? : Routing error )
+ body: renderToString(
+ ErrorPage ? : Routing error
+ ),
};
}
if (error || !renderProps) {
@@ -145,46 +251,63 @@ async function universalRender({ location, initial_state, offchain, ErrorPage, t
return {
title: 'Page Not Found - Steemit',
statusCode: 404,
- body: renderToString( )
+ body: renderToString( ),
};
}
if (process.env.BROWSER) {
const store = createStore(rootReducer, initial_state, middleware);
- sagaMiddleware.run(PollDataSaga).done
- .then(() => console.log('PollDataSaga is finished'))
- .catch(err => console.log('PollDataSaga is finished with error', err));
const history = syncHistoryWithStore(browserHistory, store);
+ /**
+ * When to scroll - on hash link navigation determine if the page should scroll to that element (forward nav, or ignore nav direction)
+ */
const scroll = useScroll({
- createScrollBehavior: config => new OffsetScrollBehavior(config),
- shouldUpdateScroll: (prevLocation, {location}) => { // eslint-disable-line no-shadow
- //we want to navigate to the corresponding id= element on 'PUSH' navigation (prev null + POP is a new window url nav ~= 'PUSH')
- if(location.hash) {
- if((prevLocation === null && location.action === 'POP')
- || (location.action === 'PUSH')
+ createScrollBehavior: config => new OffsetScrollBehavior(config), //information assembler for has scrolling.
+ shouldUpdateScroll: (prevLocation, { location }) => {
+ // eslint-disable-line no-shadow
+ //if there is a hash, we may want to scroll to it
+ if (location.hash) {
+ //if disableNavDirectionCheck exists, we want to always navigate to the hash (the page is telling us that's desired behavior based on the element's existence
+ const disableNavDirectionCheck = document.getElementById(
+ DISABLE_ROUTER_HISTORY_NAV_DIRECTION_EL_ID
+ );
+ //we want to navigate to the corresponding id= element on 'PUSH' navigation (prev null + POP is a new window url nav ~= 'PUSH')
+ if (
+ disableNavDirectionCheck ||
+ (prevLocation === null && location.action === 'POP') ||
+ location.action === 'PUSH'
) {
return location.hash;
}
}
return true;
- }
+ },
});
if (process.env.NODE_ENV === 'production') {
- console.log('%c%s', 'color: red; background: yellow; font-size: 24px;', 'WARNING!');
- console.log('%c%s', 'color: black; font-size: 16px;', 'This is a developer console, you must read and understand anything you paste or type here or you could compromise your account and your private keys.');
+ console.log(
+ '%c%s',
+ 'color: red; background: yellow; font-size: 24px;',
+ 'WARNING!'
+ );
+ console.log(
+ '%c%s',
+ 'color: black; font-size: 16px;',
+ 'This is a developer console, you must read and understand anything you paste or type here or you could compromise your account and your private keys.'
+ );
}
return render(
-
-
-
+
+
+
,
document.getElementById('content')
);
@@ -196,16 +319,27 @@ async function universalRender({ location, initial_state, offchain, ErrorPage, t
let url = location === '/' ? 'trending' : location;
// Replace /curation-rewards and /author-rewards with /transfers for UserProfile
// to resolve data correctly
- if (url.indexOf('/curation-rewards') !== -1) url = url.replace(/\/curation-rewards$/, '/transfers');
- if (url.indexOf('/author-rewards') !== -1) url = url.replace(/\/author-rewards$/, '/transfers');
+ if (url.indexOf('/curation-rewards') !== -1)
+ url = url.replace(/\/curation-rewards$/, '/transfers');
+ if (url.indexOf('/author-rewards') !== -1)
+ url = url.replace(/\/author-rewards$/, '/transfers');
- onchain = await api.getStateAsync(url);
+ if (process.env.OFFLINE_SSR_TEST) {
+ onchain = get_state_perf;
+ } else {
+ onchain = await api.getStateAsync(url);
+ }
- if (Object.getOwnPropertyNames(onchain.accounts).length === 0 && (url.match(routeRegex.UserProfile1) || url.match(routeRegex.UserProfile3))) { // protect for invalid account
+ if (
+ Object.getOwnPropertyNames(onchain.accounts).length === 0 &&
+ (url.match(routeRegex.UserProfile1) ||
+ url.match(routeRegex.UserProfile3))
+ ) {
+ // protect for invalid account
return {
title: 'User Not Found - Steemit',
statusCode: 404,
- body: renderToString( )
+ body: renderToString( ),
};
}
@@ -214,50 +348,68 @@ async function universalRender({ location, initial_state, offchain, ErrorPage, t
for (var key in onchain.content) {
//onchain.content[key]['body'] = onchain.content[key]['body'].substring(0, 1024) // TODO: can be removed. will be handled by steemd
// Count some stats then remove voting data. But keep current user's votes. (#1040)
- onchain.content[key]['stats'] = contentStats(onchain.content[key])
- onchain.content[key]['active_votes'] = onchain.content[key]['active_votes'].filter(vote => vote.voter === offchain.account)
+ onchain.content[key]['stats'] = contentStats(
+ onchain.content[key]
+ );
+ onchain.content[key]['active_votes'] = onchain.content[key][
+ 'active_votes'
+ ].filter(vote => vote.voter === offchain.account);
}
}
- if (!url.match(routeRegex.PostsIndex) && !url.match(routeRegex.UserProfile1) && !url.match(routeRegex.UserProfile2) && url.match(routeRegex.PostNoCategory)) {
- const params = url.substr(2, url.length - 1).split("/");
- const content = await api.getContentAsync(params[0], params[1]);
- if (content.author && content.permlink) { // valid short post url
+ if (
+ !url.match(routeRegex.PostsIndex) &&
+ !url.match(routeRegex.UserProfile1) &&
+ !url.match(routeRegex.UserProfile2) &&
+ url.match(routeRegex.PostNoCategory)
+ ) {
+ const params = url.substr(2, url.length - 1).split('/');
+ let content;
+ if (process.env.OFFLINE_SSR_TEST) {
+ content = get_content_perf;
+ } else {
+ content = await api.getContentAsync(params[0], params[1]);
+ }
+ if (content.author && content.permlink) {
+ // valid short post url
onchain.content[url.substr(2, url.length - 1)] = content;
- } else { // protect on invalid user pages (i.e /user/transferss)
+ } else {
+ // protect on invalid user pages (i.e /user/transferss)
return {
title: 'Page Not Found - Steemit',
statusCode: 404,
- body: renderToString( )
+ body: renderToString( ),
};
}
}
// Calculate signup bonus
const fee = parseFloat($STM_Config.registrar_fee.split(' ')[0]),
- {base, quote} = onchain.feed_price,
- feed = parseFloat(base.split(' ')[0]) / parseFloat(quote.split(' ')[0]);
+ { base, quote } = onchain.feed_price,
+ feed =
+ parseFloat(base.split(' ')[0]) /
+ parseFloat(quote.split(' ')[0]);
const sd = fee * feed;
let sdDisp;
if (sd < 1.0) {
sdDisp = '¢' + parseInt(sd * 100);
} else {
- const sdInt = parseInt(sd), sdDec = (sd - sdInt);
+ const sdInt = parseInt(sd),
+ sdDec = sd - sdInt;
sdDisp = '$' + sdInt + (sdInt < 5 && sdDec >= 0.5 ? '.50' : '');
}
offchain.signup_bonus = sdDisp;
offchain.server_location = location;
- server_store = createStore(rootReducer, { global: onchain, offchain});
- server_store.dispatch({type: '@@router/LOCATION_CHANGE', payload: {pathname: location}});
- server_store.dispatch({type: 'SET_USER_PREFERENCES', payload: userPreferences});
- if (offchain.account) {
- try {
- const notifications = await tarantool.select('notifications', 0, 1, 0, 'eq', offchain.account);
- server_store.dispatch({type: 'UPDATE_NOTIFICOUNTERS', payload: notificationsArrayToMap(notifications)});
- } catch(e) {
- console.warn('WARNING! cannot retrieve notifications from tarantool in universalRender:', e.message);
- }
- }
+ server_store = createStore(rootReducer, {
+ app: initial_state.app,
+ global: onchain,
+ offchain,
+ });
+ server_store.dispatch({
+ type: '@@router/LOCATION_CHANGE',
+ payload: { pathname: location },
+ });
+ server_store.dispatch(appActions.setUserPreferences(userPreferences));
} catch (e) {
// Ensure 404 page when username not found
if (location.match(routeRegex.UserProfile1)) {
@@ -265,9 +417,9 @@ async function universalRender({ location, initial_state, offchain, ErrorPage, t
return {
title: 'Page Not Found - Steemit',
statusCode: 404,
- body: renderToString( )
+ body: renderToString( ),
};
- // Ensure error page on state exception
+ // Ensure error page on state exception
} else {
const msg = (e.toString && e.toString()) || e.message || e;
const stack_trace = e.stack || '[no stack]';
@@ -275,7 +427,7 @@ async function universalRender({ location, initial_state, offchain, ErrorPage, t
return {
title: 'Server error - Steemit',
statusCode: 500,
- body: renderToString( )
+ body: renderToString( ),
};
}
}
@@ -285,7 +437,7 @@ async function universalRender({ location, initial_state, offchain, ErrorPage, t
app = renderToString(
-
+
);
@@ -302,7 +454,7 @@ async function universalRender({ location, initial_state, offchain, ErrorPage, t
titleBase: 'Steemit - ',
meta,
statusCode: status,
- body: Iso.render(app, server_store.getState())
+ body: Iso.render(app, server_store.getState()),
};
}
diff --git a/src/shared/api_client/ChainConfig.js b/src/shared/api_client/ChainConfig.js
index 52a975d5cd2ade6a42fdd0bf35d746825004b119..15b8689578b76a93e1512cfb01f74125209085ac 100644
--- a/src/shared/api_client/ChainConfig.js
+++ b/src/shared/api_client/ChainConfig.js
@@ -1,12 +1,12 @@
-import * as steem from 'steem'
+import * as steem from '@steemit/steem-js';
-steem.config.set('address_prefix', 'STM')
+steem.config.set('address_prefix', 'STM');
-let chain_id = ""
-for(let i = 0; i < 32; i++) chain_id += "00"
+let chain_id = '';
+for (let i = 0; i < 32; i++) chain_id += '00';
module.exports = {
- address_prefix: "STM",
+ address_prefix: 'STM',
expire_in_secs: 15,
- chain_id
-}
+ chain_id,
+};
diff --git a/src/shared/api_client/index.js b/src/shared/api_client/index.js
index 91a6a9a4cbbcd955487921ee7fff3c158f3a8f4c..c235190de58a497eef33871c0e74710389047318 100644
--- a/src/shared/api_client/index.js
+++ b/src/shared/api_client/index.js
@@ -1,5 +1,5 @@
-import ChainConfig from "./ChainConfig"
+import ChainConfig from './ChainConfig';
module.exports = {
- ChainConfig
-}
+ ChainConfig,
+};
diff --git a/src/shared/clash/object2json.js b/src/shared/clash/object2json.js
index 9b13becc53a7ce10d7dd4b4bfab5a5296948e372..9e6ea453a0de556ad8f73e44363886ab7f66b9b1 100644
--- a/src/shared/clash/object2json.js
+++ b/src/shared/clash/object2json.js
@@ -1,31 +1,33 @@
const expo = {
- ifObjectToJSON: (item) => {
- if (typeof item==='object') {
- try {
- return JSON.stringify(item);
- } catch(e) {return item;}
- }
- return item;
- },
-
- ifStringParseJSON: (item) => {
- if (typeof item==='string') {
- try {
- return JSON.parse(item);
- } catch (e) {
+ ifObjectToJSON: item => {
+ if (typeof item === 'object') {
+ try {
+ return JSON.stringify(item);
+ } catch (e) {
+ return item;
+ }
+ }
return item;
- }
- }
- return item;
- }
-}
-export {expo as default}
+ },
+ ifStringParseJSON: item => {
+ if (typeof item === 'string') {
+ try {
+ return JSON.parse(item);
+ } catch (e) {
+ return item;
+ }
+ }
+ return item;
+ },
+};
+export { expo as default };
exports.test = {
- run: () => {
- let ob ={a: 2}, st='{"a":2}'
- console.log ("test eq1", expo.ifObjectToJSON(ob) == st);
- console.log ("test eq2", expo.ifStringParseJSON(st).a == ob.a);
- }
-}
+ run: () => {
+ let ob = { a: 2 },
+ st = '{"a":2}';
+ console.log('test eq1', expo.ifObjectToJSON(ob) == st);
+ console.log('test eq2', expo.ifStringParseJSON(st).a == ob.a);
+ },
+};
diff --git a/src/shared/constants.js b/src/shared/constants.js
new file mode 100644
index 0000000000000000000000000000000000000000..7afcc39ef86e14bbe17a28137a9dc89889c7795b
--- /dev/null
+++ b/src/shared/constants.js
@@ -0,0 +1,4 @@
+export const PARAM_VIEW_MODE = 'view_mode';
+export const VIEW_MODE_WHISTLE = 'whistle';
+export const WHISTLE_SIGNUP_COMPLETE = 'whistle_signup_complete';
+export const SIGNUP_URL = 'https://signup.steemit.com';
diff --git a/webpack/base.config.js b/webpack/base.config.js
index c02db30b944861e72b226dd0c0bd954fc4087e87..35d6a8e3220df146b8a8331fb2ef35e435b1f288 100644
--- a/webpack/base.config.js
+++ b/webpack/base.config.js
@@ -1,7 +1,7 @@
-import path from 'path';
-import webpack from 'webpack';
-import ExtractTextPlugin from 'extract-text-webpack-plugin';
-import writeStats from './utils/write-stats';
+const path = require('path');
+const webpack = require('webpack');
+const ExtractTextPlugin = require('extract-text-webpack-plugin');
+const writeStats = require('./utils/write-stats');
const Webpack_isomorphic_tools_plugin = require('webpack-isomorphic-tools/plugin');
const webpack_isomorphic_tools_plugin =
@@ -32,14 +32,14 @@ const scss_loaders = [
}
]
-export default {
+module.exports = {
entry: {
app: ['babel-polyfill', './src/app/Main.js'],
vendor: [
'react',
'react-dom',
'react-router',
- 'steem',
+ '@steemit/steem-js',
'bytebuffer',
'immutable',
'autolinker',
@@ -64,10 +64,6 @@ export default {
test: require.resolve("blueimp-file-upload"),
use: "imports?define=>false"
},
- {
- test: require.resolve("medium-editor-insert-plugin"),
- use: "imports?define=>false"
- },
{
test: /\.css$/,
use: css_loaders
diff --git a/webpack/debug.config.js b/webpack/debug.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..2f6f468d7b8d40c4f42377dda7c7b6e2b01d01e1
--- /dev/null
+++ b/webpack/debug.config.js
@@ -0,0 +1,28 @@
+const webpack = require('webpack');
+const git = require('git-rev-sync');
+const baseConfig = require('./base.config');
+
+module.exports = {
+ ...baseConfig,
+ devtool: 'cheap-module-eval-source-map',
+ output: {
+ ...baseConfig.output,
+ publicPath: '/assets/',
+ },
+ module: {
+ ...baseConfig.module,
+ rules: [
+ ...baseConfig.module.rules,
+ ],
+ },
+ plugins: [
+ new webpack.DefinePlugin({
+ 'process.env': {
+ BROWSER: JSON.stringify(true),
+ NODE_ENV: JSON.stringify('development'),
+ VERSION: JSON.stringify(git.long()),
+ }
+ }),
+ ...baseConfig.plugins,
+ ],
+};
diff --git a/webpack/dev-server.js b/webpack/dev-server.js
index 72b99236027f151772b588e6d1f97f66ddbde5fe..29a4b367ac3178e0fb3e87ca7b75fc55a7496117 100644
--- a/webpack/dev-server.js
+++ b/webpack/dev-server.js
@@ -5,10 +5,10 @@ if(!fs.existsSync('tmp'))
process.env.BABEL_ENV = 'browser';
process.env.NODE_ENV = 'development';
-import Koa from 'koa';
-import webpack from 'webpack';
+const Koa = require('koa');
+const webpack = require('webpack');
-import webpackDevConfig from './dev.config';
+const webpackDevConfig = require('./dev.config');
const app = new Koa();
const compiler = webpack(webpackDevConfig);
diff --git a/webpack/dev.config.js b/webpack/dev.config.js
index 360115391f60d78b60fbd1bf6f54877036bd39dc..95f98c61b0e8e07158e7439fd9c22db97e9273bc 100644
--- a/webpack/dev.config.js
+++ b/webpack/dev.config.js
@@ -1,12 +1,12 @@
-import webpack from 'webpack';
-import git from 'git-rev-sync';
-import baseConfig from './base.config';
-import startKoa from './utils/start-koa';
+const webpack = require('webpack');
+const git = require('git-rev-sync');
+const baseConfig = require('./base.config');
+const startKoa = require('./utils/start-koa');
// var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// baseConfig.plugins.push(new BundleAnalyzerPlugin());
-export default {
+module.exports = {
...baseConfig,
devtool: 'cheap-module-eval-source-map',
output: {
@@ -25,9 +25,6 @@ export default {
BROWSER: JSON.stringify(true),
NODE_ENV: JSON.stringify('development'),
VERSION: JSON.stringify(git.long())
- },
- global: {
- TYPED_ARRAY_SUPPORT: JSON.stringify(false)
}
}),
...baseConfig.plugins,
diff --git a/webpack/prod.config.js b/webpack/prod.config.js
index 1111e109a94fe2094a21bfafe5d117cf9394364c..8c63e4874d76e5efadd6118062171be5b24fb99a 100644
--- a/webpack/prod.config.js
+++ b/webpack/prod.config.js
@@ -1,8 +1,8 @@
-import webpack from 'webpack';
-import git from 'git-rev-sync';
-import baseConfig from './base.config';
+const webpack = require('webpack');
+const git = require('git-rev-sync');
+const baseConfig = require('./base.config');
-export default {
+module.exports = {
...baseConfig,
plugins: [
new webpack.DefinePlugin({
@@ -10,9 +10,6 @@ export default {
BROWSER: JSON.stringify(true),
NODE_ENV: JSON.stringify('production'),
VERSION: JSON.stringify(git.long())
- },
- global: {
- TYPED_ARRAY_SUPPORT: JSON.stringify(false)
}
}),
new webpack.optimize.UglifyJsPlugin({
@@ -37,6 +34,13 @@ export default {
comments: false
}
}),
- ...baseConfig.plugins
+ ...baseConfig.plugins,
+ // Fix window.onerror
+ // See https://github.com/webpack/webpack/issues/5681#issuecomment-345861733
+ new webpack.SourceMapDevToolPlugin({
+ module: true,
+ columns: false,
+ moduleFilenameTemplate: info => { return `${info.resourcePath}?${info.loaders}` }
+ })
]
};
diff --git a/webpack/storybook.config.js b/webpack/storybook.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..c2d25a59d1b078f9c44886f209ea11b7f622f161
--- /dev/null
+++ b/webpack/storybook.config.js
@@ -0,0 +1,85 @@
+import path from 'path';
+import ExtractTextPlugin from 'extract-text-webpack-plugin';
+import genDefaultConfig from '@storybook/react/dist/server/config/defaults/webpack.config.js';
+import webpack from 'webpack';
+
+const css_loaders = [
+ {
+ loader: 'style-loader',
+ },
+ {
+ loader: 'css-loader',
+ },
+ {
+ loader: 'autoprefixer-loader'
+ }
+];
+
+const scss_loaders = [
+ {
+ loader: 'css-loader',
+ },
+ {
+ loader: 'autoprefixer-loader'
+ },
+ {
+ loader: 'sass-loader',
+ options: {
+ sourceMap: true,
+ data: '@import "app";',
+ includePaths: [
+ path.join(__dirname, '../src/app/assets/stylesheets'),
+ ]
+ }
+ },
+];
+
+module.exports = (baseConfig, env) => {
+ const config = genDefaultConfig(baseConfig, env);
+ config.resolve = {
+ alias: {
+ react: path.join(__dirname, '../node_modules', 'react'),
+ assets: path.join(__dirname, '../src/app/assets'),
+ decorators: path.join(__dirname, '../.storybook/decorators')
+ },
+ extensions: ['.js', '.json', '.jsx'],
+ modules: [
+ path.resolve(__dirname, '../src'),
+ 'node_modules'
+ ]
+ };
+ config.plugins.push( new ExtractTextPlugin('[name]-[chunkhash].css'));
+ config.plugins.push(new webpack.DefinePlugin({
+ 'process.env': {
+ BROWSER: JSON.stringify(true),
+ }
+ }));
+ config.module = {
+ rules: [
+ {test: /\.(jpe?g|png)/, use: 'url-loader?limit=4096'},
+ {test: /\.json$/, use: 'json-loader'},
+ {test: /\.js$|\.jsx$/, exclude: /node_modules/, use: 'babel-loader'},
+ {test: /\.svg$/, use: 'svg-inline-loader'},
+ {
+ test: require.resolve("blueimp-file-upload"),
+ use: "imports?define=>false"
+ },
+ {
+ test: /\.css$/,
+ use: css_loaders
+ },
+ {
+ test: /\.scss$/,
+ use: ExtractTextPlugin.extract({
+ fallback: 'style-loader',
+ use: scss_loaders
+ })
+ },
+ {
+ test: /\.md/,
+ use: 'raw-loader'
+ }
+ ]
+ };
+ return config;
+};
diff --git a/webpack/utils/start-koa.js b/webpack/utils/start-koa.js
index 0fbb6458e5995c6802b1ef0c7947cb646b917688..f871e92ee199e52a74f2bce33400b454ca5590ac 100644
--- a/webpack/utils/start-koa.js
+++ b/webpack/utils/start-koa.js
@@ -1,6 +1,6 @@
-import cp from 'child_process';
-import path from 'path';
-import watch from 'node-watch';
+const cp = require('child_process');
+const path = require('path');
+const watch = require('node-watch');
let server;
let started;
@@ -50,4 +50,7 @@ const startServer = () => {
// kill server on exit
process.on('exit', () => server.kill('SIGTERM'));
-export default () => !server ? startServer() : () => ({});
+
+module.exports = function () {
+ return !server ? startServer() : () => ({});
+};
diff --git a/webpack/utils/write-stats.js b/webpack/utils/write-stats.js
index 249c584fa9c686307c3f1744b1254de68cdb2aee..354e61af650b660706e4e233cfb00227811d1295 100644
--- a/webpack/utils/write-stats.js
+++ b/webpack/utils/write-stats.js
@@ -1,8 +1,8 @@
// borrowed from https://github.com/gpbl/isomorphic500/blob/master/webpack%2Futils%2Fwrite-stats.js
-import fs from 'fs';
-import path from 'path';
+const fs = require('fs');
+const path = require('path');
-export default function (stats) {
+module.exports = function (stats) {
const publicPath = this.options.output.publicPath;
const json = stats.toJson();
diff --git a/yarn.lock b/yarn.lock
index 5d26d1548987a1f5d309010406de23ce41b3b8a0..0b56d1c6c9ddd312cabf2a405e5d97598a28c5ad 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,6 +2,14 @@
# yarn lockfile v1
+"@babel/code-frame@^7.0.0-beta.35":
+ version "7.0.0-beta.39"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.39.tgz#91c90bb65207fc5a55128cb54956ded39e850457"
+ dependencies:
+ chalk "^2.0.0"
+ esutils "^2.0.2"
+ js-tokens "^3.0.0"
+
"@steem/crypto-session@git+https://github.com/steemit/crypto-session.git#83a90b319ce5bc6a70362d52a15a815de7e729bb":
version "1.0.3"
resolved "git+https://github.com/steemit/crypto-session.git#83a90b319ce5bc6a70362d52a15a815de7e729bb"
@@ -10,11 +18,231 @@
libsodium "^0.4.8"
libsodium-wrappers "^0.4.8"
+"@steemit/libcrypto@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@steemit/libcrypto/-/libcrypto-1.0.1.tgz#c31ab3e5deb667628169b3d54d746b015de31a79"
+
+"@steemit/rpc-auth@^1.1.0":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@steemit/rpc-auth/-/rpc-auth-1.1.1.tgz#8f6239e89783d2b251b49e9e1b9486b5d167f944"
+ dependencies:
+ "@steemit/libcrypto" "^1.0.1"
+
+"@steemit/steem-js@0.7.1":
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/@steemit/steem-js/-/steem-js-0.7.1.tgz#9e9ead34ce9438513ad49e8f7d4d48d32d9c3c39"
+ dependencies:
+ "@steemit/rpc-auth" "^1.1.0"
+ bigi "^1.4.2"
+ bluebird "^3.4.6"
+ browserify-aes "^1.0.6"
+ bs58 "^4.0.0"
+ buffer "^5.0.6"
+ bytebuffer "^5.0.1"
+ create-hash "^1.1.2"
+ create-hmac "^1.1.4"
+ cross-env "^5.0.0"
+ cross-fetch "^1.1.1"
+ debug "^2.6.8"
+ detect-node "^2.0.3"
+ ecurve "^1.0.5"
+ lodash "^4.16.4"
+ secure-random "^1.1.1"
+ ws "^3.3.2"
+
+"@storybook/addon-actions@^3.2.19":
+ version "3.3.12"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-3.3.12.tgz#1bd2668918a62f32c0907af14946cdd0c6be66f5"
+ dependencies:
+ deep-equal "^1.0.1"
+ global "^4.3.2"
+ make-error "^1.3.2"
+ prop-types "^15.6.0"
+ react-inspector "^2.2.2"
+ uuid "^3.1.0"
+
+"@storybook/addon-knobs@3.2.19":
+ version "3.2.19"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-knobs/-/addon-knobs-3.2.19.tgz#ac9aeb3f7853dfe6bea4ae41e4ccbac22434bda9"
+ dependencies:
+ "@storybook/addons" "^3.2.19"
+ babel-runtime "^6.26.0"
+ deep-equal "^1.0.1"
+ global "^4.3.2"
+ insert-css "^2.0.0"
+ lodash.debounce "^4.0.8"
+ moment "^2.20.1"
+ prop-types "^15.6.0"
+ react-color "^2.11.4"
+ react-datetime "^2.11.1"
+ react-textarea-autosize "^5.2.1"
+ util-deprecate "^1.0.2"
+
+"@storybook/addon-links@^3.2.19":
+ version "3.3.12"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-3.3.12.tgz#e1bb6e207506a45bea9e5f64cd78c045327412b7"
+ dependencies:
+ "@storybook/components" "^3.3.12"
+ global "^4.3.2"
+ prop-types "^15.5.10"
+
+"@storybook/addons@^3.2.19":
+ version "3.3.12"
+ resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-3.3.12.tgz#682927b5ac4baad796922eec505a7e956a3f79d9"
+
+"@storybook/channel-postmessage@^3.2.19":
+ version "3.3.12"
+ resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-3.3.12.tgz#a4e7ac32ff84d2cc41bf3a5f30608ce5f82bcf82"
+ dependencies:
+ "@storybook/channels" "^3.3.12"
+ global "^4.3.2"
+ json-stringify-safe "^5.0.1"
+
+"@storybook/channels@^3.3.12":
+ version "3.3.12"
+ resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-3.3.12.tgz#aa4106888971f9e689511093b0e6f2b569973a09"
+
+"@storybook/components@^3.3.12":
+ version "3.3.12"
+ resolved "https://registry.yarnpkg.com/@storybook/components/-/components-3.3.12.tgz#e2571ca7150488f4ac3fa1cd1f70fa91ce38da8b"
+ dependencies:
+ glamor "^2.20.40"
+ glamorous "^4.11.2"
+ prop-types "^15.6.0"
+
+"@storybook/mantra-core@^1.7.2":
+ version "1.7.2"
+ resolved "https://registry.yarnpkg.com/@storybook/mantra-core/-/mantra-core-1.7.2.tgz#e10c7faca29769e97131e0e0308ef7cfb655b70c"
+ dependencies:
+ "@storybook/react-komposer" "^2.0.1"
+ "@storybook/react-simple-di" "^1.2.1"
+ babel-runtime "6.x.x"
+
+"@storybook/react-komposer@^2.0.1", "@storybook/react-komposer@^2.0.3":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@storybook/react-komposer/-/react-komposer-2.0.3.tgz#f9e12a9586b2ce95c24c137eabb8b71527ddb369"
+ dependencies:
+ "@storybook/react-stubber" "^1.0.0"
+ babel-runtime "^6.11.6"
+ hoist-non-react-statics "^1.2.0"
+ lodash.pick "^4.4.0"
+ shallowequal "^0.2.2"
+
+"@storybook/react-simple-di@^1.2.1":
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/@storybook/react-simple-di/-/react-simple-di-1.3.0.tgz#13116d89a2f42898716a7f8c4095b47415526371"
+ dependencies:
+ babel-runtime "6.x.x"
+ create-react-class "^15.6.2"
+ hoist-non-react-statics "1.x.x"
+ prop-types "^15.6.0"
+
+"@storybook/react-stubber@^1.0.0":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@storybook/react-stubber/-/react-stubber-1.0.1.tgz#8c312c2658b9eeafce470e1c39e4193f0b5bf9b1"
+ dependencies:
+ babel-runtime "^6.5.0"
+
+"@storybook/react@3.2.19":
+ version "3.2.19"
+ resolved "https://registry.yarnpkg.com/@storybook/react/-/react-3.2.19.tgz#3a609ccf6b0608cec9c6dfe76494e3721efe2fc3"
+ dependencies:
+ "@storybook/addon-actions" "^3.2.19"
+ "@storybook/addon-links" "^3.2.19"
+ "@storybook/addons" "^3.2.19"
+ "@storybook/channel-postmessage" "^3.2.19"
+ "@storybook/ui" "^3.2.19"
+ airbnb-js-shims "^1.4.0"
+ autoprefixer "^7.2.3"
+ babel-loader "^7.1.2"
+ babel-plugin-react-docgen "^1.8.0"
+ babel-plugin-transform-regenerator "^6.26.0"
+ babel-plugin-transform-runtime "^6.23.0"
+ babel-preset-env "^1.6.1"
+ babel-preset-minify "^0.2.0"
+ babel-preset-react "^6.24.1"
+ babel-preset-react-app "^3.1.0"
+ babel-preset-stage-0 "^6.24.1"
+ babel-runtime "^6.26.0"
+ case-sensitive-paths-webpack-plugin "^2.1.1"
+ chalk "^2.3.0"
+ commander "^2.12.2"
+ common-tags "^1.6.0"
+ configstore "^3.1.1"
+ core-js "^2.5.3"
+ css-loader "^0.28.7"
+ dotenv-webpack "^1.5.4"
+ express "^4.16.2"
+ file-loader "^1.1.6"
+ find-cache-dir "^1.0.0"
+ glamor "^2.20.40"
+ glamorous "^4.11.2"
+ global "^4.3.2"
+ json-loader "^0.5.7"
+ json-stringify-safe "^5.0.1"
+ json5 "^0.5.1"
+ lodash.flattendeep "^4.4.0"
+ postcss-flexbugs-fixes "^3.2.0"
+ postcss-loader "^2.0.9"
+ prop-types "^15.6.0"
+ qs "^6.5.1"
+ redux "^3.7.2"
+ request "^2.83.0"
+ serve-favicon "^2.4.5"
+ shelljs "^0.7.8"
+ style-loader "^0.19.1"
+ url-loader "^0.6.2"
+ util-deprecate "^1.0.2"
+ uuid "^3.1.0"
+ webpack "^3.10.0"
+ webpack-dev-middleware "^1.12.2"
+ webpack-hot-middleware "^2.21.0"
+
+"@storybook/ui@^3.2.19":
+ version "3.3.12"
+ resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-3.3.12.tgz#b0a9cd83423c4d6cded0a0340fc4f48d5bdf3bc0"
+ dependencies:
+ "@storybook/components" "^3.3.12"
+ "@storybook/mantra-core" "^1.7.2"
+ "@storybook/react-komposer" "^2.0.3"
+ babel-runtime "^6.26.0"
+ deep-equal "^1.0.1"
+ events "^1.1.1"
+ fuse.js "^3.2.0"
+ global "^4.3.2"
+ json-stringify-safe "^5.0.1"
+ keycode "^2.1.9"
+ lodash.debounce "^4.0.8"
+ lodash.pick "^4.4.0"
+ lodash.sortby "^4.7.0"
+ podda "^1.2.2"
+ prop-types "^15.6.0"
+ qs "^6.5.1"
+ react-fuzzy "^0.5.1"
+ react-icons "^2.2.7"
+ react-inspector "^2.2.2"
+ react-modal "^3.1.10"
+ react-split-pane "^0.1.74"
+ react-treebeard "^2.1.0"
+ redux "^3.7.2"
+
"@types/geojson@^1.0.0":
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-1.0.5.tgz#ef9f12277233399c7f32086818a56a84c8952f8f"
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-1.0.6.tgz#3e02972728c69248c2af08d60a48cbb8680fffdf"
+
+"@types/inline-style-prefixer@^3.0.0":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/inline-style-prefixer/-/inline-style-prefixer-3.0.1.tgz#8541e636b029124b747952e9a28848286d2b5bf6"
-abab@^1.0.3:
+"@types/node@*":
+ version "9.4.0"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.0.tgz#b85a0bcf1e1cc84eb4901b7e96966aedc6f078d1"
+
+"@types/react@^16.0.18":
+ version "16.0.36"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-16.0.36.tgz#ceb5639013bdb92a94147883052e69bb2c22c69b"
+
+abab@^1.0.3, abab@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e"
@@ -41,6 +269,12 @@ acorn-globals@^3.1.0:
dependencies:
acorn "^4.0.4"
+acorn-globals@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538"
+ dependencies:
+ acorn "^5.0.0"
+
acorn-jsx@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
@@ -55,17 +289,40 @@ acorn@^4.0.3, acorn@^4.0.4:
version "4.0.13"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
-acorn@^5.0.0, acorn@^5.1.1:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7"
+acorn@^5.0.0, acorn@^5.1.1, acorn@^5.3.0, acorn@^5.4.0:
+ version "5.4.1"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.4.1.tgz#fdc58d9d17f4a4e98d102ded826a9b9759125102"
addressparser@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746"
+agent-base@^4.1.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce"
+ dependencies:
+ es6-promisify "^5.0.0"
+
+airbnb-js-shims@^1.4.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-1.4.1.tgz#cc3e8eb8d35877f9d0fdc6583e26b0ee75b98ad0"
+ dependencies:
+ array-includes "^3.0.3"
+ array.prototype.flatmap "^1.2.0"
+ array.prototype.flatten "^1.2.0"
+ es5-shim "^4.5.10"
+ es6-shim "^0.35.3"
+ function.prototype.name "^1.1.0"
+ object.entries "^1.0.4"
+ object.getownpropertydescriptors "^2.0.3"
+ object.values "^1.0.4"
+ promise.prototype.finally "^3.1.0"
+ string.prototype.padend "^3.0.0"
+ string.prototype.padstart "^3.0.0"
+
ajv-keywords@^2.0.0, ajv-keywords@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.0.tgz#a296e17f7bfae7c1ce4f7e0de53d29cb32162df0"
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762"
ajv@^4.9.1:
version "4.11.8"
@@ -75,13 +332,13 @@ ajv@^4.9.1:
json-stable-stringify "^1.0.1"
ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5, ajv@^5.2.0, ajv@^5.2.3:
- version "5.2.3"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.3.tgz#c06f598778c44c6b161abafe3466b81ad1814ed2"
+ version "5.5.2"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
dependencies:
co "^4.6.0"
fast-deep-equal "^1.0.0"
+ fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.3.0"
- json-stable-stringify "^1.0.1"
align-text@^0.1.1, align-text@^0.1.3:
version "0.1.4"
@@ -99,6 +356,10 @@ amdefine@>=0.0.4:
version "1.0.1"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+ansi-escapes@^1.0.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+
ansi-escapes@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92"
@@ -119,12 +380,16 @@ ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
-ansi-styles@^3.1.0:
+ansi-styles@^3.1.0, ansi-styles@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88"
dependencies:
color-convert "^1.9.0"
+any-observable@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.2.0.tgz#c67870058003579009083f54ac0abafb5c33d242"
+
any-promise@^1.0.0, any-promise@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
@@ -136,14 +401,20 @@ anymatch@^1.3.0:
micromatch "^2.1.5"
normalize-path "^2.0.0"
+app-root-path@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.0.1.tgz#cd62dcf8e4fd5a417efc664d2e5b10653c651b46"
+
+append-transform@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991"
+ dependencies:
+ default-require-extensions "^1.0.0"
+
aproba@^1.0.3:
version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
-archy@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
-
are-we-there-yet@~1.1.2:
version "1.1.4"
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
@@ -165,10 +436,11 @@ argparse@~0.1.15:
underscore.string "~2.4.0"
aria-query@^0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-0.7.0.tgz#4af10a1e61573ddea0cf3b99b51c52c05b424d24"
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-0.7.1.tgz#26cbb5aff64144b0a825be1846e0b16cfa00b11e"
dependencies:
ast-types-flow "0.0.7"
+ commander "^2.11.0"
arr-diff@^2.0.0:
version "2.0.0"
@@ -180,14 +452,6 @@ arr-flatten@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
-array-differ@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031"
-
-array-each@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f"
-
array-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
@@ -196,6 +460,10 @@ array-find-index@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
+array-find@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8"
+
array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
@@ -207,17 +475,13 @@ array-includes@^3.0.3:
define-properties "^1.1.2"
es-abstract "^1.7.0"
-array-slice@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.0.0.tgz#e73034f00dcc1f40876008fd20feae77bd4b7c2f"
-
array-union@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
dependencies:
array-uniq "^1.0.1"
-array-uniq@^1.0.1, array-uniq@^1.0.2:
+array-uniq@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
@@ -225,26 +489,38 @@ array-unique@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
-arrify@^1.0.0:
+array.prototype.flatmap@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.0.tgz#279f7ed4eeb1cedfe5515e92e63cfb40ca15b74b"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.10.0"
+ function-bind "^1.1.1"
+
+array.prototype.flatten@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/array.prototype.flatten/-/array.prototype.flatten-1.2.0.tgz#e46fb18954f8796381a73755e122570647984be3"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.10.0"
+ function-bind "^1.1.1"
+
+arrify@^1.0.0, arrify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
-asap@~2.0.3:
+asap@^2.0.0, asap@~2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
asn1.js@^4.0.0, asn1.js@^4.8.1:
- version "4.9.1"
- resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40"
+ version "4.9.2"
+ resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.2.tgz#8117ef4f7ed87cd8f89044b5bff97ac243a16c9a"
dependencies:
bn.js "^4.0.0"
inherits "^2.0.1"
minimalistic-assert "^1.0.0"
-asn1@0.1.11:
- version "0.1.11"
- resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7"
-
asn1@~0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
@@ -253,28 +529,28 @@ assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
-assert-plus@^0.1.5:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160"
-
assert-plus@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
-assert@^1.1.1, assert@^1.3.0:
+assert@1.4.1, assert@^1.1.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
dependencies:
util "0.10.3"
-assertion-error@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c"
-
ast-types-flow@0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
+ast-types@0.10.1:
+ version "0.10.1"
+ resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd"
+
+astral-regex@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
+
async-each@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
@@ -349,9 +625,9 @@ async@^1.4.0:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
-async@^2.0.1, async@^2.1.2, async@^2.1.5, async@^2.4.1:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d"
+async@^2.1.2, async@^2.1.4, async@^2.1.5, async@^2.4.1:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4"
dependencies:
lodash "^4.14.0"
@@ -367,7 +643,7 @@ autolinker@~0.15.0:
version "0.15.3"
resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.15.3.tgz#342417d8f2f3461b14cf09088d5edf8791dc9832"
-autoprefixer-loader@^3.2.0:
+autoprefixer-loader@3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/autoprefixer-loader/-/autoprefixer-loader-3.2.0.tgz#39a7b6646a8269865073d958c97f486152c2c84a"
dependencies:
@@ -387,9 +663,16 @@ autoprefixer@^6.0.2, autoprefixer@^6.3.1:
postcss "^5.2.16"
postcss-value-parser "^3.2.3"
-aws-sign2@~0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63"
+autoprefixer@^7.2.3:
+ version "7.2.5"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-7.2.5.tgz#04ccbd0c6a61131b6d13f53d371926092952d192"
+ dependencies:
+ browserslist "^2.11.1"
+ caniuse-lite "^1.0.30000791"
+ normalize-range "^0.1.2"
+ num2fraction "^1.2.2"
+ postcss "^6.0.16"
+ postcss-value-parser "^3.2.3"
aws-sign2@~0.6.0:
version "0.6.0"
@@ -409,7 +692,7 @@ axobject-query@^0.1.0:
dependencies:
ast-types-flow "0.0.7"
-babel-cli@^6.22.2:
+babel-cli@6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.26.0.tgz#502ab54874d7db88ad00b887a06383ce03d002f1"
dependencies:
@@ -438,7 +721,7 @@ babel-code-frame@^6.11.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
esutils "^2.0.2"
js-tokens "^3.0.2"
-babel-core@^6.20.0, babel-core@^6.26.0:
+babel-core@6.26.0, babel-core@^6.0.0, babel-core@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8"
dependencies:
@@ -462,7 +745,7 @@ babel-core@^6.20.0, babel-core@^6.26.0:
slash "^1.0.0"
source-map "^0.5.6"
-babel-eslint@^6.0.4:
+babel-eslint@6.1.2:
version "6.1.2"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-6.1.2.tgz#5293419fe3672d66598d327da9694567ba6a5f2f"
dependencies:
@@ -472,9 +755,9 @@ babel-eslint@^6.0.4:
lodash.assign "^4.0.0"
lodash.pickby "^4.0.0"
-babel-generator@^6.26.0:
- version "6.26.0"
- resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5"
+babel-generator@^6.18.0, babel-generator@^6.26.0:
+ version "6.26.1"
+ resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90"
dependencies:
babel-messages "^6.23.0"
babel-runtime "^6.26.0"
@@ -482,7 +765,7 @@ babel-generator@^6.26.0:
detect-indent "^4.0.0"
jsesc "^1.3.0"
lodash "^4.17.4"
- source-map "^0.5.6"
+ source-map "^0.5.7"
trim-right "^1.0.1"
babel-helper-bindify-decorators@^6.24.1:
@@ -527,6 +810,10 @@ babel-helper-define-map@^6.24.1:
babel-types "^6.26.0"
lodash "^4.17.4"
+babel-helper-evaluate-path@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.2.0.tgz#0bb2eb01996c0cef53c5e8405e999fe4a0244c08"
+
babel-helper-explode-assignable-expression@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa"
@@ -544,6 +831,10 @@ babel-helper-explode-class@^6.24.1:
babel-traverse "^6.24.1"
babel-types "^6.24.1"
+babel-helper-flip-expressions@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.2.0.tgz#160d2090a3d9f9c64a750905321a0bc218f884ec"
+
babel-helper-function-name@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9"
@@ -568,6 +859,18 @@ babel-helper-hoist-variables@^6.24.1:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
+babel-helper-is-nodes-equiv@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz#34e9b300b1479ddd98ec77ea0bbe9342dfe39684"
+
+babel-helper-is-void-0@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.2.0.tgz#6ed0ada8a9b1c5b6e88af6b47c1b3b5c080860eb"
+
+babel-helper-mark-eval-scopes@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.2.0.tgz#7648aaf2ec92aae9b09a20ad91e8df5e1fcc94b2"
+
babel-helper-optimise-call-expression@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257"
@@ -593,6 +896,10 @@ babel-helper-remap-async-to-generator@^6.24.1:
babel-traverse "^6.24.1"
babel-types "^6.24.1"
+babel-helper-remove-or-void@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.2.0.tgz#8e46ad5b30560d57d7510b3fd93f332ee7c67386"
+
babel-helper-replace-supers@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a"
@@ -604,6 +911,10 @@ babel-helper-replace-supers@^6.24.1:
babel-traverse "^6.24.1"
babel-types "^6.24.1"
+babel-helper-to-multiple-sequence-expressions@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.2.0.tgz#d1a419634c6cb301f27858c659167cfee0a9d318"
+
babel-helpers@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2"
@@ -611,7 +922,21 @@ babel-helpers@^6.24.1:
babel-runtime "^6.22.0"
babel-template "^6.24.1"
-babel-loader@^7.1.2:
+babel-jest@22.0.6:
+ version "22.0.6"
+ resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-22.0.6.tgz#807a2a5f5fad7789c57174a955cd14b11045299f"
+ dependencies:
+ babel-plugin-istanbul "^4.1.5"
+ babel-preset-jest "^22.0.6"
+
+babel-jest@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-22.1.0.tgz#7fae6f655fffe77e818a8c2868c754a42463fdfd"
+ dependencies:
+ babel-plugin-istanbul "^4.1.5"
+ babel-preset-jest "^22.1.0"
+
+babel-loader@7.1.2, babel-loader@^7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.2.tgz#f6cbe122710f1aa2af4d881c6d5b54358ca24126"
dependencies:
@@ -631,7 +956,100 @@ babel-plugin-check-es2015-constants@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-react-intl@^2.2.0:
+babel-plugin-dynamic-import-node@1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-1.1.0.tgz#bd1d88ac7aaf98df4917c384373b04d971a2b37a"
+ dependencies:
+ babel-plugin-syntax-dynamic-import "^6.18.0"
+ babel-template "^6.26.0"
+ babel-types "^6.26.0"
+
+babel-plugin-istanbul@^4.1.5:
+ version "4.1.5"
+ resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.5.tgz#6760cdd977f411d3e175bb064f2bc327d99b2b6e"
+ dependencies:
+ find-up "^2.1.0"
+ istanbul-lib-instrument "^1.7.5"
+ test-exclude "^4.1.1"
+
+babel-plugin-jest-hoist@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.1.0.tgz#c1281dd7887d77a1711dc760468c3b8285dde9ee"
+
+babel-plugin-minify-builtins@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.2.0.tgz#317f824b0907210b6348671bb040ca072e2e0c82"
+ dependencies:
+ babel-helper-evaluate-path "^0.2.0"
+
+babel-plugin-minify-constant-folding@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.2.0.tgz#8c70b528b2eb7c13e94d95c8789077d4cdbc3970"
+ dependencies:
+ babel-helper-evaluate-path "^0.2.0"
+
+babel-plugin-minify-dead-code-elimination@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.2.0.tgz#e8025ee10a1e5e4f202633a6928ce892c33747e3"
+ dependencies:
+ babel-helper-evaluate-path "^0.2.0"
+ babel-helper-mark-eval-scopes "^0.2.0"
+ babel-helper-remove-or-void "^0.2.0"
+ lodash.some "^4.6.0"
+
+babel-plugin-minify-flip-comparisons@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.2.0.tgz#0c9c8e93155c8f09dedad8118b634c259f709ef5"
+ dependencies:
+ babel-helper-is-void-0 "^0.2.0"
+
+babel-plugin-minify-guarded-expressions@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.2.0.tgz#8a8c950040fce3e258a12e6eb21eab94ad7235ab"
+ dependencies:
+ babel-helper-flip-expressions "^0.2.0"
+
+babel-plugin-minify-infinity@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.2.0.tgz#30960c615ddbc657c045bb00a1d8eb4af257cf03"
+
+babel-plugin-minify-mangle-names@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.2.0.tgz#719892297ff0106a6ec1a4b0fc062f1f8b6a8529"
+ dependencies:
+ babel-helper-mark-eval-scopes "^0.2.0"
+
+babel-plugin-minify-numeric-literals@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.2.0.tgz#5746e851700167a380c05e93f289a7070459a0d1"
+
+babel-plugin-minify-replace@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.2.0.tgz#3c1f06bc4e6d3e301eacb763edc1be611efc39b0"
+
+babel-plugin-minify-simplify@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.2.0.tgz#21ceec4857100c5476d7cef121f351156e5c9bc0"
+ dependencies:
+ babel-helper-flip-expressions "^0.2.0"
+ babel-helper-is-nodes-equiv "^0.0.1"
+ babel-helper-to-multiple-sequence-expressions "^0.2.0"
+
+babel-plugin-minify-type-constructors@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.2.0.tgz#7f3b6458be0863cfd59e9985bed6d134aa7a2e17"
+ dependencies:
+ babel-helper-is-void-0 "^0.2.0"
+
+babel-plugin-react-docgen@^1.8.0:
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/babel-plugin-react-docgen/-/babel-plugin-react-docgen-1.8.2.tgz#4615da43588c8cf5bdcae028f217954c70e6770b"
+ dependencies:
+ babel-types "^6.24.1"
+ lodash "^4.17.0"
+ react-docgen "^2.20.0"
+
+babel-plugin-react-intl@2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/babel-plugin-react-intl/-/babel-plugin-react-intl-2.3.1.tgz#3d43912e824da005e08e8e8239d5ba784374bb00"
dependencies:
@@ -663,7 +1081,7 @@ babel-plugin-syntax-do-expressions@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz#5747756139aa26d390d09410b03744ba07e4796d"
-babel-plugin-syntax-dynamic-import@^6.18.0:
+babel-plugin-syntax-dynamic-import@6.18.0, babel-plugin-syntax-dynamic-import@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da"
@@ -687,7 +1105,7 @@ babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
-babel-plugin-syntax-object-rest-spread@^6.8.0:
+babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
@@ -703,7 +1121,7 @@ babel-plugin-transform-async-generator-functions@^6.24.1:
babel-plugin-syntax-async-generators "^6.5.0"
babel-runtime "^6.22.0"
-babel-plugin-transform-async-to-generator@^6.24.1:
+babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761"
dependencies:
@@ -719,7 +1137,7 @@ babel-plugin-transform-class-constructor-call@^6.24.1:
babel-runtime "^6.22.0"
babel-template "^6.24.1"
-babel-plugin-transform-class-properties@^6.24.1:
+babel-plugin-transform-class-properties@6.24.1, babel-plugin-transform-class-properties@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac"
dependencies:
@@ -728,7 +1146,7 @@ babel-plugin-transform-class-properties@^6.24.1:
babel-runtime "^6.22.0"
babel-template "^6.24.1"
-babel-plugin-transform-decorators-legacy@^1.3.4:
+babel-plugin-transform-decorators-legacy@1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.4.tgz#741b58f6c5bce9e6027e0882d9c994f04f366925"
dependencies:
@@ -765,7 +1183,7 @@ babel-plugin-transform-es2015-block-scoped-functions@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-transform-es2015-block-scoping@^6.24.1:
+babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f"
dependencies:
@@ -775,7 +1193,7 @@ babel-plugin-transform-es2015-block-scoping@^6.24.1:
babel-types "^6.26.0"
lodash "^4.17.4"
-babel-plugin-transform-es2015-classes@^6.24.1:
+babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-classes@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db"
dependencies:
@@ -789,33 +1207,33 @@ babel-plugin-transform-es2015-classes@^6.24.1:
babel-traverse "^6.24.1"
babel-types "^6.24.1"
-babel-plugin-transform-es2015-computed-properties@^6.24.1:
+babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3"
dependencies:
babel-runtime "^6.22.0"
babel-template "^6.24.1"
-babel-plugin-transform-es2015-destructuring@^6.22.0:
+babel-plugin-transform-es2015-destructuring@6.23.0, babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d"
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-transform-es2015-duplicate-keys@^6.24.1:
+babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
-babel-plugin-transform-es2015-for-of@^6.22.0:
+babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691"
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-transform-es2015-function-name@^6.24.1:
+babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b"
dependencies:
@@ -829,7 +1247,7 @@ babel-plugin-transform-es2015-literals@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-transform-es2015-modules-amd@^6.24.1:
+babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154"
dependencies:
@@ -837,7 +1255,7 @@ babel-plugin-transform-es2015-modules-amd@^6.24.1:
babel-runtime "^6.22.0"
babel-template "^6.24.1"
-babel-plugin-transform-es2015-modules-commonjs@^6.24.1:
+babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a"
dependencies:
@@ -846,7 +1264,7 @@ babel-plugin-transform-es2015-modules-commonjs@^6.24.1:
babel-template "^6.26.0"
babel-types "^6.26.0"
-babel-plugin-transform-es2015-modules-systemjs@^6.24.1:
+babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23"
dependencies:
@@ -854,7 +1272,7 @@ babel-plugin-transform-es2015-modules-systemjs@^6.24.1:
babel-runtime "^6.22.0"
babel-template "^6.24.1"
-babel-plugin-transform-es2015-modules-umd@^6.24.1:
+babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015-modules-umd@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468"
dependencies:
@@ -862,14 +1280,14 @@ babel-plugin-transform-es2015-modules-umd@^6.24.1:
babel-runtime "^6.22.0"
babel-template "^6.24.1"
-babel-plugin-transform-es2015-object-super@^6.24.1:
+babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d"
dependencies:
babel-helper-replace-supers "^6.24.1"
babel-runtime "^6.22.0"
-babel-plugin-transform-es2015-parameters@^6.24.1:
+babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-parameters@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b"
dependencies:
@@ -880,7 +1298,7 @@ babel-plugin-transform-es2015-parameters@^6.24.1:
babel-traverse "^6.24.1"
babel-types "^6.24.1"
-babel-plugin-transform-es2015-shorthand-properties@^6.24.1:
+babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0"
dependencies:
@@ -893,7 +1311,7 @@ babel-plugin-transform-es2015-spread@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-transform-es2015-sticky-regex@^6.24.1:
+babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc"
dependencies:
@@ -907,13 +1325,13 @@ babel-plugin-transform-es2015-template-literals@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-transform-es2015-typeof-symbol@^6.22.0:
+babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372"
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-transform-es2015-unicode-regex@^6.24.1:
+babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9"
dependencies:
@@ -921,7 +1339,7 @@ babel-plugin-transform-es2015-unicode-regex@^6.24.1:
babel-runtime "^6.22.0"
regexpu-core "^2.0.0"
-babel-plugin-transform-exponentiation-operator@^6.24.1:
+babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e"
dependencies:
@@ -950,38 +1368,66 @@ babel-plugin-transform-function-bind@^6.22.0:
babel-plugin-syntax-function-bind "^6.8.0"
babel-runtime "^6.22.0"
-babel-plugin-transform-inline-environment-variables@^0.2.0:
+babel-plugin-transform-inline-consecutive-adds@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.2.0.tgz#15dae78921057f4004f8eafd79e15ddc5f12f426"
+
+babel-plugin-transform-inline-environment-variables@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-environment-variables/-/babel-plugin-transform-inline-environment-variables-0.2.0.tgz#37dad411a819667fd69c33e72f7a14ea1a50ba98"
-babel-plugin-transform-object-rest-spread@^6.22.0:
+babel-plugin-transform-member-expression-literals@^6.8.5:
+ version "6.9.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.0.tgz#ab07ad52a11ff7d2528c71388e8f901a4499c2b2"
+
+babel-plugin-transform-merge-sibling-variables@^6.8.6:
+ version "6.9.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.0.tgz#140017e305f8eb4f60d2f2db61154fbd71a9fcdd"
+
+babel-plugin-transform-minify-booleans@^6.8.3:
+ version "6.9.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.0.tgz#e36ceaa49aadcae70ec98bd9dbccb660719a667a"
+
+babel-plugin-transform-object-rest-spread@6.26.0, babel-plugin-transform-object-rest-spread@^6.22.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06"
dependencies:
babel-plugin-syntax-object-rest-spread "^6.8.0"
babel-runtime "^6.26.0"
+babel-plugin-transform-property-literals@^6.8.5:
+ version "6.9.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.0.tgz#4ddc12ada888927eacab4daff8a535ebc5de5a61"
+ dependencies:
+ esutils "^2.0.2"
+
+babel-plugin-transform-react-constant-elements@6.23.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-constant-elements/-/babel-plugin-transform-react-constant-elements-6.23.0.tgz#2f119bf4d2cdd45eb9baaae574053c604f6147dd"
+ dependencies:
+ babel-runtime "^6.22.0"
+
babel-plugin-transform-react-display-name@^6.23.0:
version "6.25.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz#67e2bf1f1e9c93ab08db96792e05392bf2cc28d1"
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-transform-react-jsx-self@^6.22.0:
+babel-plugin-transform-react-jsx-self@6.22.0, babel-plugin-transform-react-jsx-self@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e"
dependencies:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.22.0"
-babel-plugin-transform-react-jsx-source@^6.22.0:
+babel-plugin-transform-react-jsx-source@6.22.0, babel-plugin-transform-react-jsx-source@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6"
dependencies:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.22.0"
-babel-plugin-transform-react-jsx@^6.24.1:
+babel-plugin-transform-react-jsx@6.24.1, babel-plugin-transform-react-jsx@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3"
dependencies:
@@ -989,18 +1435,40 @@ babel-plugin-transform-react-jsx@^6.24.1:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.22.0"
-babel-plugin-transform-regenerator@^6.24.1:
+babel-plugin-transform-regenerator@6.26.0, babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1, babel-plugin-transform-regenerator@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f"
dependencies:
regenerator-transform "^0.10.0"
-babel-plugin-transform-runtime@^6.15.0:
+babel-plugin-transform-regexp-constructors@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.2.0.tgz#6aa5dd0acc515db4be929bbcec4ed4c946c534a3"
+
+babel-plugin-transform-remove-console@^6.8.5:
+ version "6.9.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.0.tgz#a7b671aab050dd30ef7cf2142b61a7d10efb327f"
+
+babel-plugin-transform-remove-debugger@^6.8.5:
+ version "6.9.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.0.tgz#b465e74b3fbe1970da561fb1331e30aefac3f1fe"
+
+babel-plugin-transform-remove-undefined@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.2.0.tgz#94f052062054c707e8d094acefe79416b63452b1"
+ dependencies:
+ babel-helper-evaluate-path "^0.2.0"
+
+babel-plugin-transform-runtime@6.23.0, babel-plugin-transform-runtime@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz#88490d446502ea9b8e7efb0fe09ec4d99479b1ee"
dependencies:
babel-runtime "^6.22.0"
+babel-plugin-transform-simplify-comparison-operators@^6.8.5:
+ version "6.9.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.0.tgz#586252fea023cb13f2400a09c0ab178dc0844f0a"
+
babel-plugin-transform-strict-mode@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758"
@@ -1008,6 +1476,10 @@ babel-plugin-transform-strict-mode@^6.24.1:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
+babel-plugin-transform-undefined-to-void@^6.8.3:
+ version "6.9.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.0.tgz#eb5db0554caffe9ded0206468ec0c6c3b332b9d2"
+
babel-polyfill@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153"
@@ -1016,7 +1488,42 @@ babel-polyfill@^6.26.0:
core-js "^2.5.0"
regenerator-runtime "^0.10.5"
-babel-preset-es2015@^6.18.0:
+babel-preset-env@1.6.1, babel-preset-env@^1.6.1:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48"
+ dependencies:
+ babel-plugin-check-es2015-constants "^6.22.0"
+ babel-plugin-syntax-trailing-function-commas "^6.22.0"
+ babel-plugin-transform-async-to-generator "^6.22.0"
+ babel-plugin-transform-es2015-arrow-functions "^6.22.0"
+ babel-plugin-transform-es2015-block-scoped-functions "^6.22.0"
+ babel-plugin-transform-es2015-block-scoping "^6.23.0"
+ babel-plugin-transform-es2015-classes "^6.23.0"
+ babel-plugin-transform-es2015-computed-properties "^6.22.0"
+ babel-plugin-transform-es2015-destructuring "^6.23.0"
+ babel-plugin-transform-es2015-duplicate-keys "^6.22.0"
+ babel-plugin-transform-es2015-for-of "^6.23.0"
+ babel-plugin-transform-es2015-function-name "^6.22.0"
+ babel-plugin-transform-es2015-literals "^6.22.0"
+ babel-plugin-transform-es2015-modules-amd "^6.22.0"
+ babel-plugin-transform-es2015-modules-commonjs "^6.23.0"
+ babel-plugin-transform-es2015-modules-systemjs "^6.23.0"
+ babel-plugin-transform-es2015-modules-umd "^6.23.0"
+ babel-plugin-transform-es2015-object-super "^6.22.0"
+ babel-plugin-transform-es2015-parameters "^6.23.0"
+ babel-plugin-transform-es2015-shorthand-properties "^6.22.0"
+ babel-plugin-transform-es2015-spread "^6.22.0"
+ babel-plugin-transform-es2015-sticky-regex "^6.22.0"
+ babel-plugin-transform-es2015-template-literals "^6.22.0"
+ babel-plugin-transform-es2015-typeof-symbol "^6.23.0"
+ babel-plugin-transform-es2015-unicode-regex "^6.22.0"
+ babel-plugin-transform-exponentiation-operator "^6.22.0"
+ babel-plugin-transform-regenerator "^6.22.0"
+ browserslist "^2.1.2"
+ invariant "^2.2.2"
+ semver "^5.3.0"
+
+babel-preset-es2015@6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939"
dependencies:
@@ -1051,7 +1558,60 @@ babel-preset-flow@^6.23.0:
dependencies:
babel-plugin-transform-flow-strip-types "^6.22.0"
-babel-preset-react@^6.16.0:
+babel-preset-jest@^22.0.6, babel-preset-jest@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-22.1.0.tgz#ff4e704102f9642765e2254226050561d8942ec9"
+ dependencies:
+ babel-plugin-jest-hoist "^22.1.0"
+ babel-plugin-syntax-object-rest-spread "^6.13.0"
+
+babel-preset-minify@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.2.0.tgz#006566552d9b83834472273f306c0131062a0acc"
+ dependencies:
+ babel-plugin-minify-builtins "^0.2.0"
+ babel-plugin-minify-constant-folding "^0.2.0"
+ babel-plugin-minify-dead-code-elimination "^0.2.0"
+ babel-plugin-minify-flip-comparisons "^0.2.0"
+ babel-plugin-minify-guarded-expressions "^0.2.0"
+ babel-plugin-minify-infinity "^0.2.0"
+ babel-plugin-minify-mangle-names "^0.2.0"
+ babel-plugin-minify-numeric-literals "^0.2.0"
+ babel-plugin-minify-replace "^0.2.0"
+ babel-plugin-minify-simplify "^0.2.0"
+ babel-plugin-minify-type-constructors "^0.2.0"
+ babel-plugin-transform-inline-consecutive-adds "^0.2.0"
+ babel-plugin-transform-member-expression-literals "^6.8.5"
+ babel-plugin-transform-merge-sibling-variables "^6.8.6"
+ babel-plugin-transform-minify-booleans "^6.8.3"
+ babel-plugin-transform-property-literals "^6.8.5"
+ babel-plugin-transform-regexp-constructors "^0.2.0"
+ babel-plugin-transform-remove-console "^6.8.5"
+ babel-plugin-transform-remove-debugger "^6.8.5"
+ babel-plugin-transform-remove-undefined "^0.2.0"
+ babel-plugin-transform-simplify-comparison-operators "^6.8.5"
+ babel-plugin-transform-undefined-to-void "^6.8.3"
+ lodash.isplainobject "^4.0.6"
+
+babel-preset-react-app@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-3.1.1.tgz#d3f06a79742f0e89d7afcb72e282d9809c850920"
+ dependencies:
+ babel-plugin-dynamic-import-node "1.1.0"
+ babel-plugin-syntax-dynamic-import "6.18.0"
+ babel-plugin-transform-class-properties "6.24.1"
+ babel-plugin-transform-es2015-destructuring "6.23.0"
+ babel-plugin-transform-object-rest-spread "6.26.0"
+ babel-plugin-transform-react-constant-elements "6.23.0"
+ babel-plugin-transform-react-jsx "6.24.1"
+ babel-plugin-transform-react-jsx-self "6.22.0"
+ babel-plugin-transform-react-jsx-source "6.22.0"
+ babel-plugin-transform-regenerator "6.26.0"
+ babel-plugin-transform-runtime "6.23.0"
+ babel-preset-env "1.6.1"
+ babel-preset-react "6.24.1"
+
+babel-preset-react@6.24.1, babel-preset-react@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380"
dependencies:
@@ -1062,7 +1622,7 @@ babel-preset-react@^6.16.0:
babel-plugin-transform-react-jsx-source "^6.22.0"
babel-preset-flow "^6.23.0"
-babel-preset-stage-0@^6.16.0:
+babel-preset-stage-0@6.24.1, babel-preset-stage-0@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.24.1.tgz#5642d15042f91384d7e5af8bc88b1db95b039e6a"
dependencies:
@@ -1109,14 +1669,14 @@ babel-register@^6.26.0:
mkdirp "^0.5.1"
source-map-support "^0.4.15"
-babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0, babel-runtime@^6.6.1:
+babel-runtime@6.x.x, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0, babel-runtime@^6.5.0, babel-runtime@^6.6.1, babel-runtime@^6.9.2:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.11.0"
-babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0:
+babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02"
dependencies:
@@ -1126,7 +1686,7 @@ babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0:
babylon "^6.18.0"
lodash "^4.17.4"
-babel-traverse@^6.0.20, babel-traverse@^6.24.1, babel-traverse@^6.26.0:
+babel-traverse@^6.0.20, babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee"
dependencies:
@@ -1140,7 +1700,7 @@ babel-traverse@^6.0.20, babel-traverse@^6.24.1, babel-traverse@^6.26.0:
invariant "^2.2.2"
lodash "^4.17.4"
-babel-types@^6.0.19, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0:
+babel-types@^6.0.19, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
dependencies:
@@ -1153,6 +1713,10 @@ babylon@^6.0.18, babylon@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
+babylon@~5.8.3:
+ version "5.8.38"
+ resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd"
+
balanced-match@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
@@ -1166,8 +1730,8 @@ base-x@^1.1.0:
resolved "https://registry.yarnpkg.com/base-x/-/base-x-1.1.0.tgz#42d3d717474f9ea02207f6d1aa1f426913eeb7ac"
base-x@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.2.tgz#bf873861b7514279b7969f340929eab87c11d130"
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.4.tgz#94c1788736da065edb1d68808869e357c977fa77"
dependencies:
safe-buffer "^5.0.1"
@@ -1185,15 +1749,11 @@ bcrypt-pbkdf@^1.0.0:
dependencies:
tweetnacl "^0.14.3"
-beeper@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809"
-
big.js@^3.1.3:
version "3.2.0"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
-bigi@^1.1.0, bigi@^1.4.1, bigi@^1.4.2:
+bigi@1.4.2, bigi@^1.1.0, bigi@^1.4.2:
version "1.4.2"
resolved "https://registry.yarnpkg.com/bigi/-/bigi-1.4.2.tgz#9c665a95f88b8b08fc05cfd731f561859d725825"
@@ -1202,25 +1762,13 @@ bignumber.js@4.0.4:
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-4.0.4.tgz#7c40f5abcd2d6623ab7b99682ee7db81b11889a4"
binary-extensions@^1.0.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0"
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205"
bitwise-xor@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/bitwise-xor/-/bitwise-xor-0.0.0.tgz#040a8172b5bb8cc562b0b7119f230b2a1a780e3d"
-bl@~1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e"
- dependencies:
- readable-stream "~2.0.5"
-
-bl@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398"
- dependencies:
- readable-stream "~2.0.5"
-
blacklist@^1.1.2:
version "1.1.4"
resolved "https://registry.yarnpkg.com/blacklist/-/blacklist-1.1.4.tgz#b2dd09d6177625b2caa69835a37b28995fa9a2f2"
@@ -1231,19 +1779,15 @@ block-stream@*:
dependencies:
inherits "~2.0.0"
-blocked@^1.1.0:
+blocked@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/blocked/-/blocked-1.2.1.tgz#e22efe767863c65ab8197f6252929104e1ec9ce2"
-bluebird@^2.9.30:
- version "2.11.0"
- resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
-
-bluebird@^3.0.5, bluebird@^3.3.4, bluebird@^3.4.1, bluebird@^3.4.6, bluebird@^3.5.0:
+bluebird@^3.0.5, bluebird@^3.3.4, bluebird@^3.4.1, bluebird@^3.4.6, bluebird@^3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
-blueimp-file-upload@~9.12.1:
+blueimp-file-upload@9.12.6:
version "9.12.6"
resolved "https://registry.yarnpkg.com/blueimp-file-upload/-/blueimp-file-upload-9.12.6.tgz#0ad01e949d4232452e8b5d4c92e948caa9b7b155"
@@ -1292,7 +1836,11 @@ bottleneck@^1.12.0:
version "1.16.0"
resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-1.16.0.tgz#d6ce13808527afc80b69092f15606655e5b21f1a"
-brace-expansion@^1.0.0, brace-expansion@^1.1.7:
+bowser@^1.0.0, bowser@^1.7.3:
+ version "1.9.2"
+ resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.9.2.tgz#d66fc868ca5f4ba895bee1363c343fe7b37d3394"
+
+brace-expansion@^1.1.7:
version "1.1.8"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292"
dependencies:
@@ -1307,13 +1855,27 @@ braces@^1.8.2:
preserve "^0.2.0"
repeat-element "^1.1.2"
+brcast@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/brcast/-/brcast-3.0.1.tgz#6256a8349b20de9eed44257a9b24d71493cd48dd"
+
brorand@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+browser-process-hrtime@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz#425d68a58d3447f02a04aa894187fce8af8b7b8e"
+
+browser-resolve@^1.11.2:
+ version "1.11.2"
+ resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce"
+ dependencies:
+ resolve "1.1.7"
+
browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.0.6:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.0.tgz#1d2ad62a8b479f23f0ab631c1be86a82dbccbe48"
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.1.tgz#38b7ab55edb806ff2dcda1a7f1620773a477c49f"
dependencies:
buffer-xor "^1.0.3"
cipher-base "^1.0.0"
@@ -1357,11 +1919,11 @@ browserify-sign@^4.0.0:
inherits "^2.0.1"
parse-asn1 "^5.0.0"
-browserify-zlib@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
+browserify-zlib@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f"
dependencies:
- pako "~0.2.0"
+ pako "~1.0.5"
browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
version "1.7.7"
@@ -1370,7 +1932,14 @@ browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
caniuse-db "^1.0.30000639"
electron-to-chromium "^1.2.7"
-bs58@^3.0.0:
+browserslist@^2.1.2, browserslist@^2.11.1:
+ version "2.11.3"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2"
+ dependencies:
+ caniuse-lite "^1.0.30000792"
+ electron-to-chromium "^1.3.30"
+
+bs58@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-3.1.0.tgz#d4c26388bf4804cac714141b1945aa47e5eb248e"
dependencies:
@@ -1382,6 +1951,12 @@ bs58@^4.0.0:
dependencies:
base-x "^3.0.2"
+bser@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
+ dependencies:
+ node-int64 "^0.4.0"
+
buffer-equal-constant-time@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
@@ -1413,7 +1988,7 @@ 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"
-bytebuffer@^5.0.0, bytebuffer@^5.0.1:
+bytebuffer@5.0.1, bytebuffer@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/bytebuffer/-/bytebuffer-5.0.1.tgz#582eea4b1a873b6d020a48d58df85f0bba6cfddd"
dependencies:
@@ -1423,18 +1998,14 @@ bytes@1:
version "1.0.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8"
-bytes@2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339"
+bytes@2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.5.0.tgz#4c9423ea2d252c270c41b2bdefeff9bb6b62c06a"
bytes@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
-bytes@^2.4.0:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.5.0.tgz#4c9423ea2d252c270c41b2bdefeff9bb6b62c06a"
-
caller-path@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
@@ -1445,12 +2016,9 @@ callsites@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
-camel-case@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-1.2.2.tgz#1aca7c4d195359a2ce9955793433c6e5542511f2"
- dependencies:
- sentence-case "^1.1.1"
- upper-case "^1.1.1"
+callsites@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
camelcase-keys@^2.0.0:
version "2.1.0"
@@ -1475,7 +2043,7 @@ camelcase@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
-camelize@1.0.0, camelize@^1.0.0:
+camelize@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b"
@@ -1489,8 +2057,16 @@ caniuse-api@^1.5.2:
lodash.uniq "^4.5.0"
caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
- version "1.0.30000746"
- resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000746.tgz#501098c66f5fbbf634c02f25508b05e8809910f4"
+ version "1.0.30000803"
+ resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000803.tgz#3e8d2baf56c2fd5a59c82e227928a0dc2c26702d"
+
+caniuse-lite@^1.0.30000791, caniuse-lite@^1.0.30000792:
+ version "1.0.30000803"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000803.tgz#9939c37149d38d5f4540430490d240c03106a0f5"
+
+case-sensitive-paths-webpack-plugin@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.1.1.tgz#3d29ced8c1f124bf6f53846fb3f5894731fdc909"
caseless@~0.11.0:
version "0.11.0"
@@ -1507,17 +2083,9 @@ center-align@^0.1.1:
align-text "^0.1.3"
lazy-cache "^1.0.3"
-chai-immutable@^1.5.3:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/chai-immutable/-/chai-immutable-1.6.0.tgz#9ec00bdd67948b13b20fcbb89cbf4af2ce6f9247"
-
-chai@^3.5.0:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247"
- dependencies:
- assertion-error "^1.0.1"
- deep-eql "^0.1.3"
- type-detect "^1.0.0"
+chain-function@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc"
chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
version "1.1.3"
@@ -1529,34 +2097,28 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
-chalk@^2.0.0, chalk@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e"
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba"
dependencies:
ansi-styles "^3.1.0"
escape-string-regexp "^1.0.5"
supports-color "^4.0.0"
-cheerio@^0.22.0:
- version "0.22.0"
- resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e"
+chardet@^0.4.0:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
+
+cheerio@^1.0.0-rc.2:
+ version "1.0.0-rc.2"
+ resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db"
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"
+ lodash "^4.15.0"
+ parse5 "^3.0.1"
chokidar@^1.6.1, chokidar@^1.7.0:
version "1.7.0"
@@ -1573,6 +2135,10 @@ chokidar@^1.6.1, chokidar@^1.7.0:
optionalDependencies:
fsevents "^1.0.0"
+ci-info@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.2.tgz#03561259db48d0474c8bdc90f5b47b068b6bbfb4"
+
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"
@@ -1594,11 +2160,11 @@ class-autobind@^0.1.2:
version "0.1.4"
resolved "https://registry.yarnpkg.com/class-autobind/-/class-autobind-0.1.4.tgz#34516c49167cf8d3f639ddc186bcfa2268afff34"
-classnames@^2.1.3, classnames@^2.2.3, classnames@^2.2.5:
+classnames@2.2.5, classnames@^2.1.3, classnames@^2.2.3, classnames@^2.2.5:
version "2.2.5"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
-cli-color@~1.2.0:
+cli-color@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-1.2.0.tgz#3a5ae74fd76b6267af666e69e2afbbd01def34d1"
dependencies:
@@ -1609,12 +2175,38 @@ cli-color@~1.2.0:
memoizee "^0.4.3"
timers-ext "0.1"
+cli-cursor@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
+ dependencies:
+ restore-cursor "^1.0.1"
+
cli-cursor@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
dependencies:
restore-cursor "^2.0.0"
+cli-spinners@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c"
+
+cli-table2@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97"
+ dependencies:
+ lodash "^3.10.1"
+ string-width "^1.0.1"
+ optionalDependencies:
+ colors "^1.1.2"
+
+cli-truncate@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574"
+ dependencies:
+ slice-ansi "0.0.4"
+ string-width "^1.0.1"
+
cli-width@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
@@ -1635,6 +2227,14 @@ cliui@^3.2.0:
strip-ansi "^3.0.1"
wrap-ansi "^2.0.0"
+cliui@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.0.0.tgz#743d4650e05f36d1ed2575b59638d87322bfbbcc"
+ dependencies:
+ string-width "^2.1.1"
+ strip-ansi "^4.0.0"
+ wrap-ansi "^2.0.0"
+
clone-deep@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.3.0.tgz#348c61ae9cdbe0edfe053d91ff4cc521d790ede8"
@@ -1644,40 +2244,25 @@ clone-deep@^0.3.0:
kind-of "^3.2.2"
shallow-clone "^0.1.2"
-clone-stats@^0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1"
-
-clone@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f"
-
-clone@^1.0.0, clone@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149"
+clone@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f"
-cluster@^0.7.7:
+cluster@0.7.7:
version "0.7.7"
resolved "https://registry.yarnpkg.com/cluster/-/cluster-0.7.7.tgz#e497e267cc956bd0b0513adb4aa393357d0085ef"
dependencies:
log ">= 1.2.0"
mkdirp ">= 0.0.1"
-co-body@*, co-body@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/co-body/-/co-body-4.2.0.tgz#74df20fa73262125dc45482af04e342ea8db3515"
- dependencies:
- inflation "~2.0.0"
- qs "~4.0.0"
- raw-body "~2.1.2"
- type-is "~1.6.6"
-
-co-mocha@^1.1.2:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/co-mocha/-/co-mocha-1.2.1.tgz#145b997d58acd56616b3de557ff24df3d7cd63ba"
+co-body@*, co-body@5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/co-body/-/co-body-5.1.1.tgz#d97781d1e3344ba4a820fd1806bddf8341505236"
dependencies:
- co "^4.0.0"
- is-generator "^1.0.1"
+ inflation "^2.0.0"
+ qs "^6.4.0"
+ raw-body "^2.2.0"
+ type-is "^1.6.14"
co-request@^0.2.0:
version "0.2.1"
@@ -1689,7 +2274,7 @@ co-supertest@0.0.10:
version "0.0.10"
resolved "https://registry.yarnpkg.com/co-supertest/-/co-supertest-0.0.10.tgz#2cdb284e8ba803a08c379ecfde1ee8eeca8f8332"
-co@^4.0.0, co@^4.0.2, co@^4.4.0, co@^4.6.0:
+co@^4.0.2, co@^4.4.0, co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@@ -1704,8 +2289,8 @@ code-point-at@^1.0.0:
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
color-convert@^1.3.0, color-convert@^1.9.0:
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed"
dependencies:
color-name "^1.1.1"
@@ -1735,27 +2320,29 @@ colormin@^1.0.5:
css-color-names "0.0.4"
has "^1.0.1"
+colors@0.5.x:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774"
+
colors@^1.1.2, colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
-combined-stream@^1.0.5, combined-stream@~1.0.1, combined-stream@~1.0.5:
+combined-stream@^1.0.5, combined-stream@~1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
dependencies:
delayed-stream "~1.0.0"
-commander@0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06"
-
-commander@2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873"
+commander@^2.11.0, commander@^2.12.2, commander@^2.9.0:
+ version "2.14.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.0.tgz#7b25325963e6aace20d3a9285b09379b0c2208b5"
-commander@^2.11.0, commander@^2.8.1, commander@^2.9.0:
- version "2.11.0"
- resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
+common-tags@^1.6.0:
+ version "1.7.2"
+ resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.7.2.tgz#24d9768c63d253a56ecff93845b44b4df1d52771"
+ dependencies:
+ babel-runtime "^6.26.0"
commondir@^1.0.1:
version "1.0.1"
@@ -1773,10 +2360,10 @@ composition@^2.1.1:
co "^4.0.2"
compressible@2, compressible@~2.0.6:
- version "2.0.11"
- resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.11.tgz#16718a75de283ed8e604041625a2064586797d8a"
+ version "2.0.12"
+ resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.12.tgz#c59a5c99db76767e9876500e271ef63b3493bd66"
dependencies:
- mime-db ">= 1.29.0 < 2"
+ mime-db ">= 1.30.0 < 2"
concat-map@0.0.1:
version "0.0.1"
@@ -1797,21 +2384,23 @@ config-chain@~1.1.5:
ini "^1.3.4"
proto-list "~1.2.1"
-config@^1.25.1:
+config@1.26.2:
version "1.26.2"
resolved "https://registry.yarnpkg.com/config/-/config-1.26.2.tgz#2466291168d8afae0aae8ab99ea4d4272f520cae"
dependencies:
json5 "0.4.0"
os-homedir "1.0.2"
-connect@3.6.5:
- version "3.6.5"
- resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.5.tgz#fb8dde7ba0763877d0ec9df9dac0b4b40e72c7da"
+configstore@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.1.tgz#094ee662ab83fad9917678de114faaea8fcdca90"
dependencies:
- debug "2.6.9"
- finalhandler "1.0.6"
- parseurl "~1.3.2"
- utils-merge "1.0.1"
+ dot-prop "^4.1.0"
+ graceful-fs "^4.1.2"
+ make-dir "^1.0.0"
+ unique-string "^1.0.0"
+ write-file-atomic "^2.0.0"
+ xdg-basedir "^3.0.0"
console-browserify@^1.1.0:
version "1.1.0"
@@ -1835,23 +2424,21 @@ content-disposition@0.5.2, content-disposition@~0.5.0:
version "0.5.2"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
-content-security-policy-builder@1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/content-security-policy-builder/-/content-security-policy-builder-1.1.0.tgz#d91f1b076236c119850c7dee9924bf55e05772b3"
- dependencies:
- dashify "^0.2.0"
+content-security-policy-builder@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/content-security-policy-builder/-/content-security-policy-builder-2.0.0.tgz#8749a1d542fcbe82237281ea9f716ce68b394dd2"
-content-type-parser@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94"
+content-type-parser@^1.0.1, content-type-parser@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.2.tgz#caabe80623e63638b2502fd4c7f12ff4ce2352e7"
content-type@^1.0.0, content-type@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
-convert-source-map@^1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
+convert-source-map@^1.4.0, convert-source-map@^1.5.0:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5"
cookie-signature@1.0.6:
version "1.0.6"
@@ -1882,15 +2469,36 @@ core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
-core-js@^2.4.0, core-js@^2.5.0:
- version "2.5.1"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b"
+core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0, core-js@^2.5.3:
+ version "2.5.3"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e"
core-util-is@1.0.2, 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"
-counterpart@^0.17.6:
+cosmiconfig@^2.1.0, cosmiconfig@^2.1.1:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-2.2.2.tgz#6173cebd56fac042c1f4390edf7af6c07c7cb892"
+ dependencies:
+ is-directory "^0.3.1"
+ js-yaml "^3.4.3"
+ minimist "^1.2.0"
+ object-assign "^4.1.0"
+ os-homedir "^1.0.1"
+ parse-json "^2.2.0"
+ require-from-string "^1.1.0"
+
+cosmiconfig@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-3.1.0.tgz#640a94bf9847f321800403cd273af60665c73397"
+ dependencies:
+ is-directory "^0.3.1"
+ js-yaml "^3.9.0"
+ parse-json "^3.0.0"
+ require-from-string "^2.0.1"
+
+counterpart@0.17.9:
version "0.17.9"
resolved "https://registry.yarnpkg.com/counterpart/-/counterpart-0.17.9.tgz#0379e4d090b9efdb29c636a607c52e35734f5f13"
dependencies:
@@ -1900,7 +2508,7 @@ counterpart@^0.17.6:
pluralizers "^0.1.4"
sprintf-js "^1.0.3"
-cpu-stat@^2.0.1:
+cpu-stat@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/cpu-stat/-/cpu-stat-2.0.1.tgz#501e8d6dd2d44cef5d842939c38d1822c078fcac"
@@ -1931,21 +2539,28 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
-create-react-class@^15.5.1, create-react-class@^15.5.2:
- version "15.6.2"
- resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.2.tgz#cf1ed15f12aad7f14ef5f2dfe05e6c42f91ef02a"
+create-react-class@^15.5.1, create-react-class@^15.5.2, create-react-class@^15.6.0, create-react-class@^15.6.2:
+ version "15.6.3"
+ resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.3.tgz#2d73237fb3f970ae6ebe011a9e66f46dbca80036"
dependencies:
fbjs "^0.8.9"
loose-envify "^1.3.1"
object-assign "^4.1.1"
cross-env@^5.0.0:
- version "5.0.5"
- resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.0.5.tgz#4383d364d9660873dd185b398af3bfef5efffef3"
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.1.3.tgz#f8ae18faac87692b0a8b4d2f7000d4ec3a85dfd7"
dependencies:
cross-spawn "^5.1.0"
is-windows "^1.0.0"
+cross-fetch@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-1.1.1.tgz#dede6865ae30f37eae62ac90ebb7bdac002b05a0"
+ dependencies:
+ node-fetch "1.7.3"
+ whatwg-fetch "2.0.3"
+
cross-spawn@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
@@ -1974,8 +2589,8 @@ cryptiles@3.x.x:
boom "5.x.x"
crypto-browserify@^3.11.0:
- version "3.11.1"
- resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.1.tgz#948945efc6757a400d6e5e5af47194d10064279f"
+ version "3.12.0"
+ resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
dependencies:
browserify-cipher "^1.0.0"
browserify-sign "^4.0.0"
@@ -1987,6 +2602,11 @@ crypto-browserify@^3.11.0:
pbkdf2 "^3.0.3"
public-encrypt "^4.0.0"
randombytes "^2.0.0"
+ randomfill "^1.0.3"
+
+crypto-random-string@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
csrf@^3.0.0:
version "3.0.6"
@@ -2000,7 +2620,13 @@ 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"
-css-loader@^0.28.5:
+css-in-js-utils@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-2.0.0.tgz#5af1dd70f4b06b331f48d22a3d86e0786c0b9435"
+ dependencies:
+ hyphenate-style-name "^1.0.2"
+
+css-loader@0.28.7:
version "0.28.7"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.7.tgz#5f2ee989dd32edd907717f953317656160999c1b"
dependencies:
@@ -2019,6 +2645,25 @@ css-loader@^0.28.5:
postcss-value-parser "^3.3.0"
source-list-map "^2.0.0"
+css-loader@^0.28.7:
+ version "0.28.9"
+ resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.9.tgz#68064b85f4e271d7ce4c48a58300928e535d1c95"
+ dependencies:
+ babel-code-frame "^6.26.0"
+ css-selector-tokenizer "^0.7.0"
+ cssnano "^3.10.0"
+ icss-utils "^2.1.0"
+ loader-utils "^1.0.2"
+ lodash.camelcase "^4.3.0"
+ object-assign "^4.1.1"
+ postcss "^5.0.6"
+ postcss-modules-extract-imports "^1.2.0"
+ postcss-modules-local-by-default "^1.2.0"
+ postcss-modules-scope "^1.1.0"
+ postcss-modules-values "^1.3.0"
+ postcss-value-parser "^3.3.0"
+ source-list-map "^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"
@@ -2044,7 +2689,7 @@ cssesc@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
-"cssnano@>=2.6.1 <4":
+"cssnano@>=2.6.1 <4", cssnano@^3.10.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38"
dependencies:
@@ -2098,11 +2743,7 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
dependencies:
cssom "0.3.x"
-ctype@0.5.3:
- version "0.5.3"
- resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f"
-
-currency-symbol-map@^3.1.0:
+currency-symbol-map@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/currency-symbol-map/-/currency-symbol-map-3.1.0.tgz#b2b42c53e80d205bb508ca80eafc7816c9628d5b"
@@ -2112,6 +2753,10 @@ currently-unhandled@^0.4.1:
dependencies:
array-find-index "^1.0.1"
+cvss@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/cvss/-/cvss-1.0.2.tgz#df67e92bf12a796f49e928799c8db3ba74b9fcd6"
+
d@1:
version "1.0.0"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
@@ -2132,37 +2777,27 @@ dasherize@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/dasherize/-/dasherize-2.0.0.tgz#6d809c9cd0cf7bb8952d80fc84fa13d47ddb1308"
-dashify@^0.2.0:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/dashify/-/dashify-0.2.2.tgz#6a07415a01c91faf4a32e38d9dfba71f61cb20fe"
+date-fns@^1.27.2:
+ version "1.29.0"
+ resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6"
date-names@^0.1.7:
- version "0.1.10"
- resolved "https://registry.yarnpkg.com/date-names/-/date-names-0.1.10.tgz#62f8d9332295044657f3ce7616d8a34021f8ef2b"
+ version "0.1.11"
+ resolved "https://registry.yarnpkg.com/date-names/-/date-names-0.1.11.tgz#154bc1714d3e26adb4e305bde20803130a8a8e84"
date-now@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
-dateformat@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062"
-
-debug@*, debug@2, debug@2.6.9, debug@^2.2.0, debug@^2.6.8:
- version "2.6.9"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+debug@*, debug@^3.0.1, debug@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
dependencies:
ms "2.0.0"
-debug@2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da"
- dependencies:
- ms "0.7.1"
-
-debug@^3.0.1:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
+debug@2, debug@2.6.9, debug@^2.2.0, debug@^2.6.8, debug@^2.6.9:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
dependencies:
ms "2.0.0"
@@ -2170,15 +2805,9 @@ decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
-deep-copy@^1.2.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/deep-copy/-/deep-copy-1.4.0.tgz#f181ef0249bc83bbc5bb866d95c7d565acf45e8b"
-
-deep-eql@^0.1.3:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2"
- dependencies:
- type-detect "0.1.1"
+dedent@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
deep-equal@^1.0.0, deep-equal@^1.0.1, deep-equal@~1.0.1:
version "1.0.1"
@@ -2192,11 +2821,11 @@ deep-is@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
-defaults@^1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
+default-require-extensions@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
dependencies:
- clone "^1.0.2"
+ strip-bom "^2.0.0"
define-properties@^1.1.2:
version "1.1.2"
@@ -2229,17 +2858,17 @@ delegates@1.0.0, delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
-depd@1.1.1, depd@^1.1.0, depd@~1.1.1:
+depd@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359"
-deprecate@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/deprecate/-/deprecate-0.1.0.tgz#c49058612dc6c8e5145eafe4839b8c2c7d041c14"
+depd@^1.1.0, depd@~1.1.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
-deprecated@^0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/deprecated/-/deprecated-0.0.1.tgz#f9c9af5464afa1e7a971458a8bdef2aa94d5bb19"
+deprecate@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/deprecate/-/deprecate-1.0.0.tgz#661490ed2428916a6c8883d8834e5646f4e4a4a8"
des.js@^1.0.0:
version "1.0.0"
@@ -2252,33 +2881,35 @@ destroy@^1.0.3, destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
-detect-file@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63"
- dependencies:
- fs-exists-sync "^0.1.0"
-
detect-indent@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
dependencies:
repeating "^2.0.0"
+detect-libc@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+
+detect-newline@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2"
+
detect-node@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127"
-dev-ip@^1.0.1:
+dev-ip@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0"
-diff-match-patch@^1.0.0:
+diff-match-patch@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.0.tgz#1cc3c83a490d67f95d91e39f6ad1f2e086b63048"
-diff@1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf"
+diff@^3.2.0:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c"
diffie-hellman@^5.0.0:
version "5.0.2"
@@ -2288,11 +2919,11 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0"
randombytes "^2.0.0"
-dirty-chai@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/dirty-chai/-/dirty-chai-1.2.2.tgz#78495e619635f7fe44219aa4c837849bf183142e"
+discontinuous-range@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
-disk-stat@^1.0.4:
+disk-stat@1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/disk-stat/-/disk-stat-1.0.4.tgz#42a47930f5d4f2ceea9a261c02126954d117a6c4"
@@ -2308,19 +2939,22 @@ doctrine@1.5.0:
isarray "^1.0.0"
doctrine@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63"
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
dependencies:
esutils "^2.0.2"
- isarray "^1.0.0"
dom-helpers@^2.3.0, dom-helpers@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-2.4.0.tgz#9bb4b245f637367b1fa670274272aa28fe06c367"
-dom-helpers@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a"
+dom-helpers@^3.2.0, dom-helpers@^3.2.1:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6"
+
+dom-scroll-into-view@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/dom-scroll-into-view/-/dom-scroll-into-view-1.0.1.tgz#32abb92f0d8feca6215162aef43e4b449ab8d99c"
dom-serializer@0, dom-serializer@~0.1.0:
version "0.1.0"
@@ -2334,8 +2968,8 @@ dom-walk@^0.1.0:
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
domain-browser@^1.1.1:
- version "1.1.7"
- resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
domelementtype@1, domelementtype@^1.3.0:
version "1.3.0"
@@ -2345,6 +2979,12 @@ domelementtype@~1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b"
+domexception@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90"
+ dependencies:
+ webidl-conversions "^4.0.2"
+
domhandler@^2.3.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.1.tgz#892e47000a99be55bbf3774ffea0561d8879c259"
@@ -2369,6 +3009,22 @@ dont-sniff-mimetype@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58"
+dot-prop@^4.1.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
+ dependencies:
+ is-obj "^1.0.0"
+
+dotenv-webpack@^1.5.4:
+ version "1.5.4"
+ resolved "https://registry.yarnpkg.com/dotenv-webpack/-/dotenv-webpack-1.5.4.tgz#9c92e46e412a1cfbc60217ed33d69d2bbfddbf9f"
+ dependencies:
+ dotenv "^4.0.0"
+
+dotenv@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-4.0.0.tgz#864ef1379aced55ce6f95debecdce179f7a0cd1d"
+
dottie@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/dottie/-/dottie-1.1.1.tgz#45c2a3f48bd6528eeed267a69a848eaaca6faa6a"
@@ -2416,12 +3072,6 @@ draft-js@^0.7.0:
fbjs "^0.8.1"
immutable "^3.7.4"
-duplexer2@0.0.2:
- version "0.0.2"
- resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db"
- dependencies:
- readable-stream "~1.1.9"
-
duplexer@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
@@ -2439,12 +3089,19 @@ ecdsa-sig-formatter@1.0.9:
base64url "^2.0.0"
safe-buffer "^5.0.1"
-ecurve@^1.0.2, ecurve@^1.0.5:
+ecurve@1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/ecurve/-/ecurve-1.0.5.tgz#d148e8fe50a674f983bb5bae09da0ea23e10535e"
dependencies:
bigi "^1.1.0"
+ecurve@^1.0.5:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/ecurve/-/ecurve-1.0.6.tgz#dfdabbb7149f8d8b78816be5a7d5b83fcf6de797"
+ dependencies:
+ bigi "^1.1.0"
+ safe-buffer "^5.0.1"
+
editorconfig@^0.13.2:
version "0.13.3"
resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.13.3.tgz#e5219e587951d60958fd94ea9a9a008cdeff1b34"
@@ -2463,9 +3120,13 @@ ejs@^2.5.6:
version "2.5.7"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.7.tgz#cc872c168880ae3c7189762fd5ffc00896c9518a"
-electron-to-chromium@^1.2.7:
- version "1.3.26"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.26.tgz#996427294861a74d9c7c82b9260ea301e8c02d66"
+electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.30:
+ version "1.3.32"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.32.tgz#11d0684c0840e003c4be8928f8ac5f35dbc2b4e6"
+
+elegant-spinner@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e"
elliptic@^6.0.0:
version "6.4.0"
@@ -2488,8 +3149,8 @@ emojis-list@^2.0.0:
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
encodeurl@~1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20"
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
encoding@^0.1.11, encoding@^0.1.12, encoding@~0.1.12:
version "0.1.12"
@@ -2497,12 +3158,6 @@ encoding@^0.1.11, encoding@^0.1.12, encoding@~0.1.12:
dependencies:
iconv-lite "~0.4.13"
-end-of-stream@~0.1.5:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-0.1.5.tgz#8e177206c3c80837d85632e8b9359dfe8b2f6eaf"
- dependencies:
- once "~1.3.0"
-
enhanced-resolve@^3.4.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e"
@@ -2516,28 +3171,52 @@ entities@^1.1.1, entities@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
-enzyme@^2.1.0:
- version "2.9.1"
- resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-2.9.1.tgz#07d5ce691241240fb817bf2c4b18d6e530240df6"
+enzyme-adapter-react-15@1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/enzyme-adapter-react-15/-/enzyme-adapter-react-15-1.0.5.tgz#99f9a03ff2c2303e517342935798a6bdfbb75fac"
+ dependencies:
+ enzyme-adapter-utils "^1.1.0"
+ lodash "^4.17.4"
+ object.assign "^4.0.4"
+ object.values "^1.0.4"
+ prop-types "^15.5.10"
+
+enzyme-adapter-utils@^1.1.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.3.0.tgz#d6c85756826c257a8544d362cc7a67e97ea698c7"
+ dependencies:
+ lodash "^4.17.4"
+ object.assign "^4.0.4"
+ prop-types "^15.6.0"
+
+enzyme@3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.3.0.tgz#0971abd167f2d4bf3f5bd508229e1c4b6dc50479"
dependencies:
- cheerio "^0.22.0"
- function.prototype.name "^1.0.0"
+ cheerio "^1.0.0-rc.2"
+ function.prototype.name "^1.0.3"
+ has "^1.0.1"
+ is-boolean-object "^1.0.0"
+ is-callable "^1.1.3"
+ is-number-object "^1.0.3"
+ is-string "^1.0.4"
is-subset "^0.1.1"
lodash "^4.17.4"
+ object-inspect "^1.5.0"
object-is "^1.0.1"
- object.assign "^4.0.4"
+ object.assign "^4.1.0"
object.entries "^1.0.4"
object.values "^1.0.4"
- prop-types "^15.5.10"
- uuid "^3.0.1"
+ raf "^3.4.0"
+ rst-selector-parser "^2.2.3"
errno@^0.1.3:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.6.tgz#c386ce8a6283f14fc09563b71560908c9bf53026"
dependencies:
- prr "~0.0.0"
+ prr "~1.0.1"
-error-ex@^1.2.0:
+error-ex@^1.2.0, error-ex@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc"
dependencies:
@@ -2547,9 +3226,9 @@ error-inject@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37"
-es-abstract@^1.6.1, es-abstract@^1.7.0:
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.9.0.tgz#690829a07cae36b222e7fd9b75c0d0573eb25227"
+es-abstract@^1.10.0, es-abstract@^1.4.3, es-abstract@^1.5.1, es-abstract@^1.6.1, es-abstract@^1.7.0, es-abstract@^1.9.0:
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864"
dependencies:
es-to-primitive "^1.1.1"
function-bind "^1.1.1"
@@ -2565,20 +3244,24 @@ es-to-primitive@^1.1.1:
is-date-object "^1.0.1"
is-symbol "^1.0.1"
-es5-ext@^0.10.12, es5-ext@^0.10.14, es5-ext@^0.10.30, es5-ext@^0.10.9, es5-ext@~0.10.14, es5-ext@~0.10.2:
- version "0.10.31"
- resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.31.tgz#7bb938c95a7f1b9f728092dc09c41edcc398eefe"
+es5-ext@^0.10.12, es5-ext@^0.10.14, es5-ext@^0.10.30, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14, es5-ext@~0.10.2:
+ version "0.10.38"
+ resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.38.tgz#fa7d40d65bbc9bb8a67e1d3f9cc656a00530eed3"
dependencies:
- es6-iterator "~2.0.1"
+ es6-iterator "~2.0.3"
es6-symbol "~3.1.1"
-es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512"
+es5-shim@^4.5.10:
+ version "4.5.10"
+ resolved "https://registry.yarnpkg.com/es5-shim/-/es5-shim-4.5.10.tgz#b7e17ef4df2a145b821f1497b50c25cf94026205"
+
+es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
dependencies:
d "1"
- es5-ext "^0.10.14"
- es6-symbol "^3.1"
+ es5-ext "^0.10.35"
+ es6-symbol "^3.1.1"
es6-map@^0.1.3:
version "0.1.5"
@@ -2591,6 +3274,16 @@ es6-map@^0.1.3:
es6-symbol "~3.1.1"
event-emitter "~0.3.5"
+es6-promise@^4.0.3:
+ version "4.2.4"
+ resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
+
+es6-promisify@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
+ dependencies:
+ es6-promise "^4.0.3"
+
es6-set@~0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1"
@@ -2601,7 +3294,11 @@ es6-set@~0.1.5:
es6-symbol "3.1.1"
event-emitter "~0.3.5"
-es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1:
+es6-shim@^0.35.3:
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.3.tgz#9bfb7363feffff87a6cdb6cd93e405ec3c4b6f26"
+
+es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77"
dependencies:
@@ -2621,15 +3318,11 @@ escape-html@~1.0.1, escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
-escape-string-regexp@1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1"
-
-escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
+escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5, 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"
-escodegen@^1.6.1:
+escodegen@^1.6.1, escodegen@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.0.tgz#9811a2f265dc1cd3894420ee3717064b632b8852"
dependencies:
@@ -2640,7 +3333,7 @@ escodegen@^1.6.1:
optionalDependencies:
source-map "~0.5.6"
-escope@^3.6.0:
+escope@3.6.0, escope@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3"
dependencies:
@@ -2655,18 +3348,18 @@ eslint-config-airbnb-base@^11.3.0:
dependencies:
eslint-restricted-globals "^0.1.1"
-eslint-config-airbnb@^15.1.0:
+eslint-config-airbnb@15.1.0:
version "15.1.0"
resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-15.1.0.tgz#fd432965a906e30139001ba830f58f73aeddae8e"
dependencies:
eslint-config-airbnb-base "^11.3.0"
eslint-import-resolver-node@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.1.tgz#4422574cde66a9a7b099938ee4d508a199e0e3cc"
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a"
dependencies:
- debug "^2.6.8"
- resolve "^1.2.0"
+ debug "^2.6.9"
+ resolve "^1.5.0"
eslint-module-utils@^2.1.1:
version "2.1.1"
@@ -2675,11 +3368,11 @@ eslint-module-utils@^2.1.1:
debug "^2.6.8"
pkg-dir "^1.0.0"
-eslint-plugin-babel@^4.1.2:
+eslint-plugin-babel@4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-4.1.2.tgz#79202a0e35757dd92780919b2336f1fa2fe53c1e"
-eslint-plugin-import@^2.7.0:
+eslint-plugin-import@2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.7.0.tgz#21de33380b9efb55f5ef6d2e210ec0e07e7fa69f"
dependencies:
@@ -2694,7 +3387,7 @@ eslint-plugin-import@^2.7.0:
minimatch "^3.0.3"
read-pkg-up "^2.0.0"
-eslint-plugin-jsx-a11y@^6.0.2:
+eslint-plugin-jsx-a11y@6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.0.2.tgz#659277a758b036c305a7e4a13057c301cd3be73f"
dependencies:
@@ -2706,7 +3399,7 @@ eslint-plugin-jsx-a11y@^6.0.2:
emoji-regex "^6.1.0"
jsx-ast-utils "^1.4.0"
-eslint-plugin-react@^7.4.0:
+eslint-plugin-react@7.4.0:
version "7.4.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.4.0.tgz#300a95861b9729c087d362dd64abcc351a74364a"
dependencies:
@@ -2726,7 +3419,7 @@ eslint-scope@^3.7.1:
esrecurse "^4.1.0"
estraverse "^4.1.1"
-eslint@^4.7.0:
+eslint@4.8.0:
version "4.8.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.8.0.tgz#229ef0e354e0e61d837c7a80fdfba825e199815e"
dependencies:
@@ -2769,10 +3462,10 @@ eslint@^4.7.0:
text-table "~0.2.0"
espree@^3.5.1:
- version "3.5.1"
- resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.1.tgz#0c988b8ab46db53100a1954ae4ba995ddd27d87e"
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.3.tgz#931e0af64e7fbbed26b050a29daad1fc64799fa6"
dependencies:
- acorn "^5.1.1"
+ acorn "^5.4.0"
acorn-jsx "^3.0.0"
esprima@^2.6.0:
@@ -2783,7 +3476,7 @@ esprima@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
-esprima@^4.0.0:
+esprima@^4.0.0, esprima@~4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
@@ -2800,7 +3493,7 @@ esrecurse@^4.1.0:
estraverse "^4.1.0"
object-assign "^4.0.1"
-estraverse-fb@^1.3.1:
+estraverse-fb@1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/estraverse-fb/-/estraverse-fb-1.3.2.tgz#d323a4cb5e5ac331cea033413a9253e1643e07c4"
@@ -2827,7 +3520,7 @@ event-lite@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/event-lite/-/event-lite-0.1.1.tgz#47cf08a8d37d0b694cdb7b3b17b51faac6576086"
-events@^1.0.0:
+events@^1.0.0, events@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
@@ -2844,6 +3537,12 @@ except@^0.1.3:
dependencies:
indexof "0.0.1"
+exec-sh@^0.2.0:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38"
+ dependencies:
+ merge "^1.1.3"
+
execa@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
@@ -2856,9 +3555,33 @@ execa@^0.7.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
-expand-brackets@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+execa@^0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da"
+ dependencies:
+ cross-spawn "^5.0.1"
+ get-stream "^3.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"
+
+exenv@^1.2.0, exenv@^1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
+
+exit-hook@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
+
+exit@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
+
+expand-brackets@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
dependencies:
is-posix-bracket "^0.1.0"
@@ -2868,23 +3591,22 @@ expand-range@^1.8.1:
dependencies:
fill-range "^2.1.0"
-expand-tilde@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
- dependencies:
- os-homedir "^1.0.1"
-
-expand-tilde@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
- dependencies:
- homedir-polyfill "^1.0.1"
-
expect-ct@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/expect-ct/-/expect-ct-0.1.0.tgz#52735678de18530890d8d7b95f0ac63640958094"
-express@^4.15.2:
+expect@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/expect/-/expect-22.1.0.tgz#f8f9b019ab275d859cbefed531fbaefe8972431d"
+ dependencies:
+ ansi-styles "^3.2.0"
+ jest-diff "^22.1.0"
+ jest-get-type "^22.1.0"
+ jest-matcher-utils "^22.1.0"
+ jest-message-util "^22.1.0"
+ jest-regex-util "^22.1.0"
+
+express@^4.15.2, express@^4.16.2:
version "4.16.2"
resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c"
dependencies:
@@ -2923,10 +3645,6 @@ extend@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extend/-/extend-1.3.0.tgz#d1516fb0ff5624d2ebf9123ea1dac5a1994004f8"
-extend@2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/extend/-/extend-2.0.1.tgz#1ee8010689e7395ff9448241c98652bc759a8260"
-
extend@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
@@ -2936,11 +3654,11 @@ extend@^3.0.0, extend@~3.0.0, extend@~3.0.1:
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
external-editor@^2.0.4:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.5.tgz#52c249a3981b9ba187c7cacf5beb50bf1d91a6bc"
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48"
dependencies:
+ chardet "^0.4.0"
iconv-lite "^0.4.17"
- jschardet "^1.4.2"
tmp "^0.0.33"
extglob@^0.3.1:
@@ -2949,7 +3667,7 @@ extglob@^0.3.1:
dependencies:
is-extglob "^1.0.0"
-extract-text-webpack-plugin@^3.0.0:
+extract-text-webpack-plugin@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.1.tgz#605a8893faca1dd49bb0d2ca87493f33fd43d102"
dependencies:
@@ -2958,36 +3676,47 @@ extract-text-webpack-plugin@^3.0.0:
schema-utils "^0.3.0"
webpack-sources "^1.0.1"
-extsprintf@1.3.0, extsprintf@^1.2.0:
+extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
-fancy-log@^1.1.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.0.tgz#45be17d02bb9917d60ccffd4995c999e6c8c9948"
- dependencies:
- chalk "^1.1.1"
- time-stamp "^1.0.0"
+extsprintf@^1.2.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
fast-deep-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
+fast-json-stable-stringify@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
+
fast-levenshtein@~2.0.4:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+fast-memoize@^2.2.7:
+ version "2.2.8"
+ resolved "https://registry.yarnpkg.com/fast-memoize/-/fast-memoize-2.2.8.tgz#d7f899f31d037b12d9db4281912f9018575720b1"
+
fastparse@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
+fb-watchman@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
+ dependencies:
+ bser "^2.0.0"
+
fbemitter@^2.0.2:
version "2.1.1"
resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-2.1.1.tgz#523e14fdaf5248805bb02f62efc33be703f51865"
dependencies:
fbjs "^0.8.4"
-fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.9, fbjs@~0:
+fbjs@^0.8.1, fbjs@^0.8.12, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.9, fbjs@~0:
version "0.8.16"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
dependencies:
@@ -2999,11 +3728,12 @@ fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.9, fbjs@~0:
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
-fetch-ponyfill@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893"
+figures@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
dependencies:
- node-fetch "~1.7.1"
+ escape-string-regexp "^1.0.5"
+ object-assign "^4.1.0"
figures@^2.0.0:
version "2.0.0"
@@ -3018,19 +3748,33 @@ file-entry-cache@^2.0.0:
flat-cache "^1.2.1"
object-assign "^4.0.1"
-file-loader@^0.11.2:
+file-loader@0.11.2:
version "0.11.2"
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.11.2.tgz#4ff1df28af38719a6098093b88c82c71d1794a34"
dependencies:
loader-utils "^1.0.2"
+file-loader@^1.1.6:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-1.1.6.tgz#7b9a8f2c58f00a77fddf49e940f7ac978a3ea0e8"
+ dependencies:
+ loader-utils "^1.0.2"
+ schema-utils "^0.3.0"
+
filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
+fileset@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0"
+ dependencies:
+ glob "^7.0.3"
+ minimatch "^3.0.3"
+
filesize@^3.5.9:
- version "3.5.10"
- resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.10.tgz#fc8fa23ddb4ef9e5e0ab6e1e64f679a24a56761f"
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.0.tgz#22d079615624bb6fd3c04026120628a41b3f4efa"
fill-range@^2.1.0:
version "2.2.3"
@@ -3042,18 +3786,6 @@ fill-range@^2.1.0:
repeat-element "^1.1.2"
repeat-string "^1.5.2"
-finalhandler@1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.6.tgz#007aea33d1a4d3e42017f624848ad58d212f814f"
- dependencies:
- debug "2.6.9"
- encodeurl "~1.0.1"
- escape-html "~1.0.3"
- on-finished "~2.3.0"
- parseurl "~1.3.2"
- statuses "~1.3.1"
- unpipe "~1.0.0"
-
finalhandler@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5"
@@ -3074,9 +3806,9 @@ find-cache-dir@^1.0.0:
make-dir "^1.0.0"
pkg-dir "^2.0.0"
-find-index@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4"
+find-parent-dir@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.0.tgz#33c44b429ab2b2f0646299c5f9f718f376ff8d54"
find-up@^1.0.0:
version "1.1.2"
@@ -3091,42 +3823,6 @@ find-up@^2.0.0, find-up@^2.1.0:
dependencies:
locate-path "^2.0.0"
-findup-sync@^0.4.2:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12"
- dependencies:
- detect-file "^0.1.0"
- is-glob "^2.0.1"
- micromatch "^2.3.7"
- resolve-dir "^0.1.0"
-
-findup-sync@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-1.0.0.tgz#6f7e4b57b6ee3a4037b4414eaedea3f58f71e0ec"
- dependencies:
- detect-file "^0.1.0"
- is-glob "^2.0.1"
- micromatch "^2.3.7"
- resolve-dir "^0.1.0"
-
-fined@^1.0.1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/fined/-/fined-1.1.0.tgz#b37dc844b76a2f5e7081e884f7c0ae344f153476"
- dependencies:
- expand-tilde "^2.0.2"
- is-plain-object "^2.0.3"
- object.defaults "^1.1.0"
- object.pick "^1.2.0"
- parse-filepath "^1.0.1"
-
-first-chunk-stream@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e"
-
-flagged-respawn@^0.3.2:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5"
-
flat-cache@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481"
@@ -3140,12 +3836,6 @@ flatten@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
-flux-standard-action@^0.6.0:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/flux-standard-action/-/flux-standard-action-0.6.1.tgz#6f34211b94834ea1c3cc30f4e7afad3d0fbf71a2"
- dependencies:
- lodash.isplainobject "^3.2.0"
-
for-in@^0.1.3:
version "0.1.8"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
@@ -3170,7 +3860,7 @@ foreach@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
-forever-agent@~0.6.0, forever-agent@~0.6.1:
+forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
@@ -3182,14 +3872,6 @@ form-data@1.0.0-rc3:
combined-stream "^1.0.5"
mime-types "^2.1.3"
-form-data@~1.0.0-rc1, form-data@~1.0.0-rc4:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c"
- dependencies:
- async "^2.0.1"
- combined-stream "^1.0.5"
- mime-types "^2.1.11"
-
form-data@~2.1.1:
version "2.1.4"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1"
@@ -3220,7 +3902,14 @@ forwarded@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
-foundation-sites@^6.2.3, "foundation-sites@git+https://github.com/steemit/foundation-sites.git#e8e32c715bbc4c822b80b555345f61337269ca78":
+foundation-sites@^6.2.3:
+ version "6.4.3"
+ resolved "https://registry.yarnpkg.com/foundation-sites/-/foundation-sites-6.4.3.tgz#ea89eb599badf6f03dd526c51f00bdb942a844f6"
+ dependencies:
+ jquery ">=3.0.0"
+ what-input "^4.1.3"
+
+"foundation-sites@git+https://github.com/steemit/foundation-sites.git#e8e32c715bbc4c822b80b555345f61337269ca78":
version "6.3.1"
resolved "git+https://github.com/steemit/foundation-sites.git#e8e32c715bbc4c822b80b555345f61337269ca78"
dependencies:
@@ -3235,10 +3924,6 @@ fresh@0.5.2, fresh@^0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
-fs-exists-sync@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
-
fs-extra@^0.30.0:
version "0.30.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0"
@@ -3249,15 +3934,19 @@ fs-extra@^0.30.0:
path-is-absolute "^1.0.0"
rimraf "^2.2.8"
-fs-extra@^4.0.1:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b"
+fs-extra@^4.0.2:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^4.0.0"
universalify "^0.1.0"
-fs-readdir-recursive@^1.0.0, fs-readdir-recursive@~1.0.0:
+fs-readdir-recursive@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27"
+
+fs-readdir-recursive@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz#8cd1745c8b4f8a29c8caec392476921ba195f560"
@@ -3265,12 +3954,12 @@ fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
-fsevents@*, fsevents@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4"
+fsevents@^1.0.0, fsevents@^1.1.1:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8"
dependencies:
nan "^2.3.0"
- node-pre-gyp "^0.6.36"
+ node-pre-gyp "^0.6.39"
fstream-ignore@^1.0.5:
version "1.0.5"
@@ -3293,18 +3982,22 @@ function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
-function.prototype.name@^1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.0.3.tgz#0099ae5572e9dd6f03c97d023fd92bcc5e639eac"
+function.prototype.name@^1.0.3, function.prototype.name@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.0.tgz#8bd763cc0af860a859cc5d49384d74b932cd2327"
dependencies:
define-properties "^1.1.2"
- function-bind "^1.1.0"
+ function-bind "^1.1.1"
is-callable "^1.1.3"
functional-red-black-tree@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
+fuse.js@^3.0.1, fuse.js@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.2.0.tgz#f0448e8069855bf2a3e683cdc1d320e7e2a07ef4"
+
gauge@~2.7.3:
version "2.7.4"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
@@ -3318,12 +4011,6 @@ gauge@~2.7.3:
strip-ansi "^3.0.1"
wide-align "^1.1.0"
-gaze@^0.5.1:
- version "0.5.2"
- resolved "https://registry.yarnpkg.com/gaze/-/gaze-0.5.2.tgz#40b709537d24d1d45767db5a908689dfe69ac44f"
- dependencies:
- globule "~0.1.0"
-
gaze@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105"
@@ -3348,6 +4035,10 @@ get-caller-file@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
+get-own-enumerable-property-symbols@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-2.0.1.tgz#5c4ad87f2834c4b9b4e84549dc1e0650fb38c24b"
+
get-stdin@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
@@ -3362,7 +4053,7 @@ getpass@^0.1.1:
dependencies:
assert-plus "^1.0.0"
-git-rev-sync@^1.9.1:
+git-rev-sync@1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/git-rev-sync/-/git-rev-sync-1.9.1.tgz#a0c2e3dd392abcf6b76962e27fc75fb3223449ce"
dependencies:
@@ -3370,6 +4061,28 @@ git-rev-sync@^1.9.1:
graceful-fs "4.1.11"
shelljs "0.7.7"
+glamor@^2.20.40:
+ version "2.20.40"
+ resolved "https://registry.yarnpkg.com/glamor/-/glamor-2.20.40.tgz#f606660357b7cf18dface731ad1a2cfa93817f05"
+ dependencies:
+ fbjs "^0.8.12"
+ inline-style-prefixer "^3.0.6"
+ object-assign "^4.1.1"
+ prop-types "^15.5.10"
+ through "^2.3.8"
+
+glamorous@^4.11.2:
+ version "4.11.4"
+ resolved "https://registry.yarnpkg.com/glamorous/-/glamorous-4.11.4.tgz#61b333e1ec552abbe48e2fea48fea89fc0026149"
+ dependencies:
+ brcast "^3.0.0"
+ fast-memoize "^2.2.7"
+ html-tag-names "^1.1.1"
+ is-function "^1.0.1"
+ is-plain-object "^2.0.4"
+ react-html-attributes "^1.3.0"
+ svg-tag-names "^1.1.0"
+
glob-base@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
@@ -3383,46 +4096,17 @@ glob-parent@^2.0.0:
dependencies:
is-glob "^2.0.0"
-glob-stream@^3.1.5:
- version "3.1.18"
- resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-3.1.18.tgz#9170a5f12b790306fdfe598f313f8f7954fd143b"
- dependencies:
- glob "^4.3.1"
- glob2base "^0.0.12"
- minimatch "^2.0.1"
- ordered-read-streams "^0.1.0"
- through2 "^0.6.1"
- unique-stream "^1.0.0"
-
-glob-watcher@^0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-0.0.6.tgz#b95b4a8df74b39c83298b0c05c978b4d9a3b710b"
- dependencies:
- gaze "^0.5.1"
-
-glob2base@^0.0.12:
- version "0.0.12"
- resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56"
- dependencies:
- find-index "^0.1.1"
-
-glob@3.2.11:
- version "3.2.11"
- resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d"
- dependencies:
- inherits "2"
- minimatch "0.3"
-
-glob@^4.3.1:
- version "4.5.3"
- resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f"
+glob@^6.0.4:
+ version "6.0.4"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
dependencies:
inflight "^1.0.4"
inherits "2"
- minimatch "^2.0.1"
+ minimatch "2 || 3"
once "^1.3.0"
+ path-is-absolute "^1.0.0"
-glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2, glob@~7.1.1:
+glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies:
@@ -3433,31 +4117,7 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2, glob@~7.1.1:
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@~3.1.21:
- version "3.1.21"
- resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd"
- dependencies:
- graceful-fs "~1.2.0"
- inherits "1"
- minimatch "~0.2.11"
-
-global-modules@^0.2.3:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
- dependencies:
- global-prefix "^0.1.4"
- is-windows "^0.2.0"
-
-global-prefix@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f"
- dependencies:
- homedir-polyfill "^1.0.0"
- ini "^1.3.4"
- is-windows "^0.2.0"
- which "^1.2.12"
-
-global@^4.3.0:
+global@^4.3.0, global@^4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f"
dependencies:
@@ -3487,106 +4147,13 @@ globule@^1.0.0:
lodash "~4.17.4"
minimatch "~3.0.2"
-globule@~0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/globule/-/globule-0.1.0.tgz#d9c8edde1da79d125a151b79533b978676346ae5"
- dependencies:
- glob "~3.1.21"
- lodash "~1.0.1"
- minimatch "~0.2.11"
-
-glogg@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.0.tgz#7fe0f199f57ac906cf512feead8f90ee4a284fc5"
- dependencies:
- sparkles "^1.0.0"
-
-graceful-fs@4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
+graceful-fs@4.1.11, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
-graceful-fs@^3.0.0:
- version "3.0.11"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818"
- dependencies:
- natives "^1.1.0"
-
-graceful-fs@~1.2.0:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364"
-
-grant-koa@^3.6.0:
- version "3.8.0"
- resolved "https://registry.yarnpkg.com/grant-koa/-/grant-koa-3.8.0.tgz#21e9c7a9b6cf747e6150f2cb44ca07c2d412ed70"
- dependencies:
- grant "3.8.0"
- thunkify "2.1.2"
-
-grant@3.8.0:
- version "3.8.0"
- resolved "https://registry.yarnpkg.com/grant/-/grant-3.8.0.tgz#c3133f864d11838b5ebeac2d7c882d976884df44"
- dependencies:
- deep-copy "^1.2.0"
- qs "6.4.0"
- request "2.81.0"
-
-growl@1.9.2:
- version "1.9.2"
- resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f"
-
-gulp-help@~1.6.1:
- version "1.6.1"
- resolved "https://registry.yarnpkg.com/gulp-help/-/gulp-help-1.6.1.tgz#261db186e18397fef3f6a2c22e9c315bfa88ae0c"
- dependencies:
- chalk "^1.0.0"
- object-assign "^3.0.0"
-
-gulp-util@^3.0.0:
- version "3.0.8"
- resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f"
- dependencies:
- array-differ "^1.0.0"
- array-uniq "^1.0.2"
- beeper "^1.0.0"
- chalk "^1.0.0"
- dateformat "^2.0.0"
- fancy-log "^1.1.0"
- gulplog "^1.0.0"
- has-gulplog "^0.1.0"
- lodash._reescape "^3.0.0"
- lodash._reevaluate "^3.0.0"
- lodash._reinterpolate "^3.0.0"
- lodash.template "^3.0.0"
- minimist "^1.1.0"
- multipipe "^0.1.2"
- object-assign "^3.0.0"
- replace-ext "0.0.1"
- through2 "^2.0.0"
- vinyl "^0.5.0"
-
-gulp@^3.9.1:
- version "3.9.1"
- resolved "https://registry.yarnpkg.com/gulp/-/gulp-3.9.1.tgz#571ce45928dd40af6514fc4011866016c13845b4"
- dependencies:
- archy "^1.0.0"
- chalk "^1.0.0"
- deprecated "^0.0.1"
- gulp-util "^3.0.0"
- interpret "^1.0.0"
- liftoff "^2.1.0"
- minimist "^1.1.0"
- orchestrator "^0.3.0"
- pretty-hrtime "^1.0.0"
- semver "^4.1.0"
- tildify "^1.0.0"
- v8flags "^2.0.2"
- vinyl-fs "^0.3.0"
-
-gulplog@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5"
- dependencies:
- glogg "^1.0.0"
+growly@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
gzip-size@^3.0.0:
version "3.0.0"
@@ -3594,9 +4161,9 @@ gzip-size@^3.0.0:
dependencies:
duplexer "^0.1.1"
-handlebars@~4.0.0:
- version "4.0.10"
- resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f"
+handlebars@^4.0.3:
+ version "4.0.11"
+ resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc"
dependencies:
async "^1.4.0"
optimist "^0.6.1"
@@ -3612,15 +4179,6 @@ har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
-har-validator@^1.6.1:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-1.8.0.tgz#d83842b0eb4c435960aeb108a067a3aa94c0eeb2"
- dependencies:
- bluebird "^2.9.30"
- chalk "^1.0.0"
- commander "^2.8.1"
- is-my-json-valid "^2.12.0"
-
har-validator@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d"
@@ -3658,11 +4216,9 @@ has-flag@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
-has-gulplog@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce"
- dependencies:
- sparkles "^1.0.0"
+has-symbols@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
has-unicode@^2.0.0:
version "2.0.1"
@@ -3694,7 +4250,7 @@ hash.js@^1.0.0, hash.js@^1.0.3:
inherits "^2.0.3"
minimalistic-assert "^1.0.0"
-hawk@3.1.3, hawk@~3.1.0, hawk@~3.1.3:
+hawk@3.1.3, hawk@~3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
dependencies:
@@ -3712,26 +4268,25 @@ hawk@~6.0.2:
hoek "4.x.x"
sntp "2.x.x"
-helmet-csp@2.5.1:
- version "2.5.1"
- resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.5.1.tgz#5f3deec8f922fa7e074dbc3987c168a50573c36d"
+helmet-csp@2.7.0:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.7.0.tgz#7934094617d1feb7bb2dc43bb7d9e8830f774716"
dependencies:
camelize "1.0.0"
- content-security-policy-builder "1.1.0"
+ content-security-policy-builder "2.0.0"
dasherize "2.0.0"
lodash.reduce "4.6.0"
- platform "1.3.4"
+ platform "1.3.5"
helmet@^3.6.1:
- version "3.8.2"
- resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.8.2.tgz#64f988b8e9d8773ad201da455b8b6a754c229aaa"
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.10.0.tgz#96a2a9fec53c26009d3d6265c6cfdada38ddfa7f"
dependencies:
- connect "3.6.5"
dns-prefetch-control "0.1.0"
dont-sniff-mimetype "1.0.0"
expect-ct "0.1.0"
frameguard "3.0.0"
- helmet-csp "2.5.1"
+ helmet-csp "2.7.0"
hide-powered-by "1.0.0"
hpkp "2.0.0"
hsts "2.1.0"
@@ -3744,7 +4299,7 @@ hide-powered-by@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b"
-highcharts@^4.2.3, highcharts@^4.2.5:
+highcharts@4.2.7, highcharts@^4.2.3:
version "4.2.7"
resolved "https://registry.yarnpkg.com/highcharts/-/highcharts-4.2.7.tgz#45cbed8e99c9c042e95f9c51076726496f686862"
@@ -3773,7 +4328,7 @@ hoek@4.x.x:
version "4.2.0"
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d"
-hoist-non-react-statics@^1.0.5, hoist-non-react-statics@^1.2.0:
+hoist-non-react-statics@1.x.x, hoist-non-react-statics@^1.0.5, hoist-non-react-statics@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb"
@@ -3788,12 +4343,6 @@ home-or-tmp@^2.0.0:
os-homedir "^1.0.0"
os-tmpdir "^1.0.1"
-homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc"
- dependencies:
- parse-passwd "^1.0.0"
-
hosted-git-info@^2.1.4:
version "2.5.0"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c"
@@ -3810,9 +4359,13 @@ html-comment-regex@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e"
-html-encoding-sniffer@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da"
+html-element-attributes@^1.0.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/html-element-attributes/-/html-element-attributes-1.3.0.tgz#f06ebdfce22de979db82020265cac541fb17d4fc"
+
+html-encoding-sniffer@^1.0.1, html-encoding-sniffer@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8"
dependencies:
whatwg-encoding "^1.0.1"
@@ -3820,6 +4373,10 @@ html-entities@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
+html-tag-names@^1.1.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/html-tag-names/-/html-tag-names-1.1.2.tgz#f65168964c5a9c82675efda882875dcb2a875c22"
+
htmlparser2@^3.9.0, htmlparser2@^3.9.1:
version "3.9.2"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338"
@@ -3859,14 +4416,6 @@ http-response-object@^1.0.0, http-response-object@^1.0.1, http-response-object@^
version "1.1.0"
resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-1.1.0.tgz#a7c4e75aae82f3bb4904e4f43f615673b4d518c3"
-http-signature@~0.11.0:
- version "0.11.0"
- resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.11.0.tgz#1796cf67a001ad5cd6849dca0991485f09089fe6"
- dependencies:
- asn1 "0.1.11"
- assert-plus "^0.1.5"
- ctype "0.5.3"
-
http-signature@~1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
@@ -3889,19 +4438,34 @@ http_ece@^0.5.2:
dependencies:
urlsafe-base64 "~1.0.0"
-https-browserify@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
+https-browserify@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
+
+https-proxy-agent@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.1.1.tgz#a7ce4382a1ba8266ee848578778122d491260fd9"
+ dependencies:
+ agent-base "^4.1.0"
+ debug "^3.1.0"
humanize-number@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/humanize-number/-/humanize-number-0.0.2.tgz#11c0af6a471643633588588048f1799541489c18"
-iconv-lite@0.4.13, iconv-lite@~0.4.13:
- version "0.4.13"
- resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
+husky@0.14.3:
+ version "0.14.3"
+ resolved "https://registry.yarnpkg.com/husky/-/husky-0.14.3.tgz#c69ed74e2d2779769a17ba8399b54ce0b63c12c3"
+ dependencies:
+ is-ci "^1.0.10"
+ normalize-path "^1.0.0"
+ strip-indent "^2.0.0"
+
+hyphenate-style-name@^1.0.1, hyphenate-style-name@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b"
-iconv-lite@0.4.19, iconv-lite@^0.4.17:
+iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@~0.4.13:
version "0.4.19"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
@@ -3928,14 +4492,21 @@ ienoopen@1.0.0:
resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.0.0.tgz#346a428f474aac8f50cf3784ea2d0f16f62bda6b"
ignore@^3.3.3:
- version "3.3.5"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.5.tgz#c4e715455f6073a8d7e5dae72d2fc9d71663dba6"
+ version "3.3.7"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021"
-immutable@^3.7.4, immutable@^3.7.6, immutable@^3.8.1:
+immutable@^3.7.4, immutable@^3.8.1:
version "3.8.2"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"
-imports-loader@^0.7.1:
+import-local@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc"
+ dependencies:
+ pkg-dir "^2.0.0"
+ resolve-cwd "^2.0.0"
+
+imports-loader@0.7.1:
version "0.7.1"
resolved "https://registry.yarnpkg.com/imports-loader/-/imports-loader-0.7.1.tgz#f204b5f34702a32c1db7d48d89d5e867a0441253"
dependencies:
@@ -3956,6 +4527,10 @@ indent-string@^2.1.0:
dependencies:
repeating "^2.0.0"
+indent-string@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289"
+
indexes-of@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
@@ -3964,7 +4539,7 @@ indexof@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
-inflation@~2.0.0:
+inflation@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/inflation/-/inflation-2.0.0.tgz#8b417e47c28f925a45133d914ca1fd389107f30f"
@@ -3979,23 +4554,33 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
-inherits@1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b"
+inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
-inherits@2, inherits@2.0.1, inherits@^2.0.1:
+inherits@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
-inherits@2.0.3, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
-
ini@^1.3.4, ini@~1.3.0:
- version "1.3.4"
- resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
-inquirer@^3.0.6:
+inline-style-prefixer@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz#c153c7e88fd84fef5c602e95a8168b2770671fe7"
+ dependencies:
+ bowser "^1.0.0"
+ hyphenate-style-name "^1.0.1"
+
+inline-style-prefixer@^3.0.6:
+ version "3.0.8"
+ resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-3.0.8.tgz#8551b8e5b4d573244e66a34b04f7d32076a2b534"
+ dependencies:
+ bowser "^1.7.3"
+ css-in-js-utils "^2.0.0"
+
+inquirer@^3.0.6, inquirer@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9"
dependencies:
@@ -4014,31 +4599,31 @@ inquirer@^3.0.6:
strip-ansi "^4.0.0"
through "^2.3.6"
+insert-css@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/insert-css/-/insert-css-2.0.0.tgz#eb5d1097b7542f4c79ea3060d3aee07d053880f4"
+
int64-buffer@^0.1.9:
- version "0.1.9"
- resolved "https://registry.yarnpkg.com/int64-buffer/-/int64-buffer-0.1.9.tgz#9e039da043b24f78b196b283e04653ef5e990f61"
+ version "0.1.10"
+ resolved "https://registry.yarnpkg.com/int64-buffer/-/int64-buffer-0.1.10.tgz#277b228a87d95ad777d07c13832022406a473423"
interpret@^1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0"
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
intl-format-cache@^2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-2.0.5.tgz#b484cefcb9353f374f25de389a3ceea1af18d7c9"
-
-intl-messageformat-parser@1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.2.0.tgz#5906b7f953ab7470e0dc8549097b648b991892ff"
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-2.1.0.tgz#04a369fecbfad6da6005bae1f14333332dcf9316"
-intl-messageformat-parser@^1.2.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.3.0.tgz#c5d26ffb894c7d9c2b9fa444c67f417ab2594268"
+intl-messageformat-parser@1.4.0, intl-messageformat-parser@^1.2.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.4.0.tgz#b43d45a97468cadbe44331d74bb1e8dea44fc075"
intl-messageformat@^2.0.0, intl-messageformat@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.1.0.tgz#1c51da76f02a3f7b360654cdc51bbc4d3fa6c72c"
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.2.0.tgz#345bcd46de630b7683330c2e52177ff5eab484fc"
dependencies:
- intl-messageformat-parser "1.2.0"
+ intl-messageformat-parser "1.4.0"
intl-relativeformat@^2.0.0:
version "2.1.0"
@@ -4046,7 +4631,7 @@ intl-relativeformat@^2.0.0:
dependencies:
intl-messageformat "^2.0.0"
-intl@^1.2.5:
+intl@1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/intl/-/intl-1.2.5.tgz#82244a2190c4e419f8371f5aa34daa3420e2abde"
@@ -4068,13 +4653,6 @@ 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"
-is-absolute@^0.2.3:
- version "0.2.6"
- resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-0.2.6.tgz#20de69f3db942ef2d87b9c2da36f172235b1b5eb"
- dependencies:
- is-relative "^0.2.1"
- is-windows "^0.2.0"
-
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@@ -4085,9 +4663,13 @@ is-binary-path@^1.0.0:
dependencies:
binary-extensions "^1.0.0"
+is-boolean-object@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.0.tgz#98f8b28030684219a95f375cfbd88ce3405dff93"
+
is-buffer@^1.0.2, is-buffer@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
is-builtin-module@^1.0.0:
version "1.0.0"
@@ -4099,10 +4681,24 @@ is-callable@^1.1.1, is-callable@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2"
+is-ci@^1.0.10:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5"
+ dependencies:
+ ci-info "^1.0.0"
+
is-date-object@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
+is-directory@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
+
+is-dom@^1.0.9:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/is-dom/-/is-dom-1.0.9.tgz#483832d52972073de12b9fe3f60320870da8370d"
+
is-dotfile@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
@@ -4121,6 +4717,10 @@ is-extglob@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+
is-finite@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
@@ -4137,9 +4737,13 @@ 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"
-is-generator@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/is-generator/-/is-generator-1.0.3.tgz#c14c21057ed36e328db80347966c693f886389f3"
+is-function@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5"
+
+is-generator-fn@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-1.0.0.tgz#969d49e1bb3329f6bb7f09089be26578b2ddd46a"
is-glob@^2.0.0, is-glob@^2.0.1:
version "2.0.1"
@@ -4147,15 +4751,25 @@ is-glob@^2.0.0, is-glob@^2.0.1:
dependencies:
is-extglob "^1.0.0"
-is-my-json-valid@^2.12.0, is-my-json-valid@^2.12.4:
- version "2.16.1"
- resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11"
+is-glob@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
dependencies:
- generate-function "^2.0.0"
+ is-extglob "^2.1.1"
+
+is-my-json-valid@^2.12.4:
+ version "2.17.1"
+ resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471"
+ dependencies:
+ generate-function "^2.0.0"
generate-object-property "^1.1.0"
jsonpointer "^4.0.0"
xtend "^4.0.0"
+is-number-object@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.3.tgz#f265ab89a9f445034ef6aff15a8f00b00f551799"
+
is-number@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
@@ -4168,6 +4782,16 @@ is-number@^3.0.0:
dependencies:
kind-of "^3.0.2"
+is-obj@^1.0.0, is-obj@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
+
+is-observable@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-0.2.0.tgz#b361311d83c6e5d726cabf5e250b0237106f5ae2"
+ dependencies:
+ symbol-observable "^0.2.2"
+
is-path-cwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
@@ -4179,8 +4803,8 @@ is-path-in-cwd@^1.0.0:
is-path-inside "^1.0.0"
is-path-inside@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f"
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
dependencies:
path-is-inside "^1.0.1"
@@ -4188,7 +4812,7 @@ 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"
-is-plain-object@^2.0.1, is-plain-object@^2.0.3:
+is-plain-object@^2.0.1, 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"
dependencies:
@@ -4216,22 +4840,22 @@ is-regex@^1.0.4:
dependencies:
has "^1.0.1"
-is-relative@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.2.1.tgz#d27f4c7d516d175fb610db84bbeef23c3bc97aa5"
- dependencies:
- is-unc-path "^0.1.1"
+is-regexp@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
is-resolvable@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62"
- dependencies:
- tryit "^1.0.1"
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88"
is-stream@^1.0.1, is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+is-string@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.4.tgz#cc3a9b69857d621e963725a24caeec873b826e64"
+
is-subset@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6"
@@ -4250,20 +4874,10 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
-is-unc-path@^0.1.1:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-0.1.2.tgz#6ab053a72573c10250ff416a3814c35178af39b9"
- dependencies:
- unc-path-regex "^0.1.0"
-
is-utf8@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
-is-windows@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
-
is-windows@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.1.tgz#310db70f742d259a16a369202b51af84233310d9"
@@ -4280,7 +4894,7 @@ isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
-iso@^5.1.0:
+iso@5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/iso/-/iso-5.2.0.tgz#50fe58c5c25d94c8564634a4c0d4b12af7595180"
@@ -4290,7 +4904,7 @@ isobject@^2.0.0:
dependencies:
isarray "1.0.0"
-isobject@^3.0.0, isobject@^3.0.1:
+isobject@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
@@ -4301,38 +4915,347 @@ isomorphic-fetch@^2.1.1:
node-fetch "^1.0.1"
whatwg-fetch ">=0.10.0"
-isstream@~0.1.1, isstream@~0.1.2:
+isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
-jade@0.26.3:
- version "0.26.3"
- resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c"
+istanbul-api@^1.1.14:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.2.1.tgz#0c60a0515eb11c7d65c6b50bba2c6e999acd8620"
+ dependencies:
+ async "^2.1.4"
+ fileset "^2.0.2"
+ istanbul-lib-coverage "^1.1.1"
+ istanbul-lib-hook "^1.1.0"
+ istanbul-lib-instrument "^1.9.1"
+ istanbul-lib-report "^1.1.2"
+ istanbul-lib-source-maps "^1.2.2"
+ istanbul-reports "^1.1.3"
+ js-yaml "^3.7.0"
+ mkdirp "^0.5.1"
+ once "^1.4.0"
+
+istanbul-lib-coverage@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz#73bfb998885299415c93d38a3e9adf784a77a9da"
+
+istanbul-lib-hook@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.1.0.tgz#8538d970372cb3716d53e55523dd54b557a8d89b"
+ dependencies:
+ append-transform "^0.4.0"
+
+istanbul-lib-instrument@^1.7.5, istanbul-lib-instrument@^1.8.0, istanbul-lib-instrument@^1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.9.1.tgz#250b30b3531e5d3251299fdd64b0b2c9db6b558e"
dependencies:
- commander "0.6.1"
- mkdirp "0.3.0"
+ babel-generator "^6.18.0"
+ babel-template "^6.16.0"
+ babel-traverse "^6.18.0"
+ babel-types "^6.18.0"
+ babylon "^6.18.0"
+ istanbul-lib-coverage "^1.1.1"
+ semver "^5.3.0"
-jquery-sortable@~0.9.12:
- version "0.9.13"
- resolved "https://registry.yarnpkg.com/jquery-sortable/-/jquery-sortable-0.9.13.tgz#1cbfb655013a0747370571f06e22f524a00ffba2"
+istanbul-lib-report@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.2.tgz#922be27c13b9511b979bd1587359f69798c1d425"
dependencies:
- jquery "^2.1.2"
+ istanbul-lib-coverage "^1.1.1"
+ mkdirp "^0.5.1"
+ path-parse "^1.0.5"
+ supports-color "^3.1.2"
-jquery@>=1.9.0, jquery@>=3.0.0:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787"
+istanbul-lib-source-maps@^1.2.1, istanbul-lib-source-maps@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.2.tgz#750578602435f28a0c04ee6d7d9e0f2960e62c1c"
+ dependencies:
+ debug "^3.1.0"
+ istanbul-lib-coverage "^1.1.1"
+ mkdirp "^0.5.1"
+ rimraf "^2.6.1"
+ source-map "^0.5.3"
-jquery@^2.1.2:
- version "2.2.4"
- resolved "https://registry.yarnpkg.com/jquery/-/jquery-2.2.4.tgz#2c89d6889b5eac522a7eea32c14521559c6cbf02"
+istanbul-reports@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.1.3.tgz#3b9e1e8defb6d18b1d425da8e8b32c5a163f2d10"
+ dependencies:
+ handlebars "^4.0.3"
+
+jest-changed-files@^22.1.4:
+ version "22.1.4"
+ resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-22.1.4.tgz#1f7844bcb739dec07e5899a633c0cb6d5069834e"
+ dependencies:
+ throat "^4.0.0"
+
+jest-cli@^22.0.6:
+ version "22.1.4"
+ resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-22.1.4.tgz#0fe9f3ac881b0cdc00227114c58583a2ebefcc04"
+ dependencies:
+ ansi-escapes "^3.0.0"
+ chalk "^2.0.1"
+ exit "^0.1.2"
+ glob "^7.1.2"
+ graceful-fs "^4.1.11"
+ import-local "^1.0.0"
+ is-ci "^1.0.10"
+ istanbul-api "^1.1.14"
+ istanbul-lib-coverage "^1.1.1"
+ istanbul-lib-instrument "^1.8.0"
+ istanbul-lib-source-maps "^1.2.1"
+ jest-changed-files "^22.1.4"
+ jest-config "^22.1.4"
+ jest-environment-jsdom "^22.1.4"
+ jest-get-type "^22.1.0"
+ jest-haste-map "^22.1.0"
+ jest-message-util "^22.1.0"
+ jest-regex-util "^22.1.0"
+ jest-resolve-dependencies "^22.1.0"
+ jest-runner "^22.1.4"
+ jest-runtime "^22.1.4"
+ jest-snapshot "^22.1.2"
+ jest-util "^22.1.4"
+ jest-worker "^22.1.0"
+ micromatch "^2.3.11"
+ node-notifier "^5.1.2"
+ realpath-native "^1.0.0"
+ rimraf "^2.5.4"
+ slash "^1.0.0"
+ string-length "^2.0.0"
+ strip-ansi "^4.0.0"
+ which "^1.2.12"
+ yargs "^10.0.3"
+
+jest-config@^22.1.4:
+ version "22.1.4"
+ resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-22.1.4.tgz#075ffacce83c3e38cf85b1b9ba0d21bd3ee27ad0"
+ dependencies:
+ chalk "^2.0.1"
+ glob "^7.1.1"
+ jest-environment-jsdom "^22.1.4"
+ jest-environment-node "^22.1.4"
+ jest-get-type "^22.1.0"
+ jest-jasmine2 "^22.1.4"
+ jest-regex-util "^22.1.0"
+ jest-resolve "^22.1.4"
+ jest-util "^22.1.4"
+ jest-validate "^22.1.2"
+ pretty-format "^22.1.0"
+
+jest-diff@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-22.1.0.tgz#0fad9d96c87b453896bf939df3dc8aac6919ac38"
+ dependencies:
+ chalk "^2.0.1"
+ diff "^3.2.0"
+ jest-get-type "^22.1.0"
+ pretty-format "^22.1.0"
+
+jest-docblock@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-22.1.0.tgz#3fe5986d5444cbcb149746eb4b07c57c5a464dfd"
+ dependencies:
+ detect-newline "^2.1.0"
+
+jest-environment-jsdom@^22.1.4:
+ version "22.1.4"
+ resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-22.1.4.tgz#704518ce8375f7ec5de048d1e9c4268b08a03e00"
+ dependencies:
+ jest-mock "^22.1.0"
+ jest-util "^22.1.4"
+ jsdom "^11.5.1"
+
+jest-environment-node@^22.1.4:
+ version "22.1.4"
+ resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-22.1.4.tgz#0f2946e8f8686ce6c5d8fa280ce1cd8d58e869eb"
+ dependencies:
+ jest-mock "^22.1.0"
+ jest-util "^22.1.4"
+
+jest-get-type@^21.2.0:
+ version "21.2.0"
+ resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-21.2.0.tgz#f6376ab9db4b60d81e39f30749c6c466f40d4a23"
+
+jest-get-type@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.1.0.tgz#4e90af298ed6181edc85d2da500dbd2753e0d5a9"
+
+jest-haste-map@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-22.1.0.tgz#1174c6ff393f9818ebf1163710d8868b5370da2a"
+ dependencies:
+ fb-watchman "^2.0.0"
+ graceful-fs "^4.1.11"
+ jest-docblock "^22.1.0"
+ jest-worker "^22.1.0"
+ micromatch "^2.3.11"
+ sane "^2.0.0"
+
+jest-jasmine2@^22.1.4:
+ version "22.1.4"
+ resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-22.1.4.tgz#cada0baf50a220c616a9575728b80d4ddedebe8b"
+ dependencies:
+ callsites "^2.0.0"
+ chalk "^2.0.1"
+ co "^4.6.0"
+ expect "^22.1.0"
+ graceful-fs "^4.1.11"
+ is-generator-fn "^1.0.0"
+ jest-diff "^22.1.0"
+ jest-matcher-utils "^22.1.0"
+ jest-message-util "^22.1.0"
+ jest-snapshot "^22.1.2"
+ source-map-support "^0.5.0"
+
+jest-leak-detector@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-22.1.0.tgz#08376644cee07103da069baac19adb0299b772c2"
+ dependencies:
+ pretty-format "^22.1.0"
+
+jest-matcher-utils@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-22.1.0.tgz#e164665b5d313636ac29f7f6fe9ef0a6ce04febc"
+ dependencies:
+ chalk "^2.0.1"
+ jest-get-type "^22.1.0"
+ pretty-format "^22.1.0"
+
+jest-message-util@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-22.1.0.tgz#51ba0794cb6e579bfc4e9adfac452f9f1a0293fc"
+ dependencies:
+ "@babel/code-frame" "^7.0.0-beta.35"
+ chalk "^2.0.1"
+ micromatch "^2.3.11"
+ slash "^1.0.0"
+ stack-utils "^1.0.1"
+
+jest-mock@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-22.1.0.tgz#87ec21c0599325671c9a23ad0e05c86fb5879b61"
+
+jest-regex-util@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-22.1.0.tgz#5daf2fe270074b6da63e5d85f1c9acc866768f53"
+
+jest-resolve-dependencies@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-22.1.0.tgz#340e4139fb13315cd43abc054e6c06136be51e31"
+ dependencies:
+ jest-regex-util "^22.1.0"
+
+jest-resolve@^22.1.4:
+ version "22.1.4"
+ resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-22.1.4.tgz#72b9b371eaac48f84aad4ad732222ffe37692602"
+ dependencies:
+ browser-resolve "^1.11.2"
+ chalk "^2.0.1"
+
+jest-runner@^22.1.4:
+ version "22.1.4"
+ resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-22.1.4.tgz#e039039110cb1b31febc0f99e349bf7c94304a2f"
+ dependencies:
+ exit "^0.1.2"
+ jest-config "^22.1.4"
+ jest-docblock "^22.1.0"
+ jest-haste-map "^22.1.0"
+ jest-jasmine2 "^22.1.4"
+ jest-leak-detector "^22.1.0"
+ jest-message-util "^22.1.0"
+ jest-runtime "^22.1.4"
+ jest-util "^22.1.4"
+ jest-worker "^22.1.0"
+ throat "^4.0.0"
+
+jest-runtime@^22.1.4:
+ version "22.1.4"
+ resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-22.1.4.tgz#1474d9f5cda518b702e0b25a17d4ef3fc563a20c"
+ dependencies:
+ babel-core "^6.0.0"
+ babel-jest "^22.1.0"
+ babel-plugin-istanbul "^4.1.5"
+ chalk "^2.0.1"
+ convert-source-map "^1.4.0"
+ exit "^0.1.2"
+ graceful-fs "^4.1.11"
+ jest-config "^22.1.4"
+ jest-haste-map "^22.1.0"
+ jest-regex-util "^22.1.0"
+ jest-resolve "^22.1.4"
+ jest-util "^22.1.4"
+ json-stable-stringify "^1.0.1"
+ micromatch "^2.3.11"
+ realpath-native "^1.0.0"
+ slash "^1.0.0"
+ strip-bom "3.0.0"
+ write-file-atomic "^2.1.0"
+ yargs "^10.0.3"
+
+jest-snapshot@^22.1.2:
+ version "22.1.2"
+ resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-22.1.2.tgz#b270cf6e3098f33aceeafda02b13eb0933dc6139"
+ dependencies:
+ chalk "^2.0.1"
+ jest-diff "^22.1.0"
+ jest-matcher-utils "^22.1.0"
+ mkdirp "^0.5.1"
+ natural-compare "^1.4.0"
+ pretty-format "^22.1.0"
+
+jest-util@^22.1.4:
+ version "22.1.4"
+ resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-22.1.4.tgz#ac8cbd43ee654102f1941f3f0e9d1d789a8b6a9b"
+ dependencies:
+ callsites "^2.0.0"
+ chalk "^2.0.1"
+ graceful-fs "^4.1.11"
+ is-ci "^1.0.10"
+ jest-message-util "^22.1.0"
+ jest-validate "^22.1.2"
+ mkdirp "^0.5.1"
+
+jest-validate@^21.1.0:
+ version "21.2.1"
+ resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-21.2.1.tgz#cc0cbca653cd54937ba4f2a111796774530dd3c7"
+ dependencies:
+ chalk "^2.0.1"
+ jest-get-type "^21.2.0"
+ leven "^2.1.0"
+ pretty-format "^21.2.1"
+
+jest-validate@^22.1.2:
+ version "22.1.2"
+ resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-22.1.2.tgz#c3b06bcba7bd9a850919fe336b5f2a8c3a239404"
+ dependencies:
+ chalk "^2.0.1"
+ jest-get-type "^22.1.0"
+ leven "^2.1.0"
+ pretty-format "^22.1.0"
+
+jest-worker@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-22.1.0.tgz#0987832fe58fbdc205357f4c19b992446368cafb"
+ dependencies:
+ merge-stream "^1.0.1"
+
+jest@22.0.6:
+ version "22.0.6"
+ resolved "https://registry.yarnpkg.com/jest/-/jest-22.0.6.tgz#0d0d3bdc402c43cf5a3eae58a55cff6da8b6820f"
+ dependencies:
+ jest-cli "^22.0.6"
+
+jquery@>=3.0.0:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca"
js-base64@^2.1.8, js-base64@^2.1.9:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.3.2.tgz#a79a923666372b580f8e27f51845c6f7e8fbfbaf"
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.3.tgz#2e545ec2b0f2957f41356510205214e98fad6582"
-js-beautify@^1.6.11:
- version "1.7.4"
- resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.7.4.tgz#fa0dfa8fef594d6a6253755fe26af5d0a22cbd90"
+js-beautify@^1.7.4:
+ version "1.7.5"
+ resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.7.5.tgz#69d9651ef60dbb649f65527b53674950138a7919"
dependencies:
config-chain "~1.1.5"
editorconfig "^0.13.2"
@@ -4343,7 +5266,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
-js-yaml@^3.9.1:
+js-yaml@^3.4.3, js-yaml@^3.7.0, js-yaml@^3.9.0, js-yaml@^3.9.1:
version "3.10.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc"
dependencies:
@@ -4361,11 +5284,7 @@ jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
-jschardet@^1.4.2:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.5.1.tgz#c519f629f86b3a5bedba58a88d311309eec097f9"
-
-jsdom@^9.8.0:
+jsdom@9.12.0:
version "9.12.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4"
dependencies:
@@ -4389,6 +5308,37 @@ jsdom@^9.8.0:
whatwg-url "^4.3.0"
xml-name-validator "^2.0.1"
+jsdom@^11.5.1:
+ version "11.6.2"
+ resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.6.2.tgz#25d1ef332d48adf77fc5221fe2619967923f16bb"
+ dependencies:
+ abab "^1.0.4"
+ acorn "^5.3.0"
+ acorn-globals "^4.1.0"
+ array-equal "^1.0.0"
+ browser-process-hrtime "^0.1.2"
+ content-type-parser "^1.0.2"
+ cssom ">= 0.3.2 < 0.4.0"
+ cssstyle ">= 0.2.37 < 0.3.0"
+ domexception "^1.0.0"
+ escodegen "^1.9.0"
+ html-encoding-sniffer "^1.0.2"
+ left-pad "^1.2.0"
+ nwmatcher "^1.4.3"
+ parse5 "4.0.0"
+ pn "^1.1.0"
+ request "^2.83.0"
+ request-promise-native "^1.0.5"
+ sax "^1.2.4"
+ symbol-tree "^3.2.2"
+ tough-cookie "^2.3.3"
+ w3c-hr-time "^1.0.1"
+ webidl-conversions "^4.0.2"
+ whatwg-encoding "^1.0.3"
+ whatwg-url "^6.4.0"
+ ws "^4.0.0"
+ xml-name-validator "^3.0.0"
+
jsesc@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
@@ -4397,7 +5347,7 @@ jsesc@~0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
-json-loader@^0.5.4, json-loader@^0.5.7:
+json-loader@0.5.7, json-loader@^0.5.4, json-loader@^0.5.7:
version "0.5.7"
resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d"
@@ -4415,7 +5365,7 @@ json-stable-stringify@^1.0.1:
dependencies:
jsonify "~0.0.0"
-json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1:
+json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
@@ -4447,12 +5397,20 @@ jsonpointer@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9"
-jsonwebtoken@5.4.x:
- version "5.4.1"
- resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-5.4.1.tgz#2055c639195ffe56314fa6a51df02468186a9695"
+jsonwebtoken@^8.1.0:
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.1.1.tgz#b04d8bb2ad847bc93238c3c92170ffdbdd1cb2ea"
dependencies:
- jws "^3.0.0"
- ms "^0.7.1"
+ jws "^3.1.4"
+ lodash.includes "^4.3.0"
+ lodash.isboolean "^3.0.3"
+ lodash.isinteger "^4.0.4"
+ lodash.isnumber "^3.0.3"
+ lodash.isplainobject "^4.0.6"
+ lodash.isstring "^4.0.1"
+ lodash.once "^4.0.0"
+ ms "^2.1.1"
+ xtend "^4.0.1"
jsprim@^1.2.2:
version "1.4.1"
@@ -4482,7 +5440,7 @@ jwa@^1.1.4:
ecdsa-sig-formatter "1.0.9"
safe-buffer "^5.0.1"
-jws@^3.0.0, jws@^3.1.3:
+jws@^3.1.3, jws@^3.1.4:
version "3.1.4"
resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2"
dependencies:
@@ -4490,6 +5448,10 @@ jws@^3.0.0, jws@^3.1.3:
jwa "^1.1.4"
safe-buffer "^5.0.1"
+keycode@^2.1.9:
+ version "2.1.9"
+ resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.9.tgz#964a23c54e4889405b4861a5c9f0480d45141dfa"
+
keygrip@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.2.tgz#ad3297c557069dea8bcfe7a4fa491b75c5ddeb91"
@@ -4518,7 +5480,7 @@ klaw@^1.0.0:
optionalDependencies:
graceful-fs "^4.1.9"
-koa-body@^1.4.0:
+koa-body@1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/koa-body/-/koa-body-1.6.0.tgz#2e44d7c9ee1b55e2a995c32145cb874e4dbe29ae"
dependencies:
@@ -4530,7 +5492,7 @@ koa-compose@^2.2.0, koa-compose@^2.3.0:
version "2.5.1"
resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-2.5.1.tgz#726cfb17694de5cb9fbf03c0adf172303f83f156"
-koa-compressor@^1.0.3:
+koa-compressor@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/koa-compressor/-/koa-compressor-1.0.3.tgz#d5b69f7e3e583373040b9d670fa0f18848b0609f"
dependencies:
@@ -4540,34 +5502,34 @@ koa-compressor@^1.0.3:
mz "1"
statuses "1"
-koa-conditional-get@^1.0.3:
+koa-conditional-get@1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/koa-conditional-get/-/koa-conditional-get-1.0.4.tgz#96616a3790624ceab31f7d63e0f30464ff46d968"
-koa-csrf@^2.5.0:
+koa-csrf@2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/koa-csrf/-/koa-csrf-2.5.0.tgz#e23de7c8e1d0cfe1ee7310eb2f3f2eca43dacf8e"
dependencies:
csrf "^3.0.0"
-koa-etag@^2.0.0:
+koa-etag@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/koa-etag/-/koa-etag-2.1.2.tgz#b20e184c5d5504fd797f7eab98a98d1e495b8014"
dependencies:
etag "^1.3.0"
mz "^2.1.0"
-koa-favicon@^1.2.0:
+koa-favicon@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/koa-favicon/-/koa-favicon-1.2.1.tgz#c001a6db6da6d71272b93fb5b924c392194821d0"
dependencies:
mz "^2.0.0"
-koa-flash@^1.0.0:
+koa-flash@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/koa-flash/-/koa-flash-1.0.0.tgz#690f7d10a25130c530dac30b7812d5cf6f74d68d"
-koa-helmet@^1.0.0:
+koa-helmet@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/koa-helmet/-/koa-helmet-1.2.0.tgz#232061dcffa8564381c10ae63af3837864d01e86"
dependencies:
@@ -4577,17 +5539,17 @@ koa-is-json@1, koa-is-json@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14"
-koa-isbot@^0.1.1:
+koa-isbot@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/koa-isbot/-/koa-isbot-0.1.1.tgz#980e2546c697e3b9278c5fd32fe37e1374fe8253"
-koa-locale@^1.3.0:
+koa-locale@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/koa-locale/-/koa-locale-1.3.0.tgz#95289ae6fa4098804a1ee8aadd46b0af1c82cbcb"
dependencies:
delegates "1.0.0"
-koa-logger@^1.3.0:
+koa-logger@1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/koa-logger/-/koa-logger-1.3.1.tgz#ad3f5f2193b3334328f3eb99a618f4b04bee8bd5"
dependencies:
@@ -4596,21 +5558,21 @@ koa-logger@^1.3.0:
humanize-number "0.0.2"
passthrough-counter "^1.0.0"
-koa-mount@^1.3.0:
+koa-mount@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/koa-mount/-/koa-mount-1.3.0.tgz#de6ab775ec4b71ba6e67f2925a3d40dd5fab3ed0"
dependencies:
debug "*"
koa-compose "^2.2.0"
-koa-proxy@^0.5.0:
+koa-proxy@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/koa-proxy/-/koa-proxy-0.5.0.tgz#aedf8c3f6c26190298d8c97fd27172909558c340"
dependencies:
co-request "^0.2.0"
iconv-lite "^0.2.11"
-koa-route@^2.4.2:
+koa-route@2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/koa-route/-/koa-route-2.4.2.tgz#0de227989e6aa7334768abbfb16c519ad9a7fa71"
dependencies:
@@ -4618,7 +5580,7 @@ koa-route@^2.4.2:
methods "~1.1.0"
path-to-regexp "^1.2.0"
-koa-router@^5.4.0:
+koa-router@5.4.2:
version "5.4.2"
resolved "https://registry.yarnpkg.com/koa-router/-/koa-router-5.4.2.tgz#4dbdba7e715953d5686c03b7c3fdbd214631f870"
dependencies:
@@ -4628,16 +5590,16 @@ koa-router@^5.4.0:
methods "^1.0.1"
path-to-regexp "^1.1.1"
-koa-session@3, koa-session@^3.3.1:
+koa-session@3, koa-session@3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/koa-session/-/koa-session-3.4.0.tgz#ce270291a4fcfbafe199abb64ccd9830e8c787bf"
dependencies:
debug "^2.2.0"
deep-equal "^1.0.0"
-koa-static-cache@^3.1.2:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/koa-static-cache/-/koa-static-cache-3.2.0.tgz#54886189653bc4dc9a72e6312c19dba40c73ed89"
+koa-static-cache@4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/koa-static-cache/-/koa-static-cache-4.1.1.tgz#2f82885e155fd46591ccb5d22f3f6a0d17d63982"
dependencies:
compressible "~2.0.6"
debug "*"
@@ -4645,19 +5607,19 @@ koa-static-cache@^3.1.2:
mime-types "~2.1.8"
mz "~2.4.0"
-koa-webpack-dev-middleware@^1.1.0:
+koa-webpack-dev-middleware@1.4.6:
version "1.4.6"
resolved "https://registry.yarnpkg.com/koa-webpack-dev-middleware/-/koa-webpack-dev-middleware-1.4.6.tgz#6ec20d3648c3c80b5edb0b721a6838f66a1fc47a"
dependencies:
webpack-dev-middleware "^1.10.0"
-koa-webpack-hot-middleware@^1.0.3:
+koa-webpack-hot-middleware@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/koa-webpack-hot-middleware/-/koa-webpack-hot-middleware-1.0.3.tgz#df6aafbf2d77153101e37e6a4ae70235b466f8c0"
dependencies:
webpack-hot-middleware "2.x"
-koa@^1.1.2:
+koa@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/koa/-/koa-1.4.1.tgz#4f404be9cff3ce3d04bbdc22e5168f116a4b962b"
dependencies:
@@ -4699,6 +5661,14 @@ lcid@^1.0.0:
dependencies:
invert-kv "^1.0.0"
+left-pad@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.2.0.tgz#d30a73c6b8201d8f7d8e7956ba9616087a68e0ee"
+
+leven@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
+
levn@^0.3.0, levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
@@ -4716,19 +5686,78 @@ libsodium@0.4.9, libsodium@^0.4.8:
version "0.4.9"
resolved "https://registry.yarnpkg.com/libsodium/-/libsodium-0.4.9.tgz#450de70ebe8566df4220886d00d3b822e4a28c29"
-liftoff@^2.1.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.3.0.tgz#a98f2ff67183d8ba7cfaca10548bd7ff0550b385"
+lint-staged@6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-6.0.0.tgz#7ab7d345f2fe302ff196f1de6a005594ace03210"
dependencies:
- extend "^3.0.0"
- findup-sync "^0.4.2"
- fined "^1.0.1"
- flagged-respawn "^0.3.2"
- lodash.isplainobject "^4.0.4"
- lodash.isstring "^4.0.1"
- lodash.mapvalues "^4.4.0"
- rechoir "^0.6.2"
- resolve "^1.1.7"
+ app-root-path "^2.0.0"
+ chalk "^2.1.0"
+ commander "^2.11.0"
+ cosmiconfig "^3.1.0"
+ debug "^3.1.0"
+ dedent "^0.7.0"
+ execa "^0.8.0"
+ find-parent-dir "^0.3.0"
+ is-glob "^4.0.0"
+ jest-validate "^21.1.0"
+ listr "^0.13.0"
+ lodash "^4.17.4"
+ log-symbols "^2.0.0"
+ minimatch "^3.0.0"
+ npm-which "^3.0.1"
+ p-map "^1.1.1"
+ path-is-inside "^1.0.2"
+ pify "^3.0.0"
+ staged-git-files "0.0.4"
+ stringify-object "^3.2.0"
+
+listr-silent-renderer@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e"
+
+listr-update-renderer@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz#344d980da2ca2e8b145ba305908f32ae3f4cc8a7"
+ dependencies:
+ chalk "^1.1.3"
+ cli-truncate "^0.2.1"
+ elegant-spinner "^1.0.1"
+ figures "^1.7.0"
+ indent-string "^3.0.0"
+ log-symbols "^1.0.2"
+ log-update "^1.0.2"
+ strip-ansi "^3.0.1"
+
+listr-verbose-renderer@^0.4.0:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#8206f4cf6d52ddc5827e5fd14989e0e965933a35"
+ dependencies:
+ chalk "^1.1.3"
+ cli-cursor "^1.0.2"
+ date-fns "^1.27.2"
+ figures "^1.7.0"
+
+listr@^0.13.0:
+ version "0.13.0"
+ resolved "https://registry.yarnpkg.com/listr/-/listr-0.13.0.tgz#20bb0ba30bae660ee84cc0503df4be3d5623887d"
+ dependencies:
+ chalk "^1.1.3"
+ cli-truncate "^0.2.1"
+ figures "^1.7.0"
+ indent-string "^2.1.0"
+ is-observable "^0.2.0"
+ is-promise "^2.1.0"
+ is-stream "^1.1.0"
+ listr-silent-renderer "^1.1.1"
+ listr-update-renderer "^0.4.0"
+ listr-verbose-renderer "^0.4.0"
+ log-symbols "^1.0.2"
+ log-update "^1.0.2"
+ ora "^0.2.3"
+ p-map "^1.1.1"
+ rxjs "^5.4.2"
+ stream-to-observable "^0.2.0"
+ strip-ansi "^3.0.1"
load-json-file@^1.0.0:
version "1.1.0"
@@ -4778,61 +5807,17 @@ locate-path@^2.0.0:
path-exists "^3.0.0"
lodash-es@^4.2.0, lodash-es@^4.2.1:
- version "4.17.4"
- resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7"
-
-lodash._basecopy@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
-
-lodash._basefor@^3.0.0:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2"
-
-lodash._basetostring@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5"
-
-lodash._basevalues@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7"
+ version "4.17.5"
+ resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.5.tgz#9fc6e737b1c4d151d8f9cae2247305d552ce748f"
lodash._getnative@^3.0.0:
version "3.9.1"
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
-lodash._isiterateecall@^3.0.0:
- version "3.0.9"
- resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
-
-lodash._reescape@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a"
-
-lodash._reevaluate@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed"
-
-lodash._reinterpolate@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
-
-lodash._root@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
-
lodash.assign@^4.0.0, lodash.assign@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
-lodash.assignin@^4.0.9:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2"
-
-lodash.bind@^4.1.4:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35"
-
lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
@@ -4849,31 +5834,17 @@ lodash.cond@^4.3.0:
version "4.5.2"
resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5"
-lodash.debounce@^4.0.7:
+lodash.debounce@4.0.8, lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
-lodash.defaults@^4.0.1:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
-
-lodash.escape@^3.0.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698"
- dependencies:
- lodash._root "^3.0.0"
-
-lodash.filter@^4.4.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace"
-
-lodash.flatten@^4.2.0:
+lodash.flattendeep@^4.4.0:
version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
+ resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
-lodash.foreach@^4.3.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53"
+lodash.includes@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
lodash.isarguments@^3.0.0:
version "3.1.0"
@@ -4883,15 +5854,19 @@ lodash.isarray@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
-lodash.isplainobject@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5"
- dependencies:
- lodash._basefor "^3.0.0"
- lodash.isarguments "^3.0.0"
- lodash.keysin "^3.0.0"
+lodash.isboolean@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
+
+lodash.isinteger@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
+
+lodash.isnumber@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc"
-lodash.isplainobject@^4.0.4:
+lodash.isplainobject@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
@@ -4899,7 +5874,7 @@ lodash.isstring@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
-lodash.keys@^3.0.0:
+lodash.keys@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
dependencies:
@@ -4907,34 +5882,19 @@ lodash.keys@^3.0.0:
lodash.isarguments "^3.0.0"
lodash.isarray "^3.0.0"
-lodash.keysin@^3.0.0:
- version "3.0.8"
- resolved "https://registry.yarnpkg.com/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f"
- dependencies:
- lodash.isarguments "^3.0.0"
- lodash.isarray "^3.0.0"
-
-lodash.map@^4.4.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3"
-
-lodash.mapvalues@^4.4.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c"
-
lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
-lodash.merge@^4.4.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5"
-
lodash.mergewith@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55"
+ version "4.6.1"
+ resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
+
+lodash.once@^4.0.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
-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"
@@ -4942,62 +5902,60 @@ lodash.pickby@^4.0.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff"
-lodash.reduce@4.6.0, lodash.reduce@^4.4.0:
+lodash.reduce@4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b"
-lodash.reject@^4.4.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415"
-
-lodash.restparam@^3.0.0:
- version "3.6.1"
- resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
-
-lodash.some@^4.4.0:
+lodash.some@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"
+lodash.sortby@^4.7.0:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
+
lodash.tail@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
-lodash.template@^3.0.0:
- version "3.6.2"
- resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f"
- dependencies:
- lodash._basecopy "^3.0.0"
- lodash._basetostring "^3.0.0"
- lodash._basevalues "^3.0.0"
- lodash._isiterateecall "^3.0.0"
- lodash._reinterpolate "^3.0.0"
- lodash.escape "^3.0.0"
- lodash.keys "^3.0.0"
- lodash.restparam "^3.0.0"
- lodash.templatesettings "^3.0.0"
-
-lodash.templatesettings@^3.0.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5"
- dependencies:
- lodash._reinterpolate "^3.0.0"
- lodash.escape "^3.0.0"
-
lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
+lodash@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.0.0.tgz#9ac43844c595e28d30108b7ba583703395922dfc"
+
lodash@4.12.0:
version "4.12.0"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.12.0.tgz#2bd6dc46a040f59e686c972ed21d93dc59053258"
-lodash@^4.0.0, lodash@^4.14.0, lodash@^4.16.1, lodash@^4.16.4, lodash@^4.17.0, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1, lodash@~4.17.4:
- version "4.17.4"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+lodash@^3.10.1:
+ version "3.10.1"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
+
+lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.16.4, lodash@^4.17.0, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1, lodash@~4.17.4:
+ version "4.17.5"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
-lodash@~1.0.1:
+log-symbols@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
+ dependencies:
+ chalk "^1.0.0"
+
+log-symbols@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
+ dependencies:
+ chalk "^2.0.1"
+
+log-update@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/log-update/-/log-update-1.0.2.tgz#19929f64c4093d2d2e7075a1dad8af59c296b8d1"
+ dependencies:
+ ansi-escapes "^1.0.0"
+ cli-cursor "^1.0.2"
"log@>= 1.2.0":
version "1.4.0"
@@ -5028,14 +5986,6 @@ loud-rejection@^1.0.0:
currently-unhandled "^0.4.1"
signal-exit "^3.0.0"
-lower-case@^1.1.1:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
-
-lru-cache@2:
- version "2.7.3"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"
-
lru-cache@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-3.2.0.tgz#71789b3b7f5399bec8565dda38aa30d2a097efee"
@@ -5069,19 +6019,29 @@ mailparser@^0.6.1:
uue "^3.1.0"
make-dir@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978"
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.1.0.tgz#19b4369fe48c116f53c2af95ad102c0e39e85d51"
dependencies:
- pify "^2.3.0"
+ pify "^3.0.0"
-map-cache@^0.2.0:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+make-error@^1.3.2:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.3.tgz#a97ae14ffd98b05f543e83ddc395e1b2b6e4cc6a"
+
+makeerror@1.0.x:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
+ dependencies:
+ tmpl "1.0.x"
map-obj@^1.0.0, map-obj@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
+material-colors@^1.2.1:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.5.tgz#5292593e6754cb1bcc2b98030e4e0d6a3afc9ea1"
+
math-expression-evaluator@^1.2.14:
version "1.2.17"
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac"
@@ -5097,21 +6057,11 @@ media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
-medium-editor-insert-plugin@^2.3.2:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/medium-editor-insert-plugin/-/medium-editor-insert-plugin-2.4.1.tgz#e15c4970cf577590da8fa121a4a68e48cbbf6b33"
- dependencies:
- blueimp-file-upload "~9.12.1"
- handlebars "~4.0.0"
- jquery ">=1.9.0"
- jquery-sortable "~0.9.12"
- medium-editor "^5.15.0"
-
-medium-editor@^5.10.0, medium-editor@^5.15.0:
- version "5.23.2"
- resolved "https://registry.yarnpkg.com/medium-editor/-/medium-editor-5.23.2.tgz#736c681f3e4b175f9c2ee4e48f9543f9f889e066"
+medium-editor@^5.10.0:
+ version "5.23.3"
+ resolved "https://registry.yarnpkg.com/medium-editor/-/medium-editor-5.23.3.tgz#6fb638759ae2fc76c423feb056f346d9c518d3b7"
-mem-stat@^1.0.5:
+mem-stat@1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/mem-stat/-/mem-stat-1.0.5.tgz#7d66c297184da38bacbfe4f9cd2e9a7a0e195086"
@@ -5160,11 +6110,21 @@ merge-descriptors@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+merge-stream@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
+ dependencies:
+ readable-stream "^2.0.1"
+
+merge@^1.1.3:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
+
methods@1.x, methods@^1.0.1, methods@~1.1.0, methods@~1.1.1, methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
-micromatch@^2.1.5, micromatch@^2.3.7:
+micromatch@^2.1.5, micromatch@^2.3.11:
version "2.3.11"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
dependencies:
@@ -5189,11 +6149,15 @@ miller-rabin@^4.0.0:
bn.js "^4.0.0"
brorand "^1.0.1"
-"mime-db@>= 1.29.0 < 2", mime-db@~1.30.0:
+"mime-db@>= 1.30.0 < 2":
+ version "1.32.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.32.0.tgz#485b3848b01a3cda5f968b4882c0771e58e09414"
+
+mime-db@~1.30.0:
version "1.30.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01"
-mime-types@^2.0.7, mime-types@^2.1.11, mime-types@^2.1.12, mime-types@^2.1.3, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.2, mime-types@~2.1.7, mime-types@~2.1.8:
+mime-types@^2.0.7, mime-types@^2.1.12, mime-types@^2.1.3, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.7, mime-types@~2.1.8:
version "2.1.17"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a"
dependencies:
@@ -5203,14 +6167,14 @@ mime@1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
-mime@1.3.x, mime@^1.3.4:
- version "1.3.6"
- resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0"
-
mime@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
+mime@^1.3.4, mime@^1.4.1, mime@^1.5.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+
mimelib@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/mimelib/-/mimelib-0.3.1.tgz#787add2415d827acb3af6ec4bca1ea9596418853"
@@ -5219,8 +6183,8 @@ mimelib@^0.3.0:
encoding "~0.1.12"
mimic-fn@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
min-document@^2.19.0:
version "2.19.0"
@@ -5236,40 +6200,24 @@ minimalistic-crypto-utils@^1.0.0, 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"
-minimatch@0.3:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd"
- dependencies:
- lru-cache "2"
- sigmund "~1.0.0"
-
-minimatch@^2.0.1:
- version "2.0.10"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7"
- dependencies:
- brace-expansion "^1.0.0"
-
-minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2:
+"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
brace-expansion "^1.1.7"
-minimatch@~0.2.11:
- version "0.2.14"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a"
- dependencies:
- lru-cache "2"
- sigmund "~1.0.0"
-
-minimist@0.0.8, minimist@~0.0.1:
+minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
-minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0:
+minimist@1.2.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+minimist@~0.0.1:
+ version "0.0.10"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
+
mixin-object@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e"
@@ -5277,53 +6225,38 @@ mixin-object@^2.0.1:
for-in "^0.1.3"
is-extendable "^0.1.1"
-mixpanel@^0.5.0:
+mixpanel@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/mixpanel/-/mixpanel-0.5.0.tgz#b40e8a852490a6bc3d21d2f61641d950f8175380"
-mkdirp@0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e"
-
-mkdirp@0.5.1, "mkdirp@>= 0.0.1", "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
+"mkdirp@>= 0.0.1", "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
dependencies:
minimist "0.0.8"
-mocha@^2.4.5:
- version "2.5.3"
- resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58"
- dependencies:
- commander "2.3.0"
- debug "2.2.0"
- diff "1.4.0"
- escape-string-regexp "1.0.2"
- glob "3.2.11"
- growl "1.9.2"
- jade "0.26.3"
- mkdirp "0.5.1"
- supports-color "1.2.0"
- to-iso-string "0.0.2"
-
moment-timezone@^0.5.4:
- version "0.5.13"
- resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.13.tgz#99ce5c7d827262eb0f1f702044177f60745d7b90"
+ version "0.5.14"
+ resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.14.tgz#4eb38ff9538b80108ba467a458f3ed4268ccfcb1"
dependencies:
moment ">= 2.9.0"
-"moment@>= 2.9.0", moment@^2.13.0, moment@^2.16.0, moment@^2.17.1:
- version "2.19.1"
- resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.1.tgz#56da1a2d1cbf01d38b7e1afc31c10bcfa1929167"
+moment@2.19.3:
+ version "2.19.3"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.3.tgz#bdb99d270d6d7fda78cc0fbace855e27fe7da69f"
-ms@0.7.1, ms@^0.7.1:
- version "0.7.1"
- resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098"
+"moment@>= 2.9.0", moment@^2.13.0, moment@^2.20.1:
+ version "2.20.1"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ms@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
+
msgpack-lite@^0.1.20:
version "0.1.26"
resolved "https://registry.yarnpkg.com/msgpack-lite/-/msgpack-lite-0.1.26.tgz#dd3c50b26f059f25e7edee3644418358e2a9ad89"
@@ -5333,17 +6266,11 @@ msgpack-lite@^0.1.20:
int64-buffer "^0.1.9"
isarray "^1.0.0"
-multipipe@^0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b"
- dependencies:
- duplexer2 "0.0.2"
-
mute-stream@0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
-mysql@^2.10.2:
+mysql@2.15.0:
version "2.15.0"
resolved "https://registry.yarnpkg.com/mysql/-/mysql-2.15.0.tgz#ea16841156343e8f2e47fc8985ec41cdd9573b5c"
dependencies:
@@ -5376,7 +6303,11 @@ mz@~2.4.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
-nan@^2.3.0, nan@^2.3.2, nan@^2.3.3, nan@~2.7.0:
+nan@^2.3.0, nan@^2.3.2, nan@^2.3.3:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a"
+
+nan@~2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46"
@@ -5384,19 +6315,23 @@ native-or-bluebird@1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/native-or-bluebird/-/native-or-bluebird-1.2.0.tgz#39c47bfd7825d1fb9ffad32210ae25daadf101c9"
-natives@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31"
-
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+nearley@^2.7.10:
+ version "2.11.0"
+ resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.11.0.tgz#5e626c79a6cd2f6ab9e7e5d5805e7668967757ae"
+ dependencies:
+ nomnom "~1.6.2"
+ railroad-diagrams "^1.0.0"
+ randexp "^0.4.2"
+
negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
-net@^1.0.2:
+net@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/net/-/net-1.0.2.tgz#d1757ec9a7fb2371d83cf4755ce3e27e10829388"
@@ -5408,7 +6343,13 @@ nocache@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.0.0.tgz#202b48021a0c4cbde2df80de15a17443c8b43980"
-node-fetch@^1.0.1, node-fetch@~1.7.1:
+node-dir@^0.1.10:
+ version "0.1.17"
+ resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5"
+ dependencies:
+ minimatch "^3.0.2"
+
+node-fetch@1.7.3, node-fetch@^1.0.1:
version "1.7.3"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
dependencies:
@@ -5433,38 +6374,52 @@ node-gyp@^3.3.1:
tar "^2.0.0"
which "1"
+node-int64@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
+
node-libs-browser@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646"
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df"
dependencies:
assert "^1.1.1"
- browserify-zlib "^0.1.4"
+ 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 "^1.0.0"
- https-browserify "0.0.1"
- os-browserify "^0.2.0"
+ https-browserify "^1.0.0"
+ os-browserify "^0.3.0"
path-browserify "0.0.0"
- process "^0.11.0"
+ process "^0.11.10"
punycode "^1.2.4"
querystring-es3 "^0.2.0"
- readable-stream "^2.0.5"
+ readable-stream "^2.3.3"
stream-browserify "^2.0.1"
- stream-http "^2.3.1"
- string_decoder "^0.10.25"
- timers-browserify "^2.0.2"
+ 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.10.3"
vm-browserify "0.0.4"
-node-pre-gyp@^0.6.36, node-pre-gyp@~0.6.38:
- version "0.6.38"
- resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.38.tgz#e92a20f83416415bb4086f6d1fb78b3da73d113d"
+node-notifier@^5.1.2:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea"
+ dependencies:
+ growly "^1.3.0"
+ semver "^5.4.1"
+ shellwords "^0.1.1"
+ which "^1.3.0"
+
+node-pre-gyp@^0.6.39, node-pre-gyp@~0.6.38:
+ version "0.6.39"
+ resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649"
dependencies:
+ detect-libc "^1.0.2"
hawk "3.1.3"
mkdirp "^0.5.1"
nopt "^4.0.1"
@@ -5476,9 +6431,9 @@ node-pre-gyp@^0.6.36, node-pre-gyp@~0.6.38:
tar "^2.2.1"
tar-pack "^3.4.0"
-node-sass@^4.5.3:
- version "4.5.3"
- resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.5.3.tgz#d09c9d1179641239d1b97ffc6231fdcec53e1568"
+node-sass@4.7.2:
+ version "4.7.2"
+ resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.7.2.tgz#9366778ba1469eb01438a9e8592f4262bcb6794e"
dependencies:
async-foreach "^0.1.3"
chalk "^1.1.1"
@@ -5495,18 +6450,26 @@ node-sass@^4.5.3:
nan "^2.3.2"
node-gyp "^3.3.1"
npmlog "^4.0.0"
- request "^2.79.0"
- sass-graph "^2.1.1"
+ request "~2.79.0"
+ sass-graph "^2.2.4"
stdout-stream "^1.4.0"
+ "true-case-path" "^1.0.2"
-node-uuid@~1.4.0, node-uuid@~1.4.7:
- version "1.4.8"
- resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907"
-
-node-watch@^0.5.5:
+node-watch@0.5.5:
version "0.5.5"
resolved "https://registry.yarnpkg.com/node-watch/-/node-watch-0.5.5.tgz#34865ba8bc6861ab086acdcc3403e40ed55c3274"
+nodesecurity-npm-utils@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/nodesecurity-npm-utils/-/nodesecurity-npm-utils-6.0.0.tgz#5fb5974008c0c97a5c01844faa8fd3fc5520806c"
+
+nomnom@~1.6.2:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.6.2.tgz#84a66a260174408fc5b77a18f888eccc44fb6971"
+ dependencies:
+ colors "0.5.x"
+ underscore "~1.4.4"
+
"nopt@2 || 3", nopt@~3.0.1:
version "3.0.6"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
@@ -5529,6 +6492,10 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
semver "2 || 3 || 4 || 5"
validate-npm-package-license "^3.0.1"
+normalize-path@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379"
+
normalize-path@^2.0.0, normalize-path@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
@@ -5548,12 +6515,26 @@ normalize-url@^1.4.0:
query-string "^4.1.0"
sort-keys "^1.0.0"
+npm-path@^2.0.2:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.4.tgz#c641347a5ff9d6a09e4d9bce5580c4f505278e64"
+ dependencies:
+ which "^1.2.10"
+
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
dependencies:
path-key "^2.0.0"
+npm-which@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa"
+ dependencies:
+ commander "^2.9.0"
+ npm-path "^2.0.2"
+ which "^1.2.10"
+
"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
@@ -5563,6 +6544,20 @@ npm-run-path@^2.0.0:
gauge "~2.7.3"
set-blocking "~2.0.0"
+nsp@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/nsp/-/nsp-3.1.0.tgz#e3d168b01258728ef1cb03fea9ec4f0059c8e3f3"
+ dependencies:
+ chalk "^2.1.0"
+ cli-table2 "^0.2.0"
+ cvss "^1.0.2"
+ https-proxy-agent "^2.1.0"
+ inquirer "^3.3.0"
+ nodesecurity-npm-utils "^6.0.0"
+ semver "^5.4.1"
+ wreck "^12.5.1"
+ yargs "^9.0.1"
+
nth-check@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4"
@@ -5577,11 +6572,11 @@ number-is-nan@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
-"nwmatcher@>= 1.3.9 < 2.0.0":
+"nwmatcher@>= 1.3.9 < 2.0.0", nwmatcher@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.3.tgz#64348e3b3d80f035b40ac11563d278f8b72db89c"
-oauth-sign@~0.8.0, oauth-sign@~0.8.1, oauth-sign@~0.8.2:
+oauth-sign@~0.8.1, oauth-sign@~0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
@@ -5593,30 +6588,26 @@ 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"
+object-inspect@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.5.0.tgz#9d876c11e40f485c79215670281b767488f9bfe3"
+
object-is@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6"
-object-keys@^1.0.10, object-keys@^1.0.8:
+object-keys@^1.0.11, object-keys@^1.0.8:
version "1.0.11"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
-object.assign@^4.0.4:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.0.4.tgz#b1c9cc044ef1b9fe63606fc141abbb32e14730cc"
+object.assign@^4.0.4, object.assign@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
dependencies:
define-properties "^1.1.2"
- function-bind "^1.1.0"
- object-keys "^1.0.10"
-
-object.defaults@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf"
- dependencies:
- array-each "^1.0.1"
- array-slice "^1.0.0"
- for-own "^1.0.0"
- isobject "^3.0.0"
+ function-bind "^1.1.1"
+ has-symbols "^1.0.0"
+ object-keys "^1.0.11"
object.entries@^1.0.4:
version "1.0.4"
@@ -5627,6 +6618,13 @@ object.entries@^1.0.4:
function-bind "^1.1.0"
has "^1.0.1"
+object.getownpropertydescriptors@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.5.1"
+
object.omit@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
@@ -5634,12 +6632,6 @@ object.omit@^2.0.0:
for-own "^0.1.4"
is-extendable "^0.1.1"
-object.pick@^1.2.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
- dependencies:
- isobject "^3.0.1"
-
object.values@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.4.tgz#e524da09b4f66ff05df457546ec72ac99f13069a"
@@ -5655,17 +6647,15 @@ on-finished@^2.1.0, on-finished@~2.3.0:
dependencies:
ee-first "1.1.1"
-once@^1.3.0, once@^1.3.3:
+once@^1.3.0, once@^1.3.3, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
dependencies:
wrappy "1"
-once@~1.3.0:
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20"
- dependencies:
- wrappy "1"
+onetime@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
onetime@^2.0.0:
version "2.0.1"
@@ -5699,21 +6689,18 @@ optionator@^0.8.1, optionator@^0.8.2:
type-check "~0.3.2"
wordwrap "~1.0.0"
-orchestrator@^0.3.0:
- version "0.3.8"
- resolved "https://registry.yarnpkg.com/orchestrator/-/orchestrator-0.3.8.tgz#14e7e9e2764f7315fbac184e506c7aa6df94ad7e"
+ora@^0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4"
dependencies:
- end-of-stream "~0.1.5"
- sequencify "~0.0.7"
- stream-consume "~0.1.0"
-
-ordered-read-streams@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz#fd565a9af8eb4473ba69b6ed8a34352cb552f126"
+ chalk "^1.1.1"
+ cli-cursor "^1.0.2"
+ cli-spinners "^0.1.2"
+ object-assign "^4.0.1"
-os-browserify@^0.2.0:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f"
+os-browserify@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
os-homedir@1.0.2, os-homedir@^1.0.0, os-homedir@^1.0.1:
version "1.0.2"
@@ -5733,15 +6720,11 @@ os-locale@^2.0.0:
lcid "^1.0.0"
mem "^1.1.0"
-os-shim@^0.1.2:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917"
-
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
-os@^0.1.1:
+os@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/os/-/os-0.1.1.tgz#208845e89e193ad4d971474b93947736a56d13f3"
@@ -5765,8 +6748,10 @@ p-finally@^1.0.0:
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
p-limit@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc"
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c"
+ dependencies:
+ p-try "^1.0.0"
p-locate@^2.0.0:
version "2.0.0"
@@ -5774,9 +6759,17 @@ p-locate@^2.0.0:
dependencies:
p-limit "^1.1.0"
-pako@~0.2.0:
- version "0.2.9"
- resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+p-map@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
+
+p-try@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
+
+pako@~1.0.5:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
parse-asn1@^5.0.0:
version "5.1.0"
@@ -5788,14 +6781,6 @@ parse-asn1@^5.0.0:
evp_bytestokey "^1.0.0"
pbkdf2 "^3.0.3"
-parse-filepath@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.1.tgz#159d6155d43904d16c10ef698911da1e91969b73"
- dependencies:
- is-absolute "^0.2.3"
- map-cache "^0.2.0"
- path-root "^0.1.1"
-
parse-glob@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
@@ -5811,14 +6796,26 @@ parse-json@^2.2.0:
dependencies:
error-ex "^1.2.0"
-parse-passwd@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
+parse-json@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-3.0.0.tgz#fa6f47b18e23826ead32f263e744d0e1e847fb13"
+ dependencies:
+ error-ex "^1.3.1"
+
+parse5@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
parse5@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
+parse5@^3.0.1:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
+ dependencies:
+ "@types/node" "*"
+
parseurl@^1.3.0, parseurl@~1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
@@ -5857,16 +6854,6 @@ path-parse@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
-path-root-regex@^0.1.0:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d"
-
-path-root@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7"
- dependencies:
- path-root-regex "^0.1.0"
-
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"
@@ -5909,11 +6896,11 @@ performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
-picturefill@^3.0.2:
+picturefill@3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/picturefill/-/picturefill-3.0.2.tgz#fa3d35fffbef5ab5300fe2ad9dca8f2e36cba27b"
-pify@^2.0.0, pify@^2.3.0:
+pify@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@@ -5943,17 +6930,32 @@ pkg-dir@^2.0.0:
dependencies:
find-up "^2.1.0"
-platform@1.3.4:
- version "1.3.4"
- resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.4.tgz#6f0fb17edaaa48f21442b3a975c063130f1c3ebd"
+platform@1.3.5:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.5.tgz#fb6958c696e07e2918d2eeda0f0bc9448d733444"
pluralize@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777"
pluralizers@^0.1.4:
- version "0.1.6"
- resolved "https://registry.yarnpkg.com/pluralizers/-/pluralizers-0.1.6.tgz#1ab38b6e760e6f97f9846125097b862bc974c81e"
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/pluralizers/-/pluralizers-0.1.7.tgz#8d38dd0a1b660e739b10ab2eab10b684c9d50142"
+
+pn@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"
+
+podda@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/podda/-/podda-1.2.2.tgz#15b0edbd334ade145813343f5ecf9c10a71cf500"
+ dependencies:
+ babel-runtime "^6.11.6"
+ immutable "^3.8.1"
+
+pop-iterate@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/pop-iterate/-/pop-iterate-1.0.1.tgz#ceacfdab4abf353d7a0f2aaa2c1fc7b3f9413ba3"
postcss-calc@^5.2.0:
version "5.3.1"
@@ -6016,6 +7018,44 @@ postcss-filter-plugins@^2.0.0:
postcss "^5.0.4"
uniqid "^4.0.0"
+postcss-flexbugs-fixes@^3.2.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-3.3.0.tgz#e00849b536063749da50a0d410ba5d9ee65e27b8"
+ dependencies:
+ postcss "^6.0.1"
+
+postcss-load-config@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-1.2.0.tgz#539e9afc9ddc8620121ebf9d8c3673e0ce50d28a"
+ dependencies:
+ cosmiconfig "^2.1.0"
+ object-assign "^4.1.0"
+ postcss-load-options "^1.2.0"
+ postcss-load-plugins "^2.3.0"
+
+postcss-load-options@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-load-options/-/postcss-load-options-1.2.0.tgz#b098b1559ddac2df04bc0bb375f99a5cfe2b6d8c"
+ dependencies:
+ cosmiconfig "^2.1.0"
+ object-assign "^4.1.0"
+
+postcss-load-plugins@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz#745768116599aca2f009fad426b00175049d8d92"
+ dependencies:
+ cosmiconfig "^2.1.1"
+ object-assign "^4.1.0"
+
+postcss-loader@^2.0.9:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-2.1.0.tgz#038c2d6d59753fef4667827fd3ae03f5dc5e6a7a"
+ dependencies:
+ loader-utils "^1.1.0"
+ postcss "^6.0.0"
+ postcss-load-config "^1.2.0"
+ schema-utils "^0.4.0"
+
postcss-merge-idents@^2.1.5:
version "2.1.7"
resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270"
@@ -6078,26 +7118,32 @@ postcss-minify-selectors@^2.0.4:
postcss-selector-parser "^2.0.0"
postcss-modules-extract-imports@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz#b614c9720be6816eaee35fb3a5faa1dba6a05ddb"
+ dependencies:
+ postcss "^6.0.1"
+
+postcss-modules-extract-imports@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85"
dependencies:
postcss "^6.0.1"
-postcss-modules-local-by-default@^1.0.1:
+postcss-modules-local-by-default@^1.0.1, postcss-modules-local-by-default@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069"
dependencies:
css-selector-tokenizer "^0.7.0"
postcss "^6.0.1"
-postcss-modules-scope@^1.0.0:
+postcss-modules-scope@^1.0.0, postcss-modules-scope@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90"
dependencies:
css-selector-tokenizer "^0.7.0"
postcss "^6.0.1"
-postcss-modules-values@^1.1.0:
+postcss-modules-values@^1.1.0, postcss-modules-values@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20"
dependencies:
@@ -6199,25 +7245,13 @@ postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0
source-map "^0.5.6"
supports-color "^3.2.3"
-postcss@^6.0.1:
- version "6.0.13"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.13.tgz#b9ecab4ee00c89db3ec931145bd9590bbf3f125f"
+postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.16:
+ version "6.0.17"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.17.tgz#e259a051ca513f81e9afd0c21f7f82eda50c65c5"
dependencies:
- chalk "^2.1.0"
+ chalk "^2.3.0"
source-map "^0.6.1"
- supports-color "^4.4.0"
-
-postinstall-build@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/postinstall-build/-/postinstall-build-5.0.1.tgz#b917a9079b26178d9a24af5a5cd8cb4a991d11b9"
-
-pre-commit@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/pre-commit/-/pre-commit-1.2.2.tgz#dbcee0ee9de7235e57f79c56d7ce94641a69eec6"
- dependencies:
- cross-spawn "^5.0.1"
- spawn-sync "^1.0.15"
- which "1.2.x"
+ supports-color "^5.1.0"
prelude-ls@~1.1.2:
version "1.1.2"
@@ -6231,19 +7265,33 @@ preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
-pretty-hrtime@^1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
+prettier@1.8.2:
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.8.2.tgz#bff83e7fd573933c607875e5ba3abbdffb96aeb8"
-private@^0.1.6, private@^0.1.7:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
+pretty-format@^21.2.1:
+ version "21.2.1"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-21.2.1.tgz#ae5407f3cf21066cd011aa1ba5fce7b6a2eddb36"
+ dependencies:
+ ansi-regex "^3.0.0"
+ ansi-styles "^3.2.0"
+
+pretty-format@^22.1.0:
+ version "22.1.0"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.1.0.tgz#2277605b40ed4529ae4db51ff62f4be817647914"
+ dependencies:
+ ansi-regex "^3.0.0"
+ ansi-styles "^3.2.0"
+
+private@^0.1.6, private@^0.1.7, private@~0.1.5:
+ version "0.1.8"
+ resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
process-nextick-args@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
-process@^0.11.0:
+process@^0.11.10:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
@@ -6255,6 +7303,14 @@ progress@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f"
+promise.prototype.finally@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz#66f161b1643636e50e7cf201dc1b84a857f3864e"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.9.0"
+ function-bind "^1.1.1"
+
promise@^7.1.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
@@ -6267,7 +7323,7 @@ prop-types-extra@^1.0.1:
dependencies:
warning "^3.0.0"
-prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0:
+prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.5.9, prop-types@^15.6.0:
version "15.6.0"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856"
dependencies:
@@ -6286,9 +7342,9 @@ proxy-addr@~2.0.2:
forwarded "~0.1.2"
ipaddr.js "1.5.2"
-prr@~0.0.0:
- version "0.0.0"
- resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
+prr@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
pseudomap@^1.0.1, pseudomap@^1.0.2:
version "1.0.2"
@@ -6312,20 +7368,21 @@ punycode@^1.2.4, punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
-purest@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/purest/-/purest-2.0.1.tgz#371d318201a09e6b2a5bbfabc644a675b08ad646"
- dependencies:
- extend "2.0.1"
- request "2.60.0"
+punycode@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d"
-q@0.9.7:
- version "0.9.7"
- resolved "https://registry.yarnpkg.com/q/-/q-0.9.7.tgz#4de2e6cb3b29088c9e4cbc03bf9d42fb96ce2f75"
+q@2.0.x:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/q/-/q-2.0.3.tgz#75b8db0255a1a5af82f58c3f3aaa1efec7d0d134"
+ dependencies:
+ asap "^2.0.0"
+ pop-iterate "^1.0.1"
+ weak-map "^1.0.5"
q@^1.1.2:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1"
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
qr-image@^3.1.0:
version "3.2.0"
@@ -6335,21 +7392,17 @@ qs@2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404"
-qs@6.4.0, qs@~6.4.0:
- version "6.4.0"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
-
-qs@6.5.1, qs@^6.1.0, qs@~6.5.1:
+qs@6.5.1, qs@^6.1.0, qs@^6.4.0, qs@^6.5.1, qs@~6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
-qs@~4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607"
+qs@~6.3.0:
+ version "6.3.2"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c"
-qs@~6.2.0:
- version "6.2.3"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe"
+qs@~6.4.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
query-string@^4.1.0, query-string@^4.2.2:
version "4.3.4"
@@ -6366,9 +7419,31 @@ querystring@0.2.0, querystring@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
-ramda@^0.19.1:
- version "0.19.1"
- resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.19.1.tgz#89c4ad697265ff6b1face9f286439e2520d6679c"
+radium@^0.19.0:
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/radium/-/radium-0.19.6.tgz#b86721d08dbd303b061a4ae2ebb06cc6e335ae72"
+ dependencies:
+ array-find "^1.0.0"
+ exenv "^1.2.1"
+ inline-style-prefixer "^2.0.5"
+ prop-types "^15.5.8"
+
+raf@^3.4.0:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.0.tgz#a28876881b4bc2ca9117d4138163ddb80f781575"
+ dependencies:
+ performance-now "^2.1.0"
+
+railroad-diagrams@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
+
+randexp@^0.4.2:
+ version "0.4.6"
+ resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3"
+ dependencies:
+ discontinuous-range "1.0.0"
+ ret "~0.1.10"
random-bytes@~1.0.0:
version "1.0.0"
@@ -6381,17 +7456,24 @@ randomatic@^1.1.3:
is-number "^3.0.0"
kind-of "^4.0.0"
-randombytes@^2.0.0, randombytes@^2.0.1:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79"
+randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80"
+ dependencies:
+ safe-buffer "^5.1.0"
+
+randomfill@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.3.tgz#b96b7df587f01dd91726c418f30553b1418e3d62"
dependencies:
+ randombytes "^2.0.5"
safe-buffer "^5.1.0"
range-parser@^1.0.3, range-parser@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
-raw-body@2.3.2:
+raw-body@2.3.2, raw-body@^2.2.0:
version "2.3.2"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89"
dependencies:
@@ -6400,28 +7482,20 @@ raw-body@2.3.2:
iconv-lite "0.4.19"
unpipe "1.0.0"
-raw-body@~2.1.2:
- version "2.1.7"
- resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774"
- dependencies:
- bytes "2.4.0"
- iconv-lite "0.4.13"
- unpipe "1.0.0"
-
-raw-loader@^0.5.1:
+raw-loader@0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa"
rc@^1.1.7:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.5.tgz#275cd687f6e3b36cc756baa26dfee80a790301fd"
dependencies:
deep-extend "~0.4.0"
ini "~1.3.0"
minimist "^1.2.0"
strip-json-comments "~2.0.1"
-react-ab-test@^1.7.0:
+react-ab-test@1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/react-ab-test/-/react-ab-test-1.7.0.tgz#eec0f0f4c48dce33a081ac300fa79a2d36c2e8b6"
dependencies:
@@ -6449,7 +7523,24 @@ react-addons-test-utils@15.4.2:
fbjs "^0.8.4"
object-assign "^4.1.0"
-react-copy-to-clipboard@^4.2.3:
+react-autocomplete@1.7.2:
+ version "1.7.2"
+ resolved "https://registry.yarnpkg.com/react-autocomplete/-/react-autocomplete-1.7.2.tgz#c55a0a4b8a9f4cba911dfccb74ef74f2161c46e0"
+ dependencies:
+ dom-scroll-into-view "1.0.1"
+ prop-types "^15.5.10"
+
+react-color@^2.11.4:
+ version "2.13.8"
+ resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.13.8.tgz#bcc58f79a722b9bfc37c402e68cd18f26970aee4"
+ dependencies:
+ lodash "^4.0.1"
+ material-colors "^1.2.1"
+ prop-types "^15.5.10"
+ reactcss "^1.2.0"
+ tinycolor2 "^1.4.1"
+
+react-copy-to-clipboard@4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-4.3.1.tgz#aa429ce6029077c987e2bc4af7eec9a09ba5075b"
dependencies:
@@ -6457,19 +7548,41 @@ react-copy-to-clipboard@^4.2.3:
create-react-class "^15.5.2"
prop-types "^15.5.8"
+react-datetime@^2.11.1:
+ version "2.12.0"
+ resolved "https://registry.yarnpkg.com/react-datetime/-/react-datetime-2.12.0.tgz#9226a11730b7be1273c12f018a4d5613496e831c"
+ dependencies:
+ create-react-class "^15.5.2"
+ object-assign "^3.0.0"
+ prop-types "^15.5.7"
+ react-onclickoutside "^6.5.0"
+
react-deep-force-update@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-1.1.1.tgz#bcd31478027b64b3339f108921ab520b4313dc2c"
-react-dom@15.4.2, react-dom@^15.0.1:
- version "15.4.2"
- resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.2.tgz#015363f05b0a1fd52ae9efdd3a0060d90695208f"
+react-docgen@^2.20.0:
+ version "2.20.0"
+ resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-2.20.0.tgz#41a6da483a34a4aaed041a9909f5e61864d681cb"
dependencies:
- fbjs "^0.8.1"
+ async "^2.1.4"
+ babel-runtime "^6.9.2"
+ babylon "~5.8.3"
+ commander "^2.9.0"
+ doctrine "^2.0.0"
+ node-dir "^0.1.10"
+ recast "^0.12.6"
+
+react-dom@15.6.2, react-dom@^15.0.1:
+ version "15.6.2"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.6.2.tgz#41cfadf693b757faf2708443a1d1fd5a02bef730"
+ dependencies:
+ fbjs "^0.8.9"
loose-envify "^1.1.0"
object-assign "^4.1.0"
+ prop-types "^15.5.10"
-react-dropzone@^3.7.3:
+react-dropzone@3.13.4:
version "3.13.4"
resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-3.13.4.tgz#84da26815c40339691c49b4544c2ef7a16912ccc"
dependencies:
@@ -6490,13 +7603,45 @@ react-dropzone@^3.7.3:
uncontrollable "^4.0.3"
underscore.string "^3.3.4"
-react-highcharts@^8.3.3:
+react-fuzzy@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/react-fuzzy/-/react-fuzzy-0.5.1.tgz#295c2a4079ad39402e05605d9d7accd2db8527b6"
+ dependencies:
+ babel-runtime "^6.23.0"
+ classnames "^2.2.5"
+ fuse.js "^3.0.1"
+ prop-types "^15.5.9"
+
+react-highcharts@8.4.2:
version "8.4.2"
resolved "https://registry.yarnpkg.com/react-highcharts/-/react-highcharts-8.4.2.tgz#1d43865e7669ddd7b89a4b77c56d8554d8635036"
dependencies:
highcharts "^4.2.3"
-react-intl@^2.1.3:
+react-html-attributes@^1.3.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/react-html-attributes/-/react-html-attributes-1.4.1.tgz#97b5ec710da68833598c8be6f89ac436216840a5"
+ dependencies:
+ html-element-attributes "^1.0.0"
+
+react-icon-base@2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/react-icon-base/-/react-icon-base-2.1.0.tgz#a196e33fdf1e7aaa1fda3aefbb68bdad9e82a79d"
+
+react-icons@^2.2.7:
+ version "2.2.7"
+ resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-2.2.7.tgz#d7860826b258557510dac10680abea5ca23cf650"
+ dependencies:
+ react-icon-base "2.1.0"
+
+react-inspector@^2.2.2:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-2.2.2.tgz#c04f5248fa92ab6c23e37960e725fb7f48c34d05"
+ dependencies:
+ babel-runtime "^6.26.0"
+ is-dom "^1.0.9"
+
+react-intl@2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.4.0.tgz#66c14dc9df9a73b2fbbfbd6021726e80a613eb15"
dependencies:
@@ -6511,7 +7656,7 @@ react-lazy-cache@^3.0.1:
dependencies:
deep-equal "^1.0.1"
-react-medium-editor@^1.8.0:
+react-medium-editor@1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/react-medium-editor/-/react-medium-editor-1.8.1.tgz#016ffc3bb82f9364af15f7e43be75d6882555f5a"
dependencies:
@@ -6519,10 +7664,22 @@ react-medium-editor@^1.8.0:
medium-editor "^5.10.0"
object-assign "^4.0.1"
-react-notification@^5.0.7:
+react-modal@^3.1.10:
+ version "3.1.12"
+ resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.1.12.tgz#e80ab4e553ce946a6c96faf85eb31e0f9bd07470"
+ dependencies:
+ exenv "^1.2.0"
+ prop-types "^15.5.10"
+ warning "^3.0.0"
+
+react-notification@5.0.7:
version "5.0.7"
resolved "https://registry.yarnpkg.com/react-notification/-/react-notification-5.0.7.tgz#6923b299056b99b0a4cb2afcfe7595542b0bd8d8"
+react-onclickoutside@^6.5.0:
+ version "6.7.1"
+ resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.7.1.tgz#6a5b5b8b4eae6b776259712c89c8a2b36b17be93"
+
react-overlays@0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.6.3.tgz#e4e1f5b04b2cc5fc167083b9414ad42e9949b9bd"
@@ -6532,7 +7689,7 @@ react-overlays@0.6.3:
react-prop-types "^0.2.1"
warning "^2.1.0"
-react-overlays@^0.7.0:
+react-overlays@0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.7.2.tgz#03808f80d99dfadd93d67438c619aa55d07b3f80"
dependencies:
@@ -6542,19 +7699,19 @@ react-overlays@^0.7.0:
prop-types-extra "^1.0.1"
warning "^3.0.0"
-react-portal@^2.2.1:
+react-portal@2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/react-portal/-/react-portal-2.2.1.tgz#0cde8c35eeb0cce9a67b1e1255d5e4a2d147d1cf"
-react-prop-types@^0.2.1:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/react-prop-types/-/react-prop-types-0.2.2.tgz#ae49914d4952382113d0e210b2e51016f0bd7f19"
+react-prop-types@0.3.2, react-prop-types@^0.3.0:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/react-prop-types/-/react-prop-types-0.3.2.tgz#e2763ac6f3a80199d8981c3647c44b0554c97b7f"
dependencies:
warning "^2.0.0"
-react-prop-types@^0.3.0:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/react-prop-types/-/react-prop-types-0.3.2.tgz#e2763ac6f3a80199d8981c3647c44b0554c97b7f"
+react-prop-types@^0.2.1:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/react-prop-types/-/react-prop-types-0.2.2.tgz#ae49914d4952382113d0e210b2e51016f0bd7f19"
dependencies:
warning "^2.0.0"
@@ -6579,7 +7736,7 @@ react-rangeslider@1.0.3:
react "^15.0.1"
react-dom "^15.0.1"
-react-redux@^5.0.6:
+react-redux@5.0.6:
version "5.0.6"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.6.tgz#23ed3a4f986359d68b5212eaaa681e60d6574946"
dependencies:
@@ -6590,11 +7747,11 @@ react-redux@^5.0.6:
loose-envify "^1.1.0"
prop-types "^15.5.10"
-react-router-redux@^4.0.0:
+react-router-redux@4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/react-router-redux/-/react-router-redux-4.0.8.tgz#227403596b5151e182377dab835b5d45f0f8054e"
-react-router-scroll@^0.4.4:
+react-router-scroll@0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/react-router-scroll/-/react-router-scroll-0.4.4.tgz#4d7b71c75b45ff296e4adca1e029a86e898a155d"
dependencies:
@@ -6602,7 +7759,7 @@ react-router-scroll@^0.4.4:
scroll-behavior "^0.9.5"
warning "^3.0.0"
-react-router@^3.0.5:
+react-router@3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.2.0.tgz#62b6279d589b70b34e265113e4c0a9261a02ed36"
dependencies:
@@ -6614,7 +7771,7 @@ react-router@^3.0.5:
prop-types "^15.5.6"
warning "^3.0.0"
-react-rte-image@^0.3.1:
+react-rte-image@0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/react-rte-image/-/react-rte-image-0.3.1.tgz#311d48d0de252fd77a45c2e0107c5fb5c6a116e4"
dependencies:
@@ -6628,28 +7785,86 @@ react-rte-image@^0.3.1:
draft-js-utils "^0.1.5"
immutable "^3.8.1"
-react-timeago@^3.1.2:
+react-split-pane@^0.1.74:
+ version "0.1.76"
+ resolved "https://registry.yarnpkg.com/react-split-pane/-/react-split-pane-0.1.76.tgz#b2ba11e1055e18b6b0fd56e13e3adb35aec87af6"
+ dependencies:
+ "@types/inline-style-prefixer" "^3.0.0"
+ "@types/react" "^16.0.18"
+ inline-style-prefixer "^3.0.6"
+ prop-types "^15.5.10"
+ react-style-proptype "^3.0.0"
+
+react-style-proptype@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/react-style-proptype/-/react-style-proptype-3.1.0.tgz#c8912fc13460f5b0c1ec1114c729d535b52b8073"
+ dependencies:
+ prop-types "^15.5.4"
+
+react-test-renderer@15.6.2:
+ version "15.6.2"
+ resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-15.6.2.tgz#d0333434fc2c438092696ca770da5ed48037efa8"
+ dependencies:
+ fbjs "^0.8.9"
+ object-assign "^4.1.0"
+
+react-textarea-autosize@^5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-5.2.1.tgz#2b78f9067180f41b08ac59f78f1581abadd61e54"
+ dependencies:
+ prop-types "^15.6.0"
+
+react-timeago@3.4.3:
version "3.4.3"
resolved "https://registry.yarnpkg.com/react-timeago/-/react-timeago-3.4.3.tgz#eb9061eefb044e4a2b09ce8c99d34645b2dbfa25"
-react-transform-catch-errors@^1.0.1:
+react-transform-catch-errors@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/react-transform-catch-errors/-/react-transform-catch-errors-1.0.2.tgz#1b4d4a76e97271896fc16fe3086c793ec88a9eeb"
-react-transform-hmr@^1.0.4:
+react-transform-hmr@1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/react-transform-hmr/-/react-transform-hmr-1.0.4.tgz#e1a40bd0aaefc72e8dfd7a7cda09af85066397bb"
dependencies:
global "^4.3.0"
react-proxy "^1.1.7"
-react@15.4.2, react@^15.0.1:
- version "15.4.2"
- resolved "https://registry.yarnpkg.com/react/-/react-15.4.2.tgz#41f7991b26185392ba9bae96c8889e7e018397ef"
+react-transition-group@^1.1.2:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.1.tgz#e11f72b257f921b213229a774df46612346c7ca6"
dependencies:
- fbjs "^0.8.4"
+ chain-function "^1.0.0"
+ dom-helpers "^3.2.0"
+ loose-envify "^1.3.1"
+ prop-types "^15.5.6"
+ warning "^3.0.0"
+
+react-treebeard@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/react-treebeard/-/react-treebeard-2.1.0.tgz#fbd5cf51089b6f09a9b18350ab3bddf736e57800"
+ dependencies:
+ babel-runtime "^6.23.0"
+ deep-equal "^1.0.1"
+ prop-types "^15.5.8"
+ radium "^0.19.0"
+ shallowequal "^0.2.2"
+ velocity-react "^1.3.1"
+
+react@15.6.2, react@^15.0.1:
+ version "15.6.2"
+ resolved "https://registry.yarnpkg.com/react/-/react-15.6.2.tgz#dba0434ab439cfe82f108f0f511663908179aa72"
+ dependencies:
+ create-react-class "^15.6.0"
+ fbjs "^0.8.9"
loose-envify "^1.1.0"
object-assign "^4.1.0"
+ prop-types "^15.5.10"
+
+reactcss@^1.2.0:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd"
+ dependencies:
+ lodash "^4.0.1"
read-pkg-up@^1.0.1:
version "1.0.1"
@@ -6690,7 +7905,7 @@ readable-stream@1.0.27-1:
isarray "0.0.1"
string_decoder "~0.10.x"
-readable-stream@2.3.3, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.6:
+readable-stream@2.3.3, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c"
dependencies:
@@ -6702,35 +7917,6 @@ readable-stream@2.3.3, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-
string_decoder "~1.0.3"
util-deprecate "~1.0.1"
-"readable-stream@>=1.0.33-1 <1.1.0-0":
- version "1.0.34"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.1"
- isarray "0.0.1"
- string_decoder "~0.10.x"
-
-readable-stream@~1.1.9:
- version "1.1.14"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.1"
- isarray "0.0.1"
- string_decoder "~0.10.x"
-
-readable-stream@~2.0.5:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.1"
- isarray "~1.0.0"
- process-nextick-args "~1.0.6"
- string_decoder "~0.10.x"
- util-deprecate "~1.0.1"
-
readdirp@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
@@ -6740,16 +7926,28 @@ readdirp@^2.0.0:
readable-stream "^2.0.2"
set-immediate-shim "^1.0.1"
+realpath-native@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.0.0.tgz#7885721a83b43bd5327609f0ddecb2482305fdf0"
+ dependencies:
+ util.promisify "^1.0.0"
+
+recast@^0.12.6:
+ version "0.12.9"
+ resolved "https://registry.yarnpkg.com/recast/-/recast-0.12.9.tgz#e8e52bdb9691af462ccbd7c15d5a5113647a15f1"
+ dependencies:
+ ast-types "0.10.1"
+ core-js "^2.4.1"
+ esprima "~4.0.0"
+ private "~0.1.5"
+ source-map "~0.6.1"
+
rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
dependencies:
resolve "^1.1.6"
-redefine@^0.2.0:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/redefine/-/redefine-0.2.1.tgz#e89ee7a6f24d19fff62590569332dc60380a89a3"
-
redent@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
@@ -6775,17 +7973,6 @@ reduce-function-call@^1.0.1:
dependencies:
balanced-match "^0.4.2"
-reduce-reducers@^0.1.0:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-0.1.2.tgz#fa1b4718bc5292a71ddd1e5d839c9bea9770f14b"
-
-redux-actions@^0.9.1:
- version "0.9.1"
- resolved "https://registry.yarnpkg.com/redux-actions/-/redux-actions-0.9.1.tgz#a72767654bc21424c3df3f6240780ffa8872783c"
- dependencies:
- flux-standard-action "^0.6.0"
- reduce-reducers "^0.1.0"
-
redux-form@5.3.4:
version "5.3.4"
resolved "https://registry.yarnpkg.com/redux-form/-/redux-form-5.3.4.tgz#0536ec71daf919fc6ec93c9b39a9581213715980"
@@ -6796,21 +7983,11 @@ redux-form@5.3.4:
is-promise "^2.1.0"
react-lazy-cache "^3.0.1"
-redux-modules@0.0.5:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/redux-modules/-/redux-modules-0.0.5.tgz#ab38e8c7bf52b41f04a2f140c48703a241cebd1f"
- dependencies:
- camel-case "^1.2.2"
- camelize "^1.0.0"
- immutable "^3.7.6"
- ramda "^0.19.1"
- redux-actions "^0.9.1"
-
-redux-saga@^0.9.5:
+redux-saga@0.9.5:
version "0.9.5"
resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-0.9.5.tgz#f4bde5896e466932f758f86247b2fa6a4694ec2a"
-redux@^3.3.1:
+redux@3.7.2, redux@^3.7.2:
version "3.7.2"
resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.2.tgz#06b73123215901d25d065be342eb026bc1c8537b"
dependencies:
@@ -6827,14 +8004,14 @@ regenerate@^1.2.1:
version "1.3.3"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f"
+regenerator-runtime@0.11.1, regenerator-runtime@^0.11.0:
+ version "0.11.1"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
+
regenerator-runtime@^0.10.5:
version "0.10.5"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
-regenerator-runtime@^0.11.0:
- version "0.11.0"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1"
-
regenerator-transform@^0.10.0:
version "0.10.1"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd"
@@ -6879,7 +8056,7 @@ regjsparser@^0.1.4:
dependencies:
jsesc "~0.5.0"
-remarkable@^1.7.1:
+remarkable@1.7.1:
version "1.7.1"
resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.1.tgz#aaca4972100b66a642a63a1021ca4bac1be3bff6"
dependencies:
@@ -6904,11 +8081,21 @@ repeating@^2.0.0:
dependencies:
is-finite "^1.0.0"
-replace-ext@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924"
+request-promise-core@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6"
+ dependencies:
+ lodash "^4.13.1"
+
+request-promise-native@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5"
+ dependencies:
+ request-promise-core "1.1.1"
+ stealthy-require "^1.1.0"
+ tough-cookie ">=2.3.3"
-request@*, request@2, request@^2.79.0:
+request@*, request@2, request@2.83.x, request@^2.79.0, request@^2.83.0:
version "2.83.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356"
dependencies:
@@ -6935,68 +8122,45 @@ request@*, request@2, request@^2.79.0:
tunnel-agent "^0.6.0"
uuid "^3.1.0"
-request@2.60.0:
- version "2.60.0"
- resolved "https://registry.yarnpkg.com/request/-/request-2.60.0.tgz#498820957fcdded1d37749069610c85f61a29f2d"
- dependencies:
- aws-sign2 "~0.5.0"
- bl "~1.0.0"
- caseless "~0.11.0"
- combined-stream "~1.0.1"
- extend "~3.0.0"
- forever-agent "~0.6.0"
- form-data "~1.0.0-rc1"
- har-validator "^1.6.1"
- hawk "~3.1.0"
- http-signature "~0.11.0"
- isstream "~0.1.1"
- json-stringify-safe "~5.0.0"
- mime-types "~2.1.2"
- node-uuid "~1.4.0"
- oauth-sign "~0.8.0"
- qs "~4.0.0"
- stringstream "~0.0.4"
- tough-cookie ">=0.12.0"
- tunnel-agent "~0.4.0"
-
-request@2.74.x:
- version "2.74.0"
- resolved "https://registry.yarnpkg.com/request/-/request-2.74.0.tgz#7693ca768bbb0ea5c8ce08c084a45efa05b892ab"
+request@2.81.0:
+ version "2.81.0"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
dependencies:
aws-sign2 "~0.6.0"
aws4 "^1.2.1"
- bl "~1.1.2"
- caseless "~0.11.0"
+ caseless "~0.12.0"
combined-stream "~1.0.5"
extend "~3.0.0"
forever-agent "~0.6.1"
- form-data "~1.0.0-rc4"
- har-validator "~2.0.6"
+ form-data "~2.1.1"
+ har-validator "~4.2.1"
hawk "~3.1.3"
http-signature "~1.1.0"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.7"
- node-uuid "~1.4.7"
oauth-sign "~0.8.1"
- qs "~6.2.0"
+ performance-now "^0.2.0"
+ qs "~6.4.0"
+ safe-buffer "^5.0.1"
stringstream "~0.0.4"
tough-cookie "~2.3.0"
- tunnel-agent "~0.4.1"
+ tunnel-agent "^0.6.0"
+ uuid "^3.0.0"
-request@2.81.0:
- version "2.81.0"
- resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+request@~2.79.0:
+ version "2.79.0"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
dependencies:
aws-sign2 "~0.6.0"
aws4 "^1.2.1"
- caseless "~0.12.0"
+ caseless "~0.11.0"
combined-stream "~1.0.5"
extend "~3.0.0"
forever-agent "~0.6.1"
form-data "~2.1.1"
- har-validator "~4.2.1"
+ har-validator "~2.0.6"
hawk "~3.1.3"
http-signature "~1.1.0"
is-typedarray "~1.0.0"
@@ -7004,18 +8168,24 @@ request@2.81.0:
json-stringify-safe "~5.0.1"
mime-types "~2.1.7"
oauth-sign "~0.8.1"
- performance-now "^0.2.0"
- qs "~6.4.0"
- safe-buffer "^5.0.1"
+ qs "~6.3.0"
stringstream "~0.0.4"
tough-cookie "~2.3.0"
- tunnel-agent "^0.6.0"
+ tunnel-agent "~0.4.1"
uuid "^3.0.0"
require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+require-from-string@^1.1.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418"
+
+require-from-string@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.1.tgz#c545233e9d7da6616e9d59adfb39fc9f588676ff"
+
require-hacker@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/require-hacker/-/require-hacker-3.0.1.tgz#0879be067fcf067530665bcce4c89ac81a870477"
@@ -7034,23 +8204,37 @@ require-uncached@^1.0.3:
caller-path "^0.1.0"
resolve-from "^1.0.0"
-resolve-dir@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
+resolve-cwd@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
dependencies:
- expand-tilde "^1.2.2"
- global-modules "^0.2.3"
+ resolve-from "^3.0.0"
resolve-from@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
-resolve@^1.0.0, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.3:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86"
+resolve-from@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
+
+resolve@1.1.7:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
+
+resolve@^1.0.0, resolve@^1.1.6, resolve@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36"
dependencies:
path-parse "^1.0.5"
+restore-cursor@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
+ dependencies:
+ exit-hook "^1.0.0"
+ onetime "^1.0.0"
+
restore-cursor@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
@@ -7058,12 +8242,16 @@ restore-cursor@^2.0.0:
onetime "^2.0.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"
+
retry-as-promised@^2.0.0:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-2.3.1.tgz#f75059183f9730771c09bad1eed57537931cbc9d"
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-2.3.2.tgz#cd974ee4fd9b5fe03cbf31871ee48221c07737b7"
dependencies:
bluebird "^3.4.6"
- debug "^2.2.0"
+ debug "^2.6.9"
right-align@^0.1.1:
version "0.1.3"
@@ -7071,7 +8259,7 @@ right-align@^0.1.1:
dependencies:
align-text "^0.1.1"
-rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1:
+rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
dependencies:
@@ -7088,6 +8276,17 @@ rndm@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/rndm/-/rndm-1.2.0.tgz#f33fe9cfb52bbfd520aa18323bc65db110a1b76c"
+rootpath@0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/rootpath/-/rootpath-0.1.2.tgz#5b379a87dca906e9b91d690a599439bef267ea6b"
+
+rst-selector-parser@^2.2.3:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz#81b230ea2fcc6066c89e3472de794285d9b03d91"
+ dependencies:
+ lodash.flattendeep "^4.4.0"
+ nearley "^2.7.10"
+
run-async@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
@@ -7104,6 +8303,12 @@ rx-lite@*, rx-lite@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
+rxjs@^5.4.2:
+ version "5.5.6"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.6.tgz#e31fb96d6fd2ff1fd84bcea8ae9c02d007179c02"
+ dependencies:
+ symbol-observable "1.0.1"
+
safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
@@ -7112,11 +8317,29 @@ safe-buffer@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
-samsam@1.1.2, samsam@~1.1:
+samsam@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.2.tgz#bec11fdc83a9fda063401210e40176c3024d1567"
-sanitize-html@^1.11.4:
+samsam@~1.1:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.3.tgz#9f5087419b4d091f232571e7fa52e90b0f552621"
+
+sane@^2.0.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/sane/-/sane-2.3.0.tgz#3f3df584abf69e63d4bb74f0f8c42468e4d7d46b"
+ dependencies:
+ anymatch "^1.3.0"
+ exec-sh "^0.2.0"
+ fb-watchman "^2.0.0"
+ minimatch "^3.0.2"
+ minimist "^1.1.1"
+ walker "~1.0.5"
+ watch "~0.18.0"
+ optionalDependencies:
+ fsevents "^1.1.1"
+
+sanitize-html@1.14.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.14.1.tgz#730ffa2249bdf18333effe45b286173c9c5ad0b8"
dependencies:
@@ -7124,7 +8347,7 @@ sanitize-html@^1.11.4:
regexp-quote "0.0.0"
xtend "^4.0.0"
-sass-graph@^2.1.1:
+sass-graph@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49"
dependencies:
@@ -7133,7 +8356,7 @@ sass-graph@^2.1.1:
scss-tokenizer "^0.2.3"
yargs "^7.0.0"
-sass-loader@^6.0.6:
+sass-loader@6.0.6:
version "6.0.6"
resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-6.0.6.tgz#e9d5e6c1f155faa32a4b26d7a9b7107c225e40f9"
dependencies:
@@ -7143,7 +8366,7 @@ sass-loader@^6.0.6:
lodash.tail "^4.1.1"
pify "^3.0.0"
-sax@^1.2.1, sax@~1.2.1:
+sax@^1.2.1, sax@^1.2.4, sax@~1.2.1:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
@@ -7153,13 +8376,20 @@ schema-utils@^0.3.0:
dependencies:
ajv "^5.0.0"
+schema-utils@^0.4.0:
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.3.tgz#e2a594d3395834d5e15da22b48be13517859458e"
+ dependencies:
+ ajv "^5.0.0"
+ ajv-keywords "^2.1.0"
+
scmp@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/scmp/-/scmp-0.0.3.tgz#3648df2d7294641e7f78673ffc29681d9bad9073"
scroll-behavior@^0.9.5:
- version "0.9.5"
- resolved "https://registry.yarnpkg.com/scroll-behavior/-/scroll-behavior-0.9.5.tgz#41da30b559da004eb48450f6cff6068c7696ff23"
+ version "0.9.9"
+ resolved "https://registry.yarnpkg.com/scroll-behavior/-/scroll-behavior-0.9.9.tgz#ebfe0658455b82ad885b66195215416674dacce2"
dependencies:
dom-helpers "^3.2.1"
invariant "^2.2.2"
@@ -7171,17 +8401,13 @@ scss-tokenizer@^0.2.3:
js-base64 "^2.1.8"
source-map "^0.4.2"
-secure-random@^1.1.1:
+secure-random@1.1.1, secure-random@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/secure-random/-/secure-random-1.1.1.tgz#0880f2d8c5185f4bcb4684058c836b4ddb07145a"
-"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.1.0, semver@^5.3.0:
- version "5.4.1"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
-
-semver@^4.1.0:
- version "4.3.6"
- resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da"
+"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
semver@~5.3.0:
version "5.3.0"
@@ -7209,7 +8435,7 @@ sendgrid-rest@^2.3.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/sendgrid-rest/-/sendgrid-rest-2.4.0.tgz#88e11a86375ec0e14b5faf1b4a0a191639ce90ef"
-sendgrid@^4.0.1:
+sendgrid@4.10.0:
version "4.10.0"
resolved "https://registry.yarnpkg.com/sendgrid/-/sendgrid-4.10.0.tgz#fd64ae3b3f3a94e14aa0ee587db2a01333b07f53"
dependencies:
@@ -7221,30 +8447,20 @@ sendgrid@^4.0.1:
mailparser "^0.6.1"
sendgrid-rest "^2.3.0"
-sentence-case@^1.1.1:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-1.1.3.tgz#8034aafc2145772d3abe1509aa42c9e1042dc139"
+sequelize-cli@3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/sequelize-cli/-/sequelize-cli-3.2.0.tgz#c01333a98ad36466972624bb51221dd0c5a02df5"
dependencies:
- lower-case "^1.1.1"
-
-sequelize-cli@^2.3.1:
- version "2.8.0"
- resolved "https://registry.yarnpkg.com/sequelize-cli/-/sequelize-cli-2.8.0.tgz#4304cce60e499169603f838dedbab421c9849e74"
- dependencies:
- bluebird "^3.5.0"
- cli-color "~1.2.0"
- findup-sync "^1.0.0"
- fs-extra "^4.0.1"
- gulp "^3.9.1"
- gulp-help "~1.6.1"
- js-beautify "^1.6.11"
+ bluebird "^3.5.1"
+ cli-color "^1.2.0"
+ fs-extra "^4.0.2"
+ js-beautify "^1.7.4"
lodash "^4.17.4"
- moment "^2.17.1"
- resolve "^1.3.3"
- umzug "^1.12.0"
- yargs "^8.0.1"
+ resolve "^1.5.0"
+ umzug "^2.1.0"
+ yargs "^8.0.2"
-sequelize@^3.21.0:
+sequelize@3.30.4:
version "3.30.4"
resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-3.30.4.tgz#bda2df1e31854b099e4149a111e9fc0a5ca1d1a4"
dependencies:
@@ -7265,9 +8481,15 @@ sequelize@^3.21.0:
validator "^5.2.0"
wkx "0.2.0"
-sequencify@~0.0.7:
- version "0.0.7"
- resolved "https://registry.yarnpkg.com/sequencify/-/sequencify-0.0.7.tgz#90cff19d02e07027fd767f5ead3e7b95d1e7380c"
+serve-favicon@^2.4.5:
+ version "2.4.5"
+ resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.4.5.tgz#49d9a46863153a9240691c893d2b0e7d85d6d436"
+ dependencies:
+ etag "~1.8.1"
+ fresh "0.5.2"
+ ms "2.0.0"
+ parseurl "~1.3.2"
+ safe-buffer "5.1.1"
serve-static@1.13.1:
version "1.13.1"
@@ -7299,8 +8521,8 @@ setprototypeof@1.1.0:
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
sha.js@^2.4.0, sha.js@^2.4.8:
- version "2.4.9"
- resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.9.tgz#98f64880474b74f4a38b8da9d3c0f2d104633e7d"
+ version "2.4.10"
+ resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.10.tgz#b1fde5cd7d11a5626638a07c604ab909cfa31f9b"
dependencies:
inherits "^2.0.1"
safe-buffer "^5.0.1"
@@ -7314,6 +8536,12 @@ shallow-clone@^0.1.2:
lazy-cache "^0.2.3"
mixin-object "^2.0.1"
+shallowequal@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-0.2.2.tgz#1e32fd5bcab6ad688a4812cb0cc04efc75c7014e"
+ dependencies:
+ lodash.keys "^3.1.2"
+
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@@ -7332,11 +8560,23 @@ shelljs@0.7.7:
interpret "^1.0.0"
rechoir "^0.6.2"
+shelljs@^0.7.8:
+ version "0.7.8"
+ resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3"
+ dependencies:
+ glob "^7.0.0"
+ interpret "^1.0.0"
+ rechoir "^0.6.2"
+
+shellwords@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
+
shimmer@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.1.0.tgz#97d7377137ffbbab425522e429fe0aa89a488b35"
-sigmund@^1.0.1, sigmund@~1.0.0:
+sigmund@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
@@ -7348,11 +8588,7 @@ simple-html-tokenizer@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/simple-html-tokenizer/-/simple-html-tokenizer-0.1.1.tgz#05c2eec579ffffe145a030ac26cfea61b980fabe"
-sinon-chai@^2.8.0:
- version "2.14.0"
- resolved "https://registry.yarnpkg.com/sinon-chai/-/sinon-chai-2.14.0.tgz#da7dd4cc83cd6a260b67cca0f7a9fdae26a1205d"
-
-sinon@^1.17.3:
+sinon@1.17.7:
version "1.17.7"
resolved "https://registry.yarnpkg.com/sinon/-/sinon-1.17.7.tgz#4542a4f49ba0c45c05eb2e9dd9d203e2b8efe0bf"
dependencies:
@@ -7365,6 +8601,10 @@ slash@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+slice-ansi@0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
+
slice-ansi@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d"
@@ -7378,8 +8618,8 @@ sntp@1.x.x:
hoek "2.x.x"
sntp@2.x.x:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.0.2.tgz#5064110f0af85f7cfdb7d6b67a40028ce52b4b2b"
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8"
dependencies:
hoek "4.x.x"
@@ -7399,31 +8639,26 @@ source-map-support@^0.4.15:
dependencies:
source-map "^0.5.6"
+source-map-support@^0.5.0:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.3.tgz#2b3d5fff298cfa4d1afd7d4352d569e9a0158e76"
+ dependencies:
+ source-map "^0.6.0"
+
source-map@^0.4.2, source-map@^0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
dependencies:
amdefine ">=0.0.4"
-source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3, source-map@~0.5.6:
+source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1, source-map@~0.5.6:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
-source-map@^0.6.1:
+source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
-sparkles@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3"
-
-spawn-sync@^1.0.15:
- version "1.0.15"
- resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476"
- dependencies:
- concat-stream "^1.4.7"
- os-shim "^0.1.2"
-
spdx-correct@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
@@ -7438,7 +8673,7 @@ spdx-license-ids@^1.0.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
-speakingurl@^9.0.0:
+speakingurl@9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/speakingurl/-/speakingurl-9.0.0.tgz#a99494041627f31d6d14c38b571ffa3a2ec95bda"
@@ -7450,7 +8685,7 @@ sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
-sqlite3@^3.1.8:
+sqlite3@3.1.13:
version "3.1.13"
resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-3.1.13.tgz#d990a05627392768de6278bafd1a31fdfe907dd9"
dependencies:
@@ -7475,7 +8710,19 @@ sshpk@^1.7.0:
jsbn "~0.1.0"
tweetnacl "~0.14.0"
-statuses@1, "statuses@>= 1.3.1 < 2", statuses@^1.2.0, statuses@~1.3.1:
+stack-utils@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.1.tgz#d4f33ab54e8e38778b0ca5cfd3b3afb12db68620"
+
+staged-git-files@0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/staged-git-files/-/staged-git-files-0.0.4.tgz#d797e1b551ca7a639dec0237dc6eb4bb9be17d35"
+
+statuses@1, "statuses@>= 1.3.1 < 2", statuses@^1.2.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
+
+statuses@~1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
@@ -7485,32 +8732,20 @@ stdout-stream@^1.4.0:
dependencies:
readable-stream "^2.0.1"
-"steem@github:steemit/steem-js#72a36c835a74f446da47e36feea5d5f1f4dde55b":
- version "0.6.5"
- resolved "https://codeload.github.com/steemit/steem-js/tar.gz/72a36c835a74f446da47e36feea5d5f1f4dde55b"
- dependencies:
- bigi "^1.4.2"
- bluebird "^3.4.6"
- browserify-aes "^1.0.6"
- bs58 "^4.0.0"
- buffer "^5.0.6"
- bytebuffer "^5.0.1"
- create-hash "^1.1.2"
- create-hmac "^1.1.4"
- cross-env "^5.0.0"
- debug "^2.6.8"
- detect-node "^2.0.3"
- ecurve "^1.0.5"
- fetch-ponyfill "^4.1.0"
- lodash "^4.16.4"
- postinstall-build "^5.0.1"
- secure-random "^1.1.1"
- ws "^3.0.0"
+stealthy-require@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
-store@^1.3.20:
+store@1.3.20:
version "1.3.20"
resolved "https://registry.yarnpkg.com/store/-/store-1.3.20.tgz#13ea7e3fb2d6c239868265d686b1d84e99c5be3e"
+storybook-addon-intl@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/storybook-addon-intl/-/storybook-addon-intl-2.3.0.tgz#94711276cefeb0b9ef13b1e70a96516c1fe0cfd2"
+ dependencies:
+ prop-types "^15.5.0"
+
stream-browserify@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
@@ -7518,24 +8753,33 @@ stream-browserify@^2.0.1:
inherits "~2.0.1"
readable-stream "^2.0.2"
-stream-consume@~0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f"
-
-stream-http@^2.3.1:
- version "2.7.2"
- resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad"
+stream-http@^2.7.2:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.0.tgz#fd86546dac9b1c91aff8fc5d287b98fafb41bc10"
dependencies:
builtin-status-codes "^3.0.0"
inherits "^2.0.1"
- readable-stream "^2.2.6"
+ readable-stream "^2.3.3"
to-arraybuffer "^1.0.0"
xtend "^4.0.0"
+stream-to-observable@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/stream-to-observable/-/stream-to-observable-0.2.0.tgz#59d6ea393d87c2c0ddac10aa0d561bc6ba6f0e10"
+ dependencies:
+ any-observable "^0.2.0"
+
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"
+string-length@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed"
+ dependencies:
+ astral-regex "^1.0.0"
+ strip-ansi "^4.0.0"
+
string-width@^1.0.1, string-width@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
@@ -7551,20 +8795,40 @@ string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
-string.prototype.startswith@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/string.prototype.startswith/-/string.prototype.startswith-0.2.0.tgz#da68982e353a4e9ac4a43b450a2045d1c445ae7b"
+string.prototype.padend@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.4.3"
+ function-bind "^1.0.2"
-string_decoder@^0.10.25, string_decoder@~0.10.x:
- version "0.10.31"
- resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+string.prototype.padstart@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/string.prototype.padstart/-/string.prototype.padstart-3.0.0.tgz#5bcfad39f4649bb2d031292e19bcf0b510d4b242"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.4.3"
+ function-bind "^1.0.2"
-string_decoder@~1.0.3:
+string_decoder@^1.0.0, string_decoder@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
dependencies:
safe-buffer "~5.1.0"
+string_decoder@~0.10.x:
+ version "0.10.31"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
+stringify-object@^3.2.0:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.2.2.tgz#9853052e5a88fb605a44cd27445aa257ad7ffbcd"
+ dependencies:
+ get-own-enumerable-property-symbols "^2.0.1"
+ is-obj "^1.0.1"
+ is-regexp "^1.0.0"
+
stringstream@~0.0.4, stringstream@~0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
@@ -7581,12 +8845,9 @@ strip-ansi@^4.0.0:
dependencies:
ansi-regex "^3.0.0"
-strip-bom@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-1.0.0.tgz#85b8862f3844b5a6d5ec8467a93598173a36f794"
- dependencies:
- first-chunk-stream "^1.0.0"
- is-utf8 "^0.2.0"
+strip-bom@3.0.0, strip-bom@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
strip-bom@^2.0.0:
version "2.0.0"
@@ -7594,10 +8855,6 @@ strip-bom@^2.0.0:
dependencies:
is-utf8 "^0.2.0"
-strip-bom@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
-
strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
@@ -7608,17 +8865,28 @@ strip-indent@^1.0.1:
dependencies:
get-stdin "^4.0.1"
+strip-indent@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
+
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"
-style-loader@^0.18.2:
+style-loader@0.18.2:
version "0.18.2"
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.18.2.tgz#cc31459afbcd6d80b7220ee54b291a9fd66ff5eb"
dependencies:
loader-utils "^1.0.2"
schema-utils "^0.3.0"
+style-loader@^0.19.1:
+ version "0.19.1"
+ resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.19.1.tgz#591ffc80bcefe268b77c5d9ebc0505d772619f85"
+ dependencies:
+ loader-utils "^1.0.2"
+ schema-utils "^0.3.0"
+
superagent@^1.7.2:
version "1.8.5"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-1.8.5.tgz#1c0ddc3af30e80eb84ebc05cb2122da8fe940b55"
@@ -7635,34 +8903,36 @@ superagent@^1.7.2:
readable-stream "1.0.27-1"
reduce-component "1.0.1"
-supertest@^1.2.0:
+supertest@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/supertest/-/supertest-1.2.0.tgz#850a795f9068d2faf19e01799ff09962e0ce43be"
dependencies:
methods "1.x"
superagent "^1.7.2"
-supports-color@1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e"
-
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
-supports-color@^3.2.3:
+supports-color@^3.1.2, supports-color@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
dependencies:
has-flag "^1.0.0"
-supports-color@^4.0.0, supports-color@^4.2.1, supports-color@^4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e"
+supports-color@^4.0.0, supports-color@^4.2.1:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b"
dependencies:
has-flag "^2.0.0"
-svg-inline-loader@^0.8.0:
+supports-color@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.1.0.tgz#058a021d1b619f7ddf3980d712ea3590ce7de3d5"
+ dependencies:
+ has-flag "^2.0.0"
+
+svg-inline-loader@0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/svg-inline-loader/-/svg-inline-loader-0.8.0.tgz#7e9d905d80d0b4e68d2df21afcd08ee9e9a3ea6e"
dependencies:
@@ -7670,11 +8940,15 @@ svg-inline-loader@^0.8.0:
object-assign "^4.0.1"
simple-html-tokenizer "^0.1.1"
-svg-inline-react@^1.0.2:
+svg-inline-react@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/svg-inline-react/-/svg-inline-react-1.0.3.tgz#68d15bf88f99f64daa52821ed5441612d8ad9041"
-svgo-loader@^1.2.1:
+svg-tag-names@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/svg-tag-names/-/svg-tag-names-1.1.1.tgz#9641b29ef71025ee094c7043f7cdde7d99fbd50a"
+
+svgo-loader@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/svgo-loader/-/svgo-loader-1.2.1.tgz#e255cdebf56753ff83bd28d1d7a20762c0df5130"
dependencies:
@@ -7692,11 +8966,19 @@ svgo@^0.7.0:
sax "~1.2.1"
whet.extend "~0.9.9"
+symbol-observable@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4"
+
+symbol-observable@^0.2.2:
+ version "0.2.4"
+ resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-0.2.4.tgz#95a83db26186d6af7e7a18dbd9760a2f86d08f40"
+
symbol-observable@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d"
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
-symbol-tree@^3.2.1:
+symbol-tree@^3.2.1, symbol-tree@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
@@ -7728,8 +9010,8 @@ tapable@^0.2.7:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22"
tar-pack@^3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984"
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f"
dependencies:
debug "^2.2.0"
fstream "^1.0.10"
@@ -7748,7 +9030,7 @@ tar@^2.0.0, tar@^2.2.1:
fstream "^1.0.2"
inherits "2"
-tarantool-driver@^2.0.1:
+tarantool-driver@2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/tarantool-driver/-/tarantool-driver-2.0.5.tgz#ea6605ee4a66128c77a2d38a74fbd3bc612ba4e6"
dependencies:
@@ -7769,6 +9051,16 @@ terraformer@~1.0.5:
dependencies:
"@types/geojson" "^1.0.0"
+test-exclude@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.1.1.tgz#4d84964b0966b0087ecc334a2ce002d3d9341e26"
+ dependencies:
+ arrify "^1.0.1"
+ micromatch "^2.3.11"
+ object-assign "^4.1.0"
+ read-pkg-up "^1.0.1"
+ require-main-filename "^1.0.1"
+
text-table@~0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@@ -7796,45 +9088,21 @@ thenify@3, "thenify@>= 3.1.0 < 4":
dependencies:
any-promise "^1.0.0"
-through2@^0.6.1:
- version "0.6.5"
- resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48"
- dependencies:
- readable-stream ">=1.0.33-1 <1.1.0-0"
- xtend ">=4.0.0 <4.1.0-0"
-
-through2@^2.0.0:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
- dependencies:
- readable-stream "^2.1.5"
- xtend "~4.0.1"
+throat@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a"
-through@^2.3.6:
+through@^2.3.6, through@^2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
-thunkify@2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/thunkify/-/thunkify-2.1.2.tgz#faa0e9d230c51acc95ca13a361ac05ca7e04553d"
-
-tildify@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/tildify/-/tildify-1.2.0.tgz#dcec03f55dca9b7aa3e5b04f21817eb56e63588a"
- dependencies:
- os-homedir "^1.0.0"
-
-time-stamp@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3"
-
time-stamp@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-2.0.0.tgz#95c6a44530e15ba8d6f4a3ecb8c3a3fac46da357"
-timers-browserify@^2.0.2:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.4.tgz#96ca53f4b794a5e7c0e1bd7cc88a372298fa01e6"
+timers-browserify@^2.0.4:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.6.tgz#241e76927d9ca05f4d959819022f5b3664b64bae"
dependencies:
setimmediate "^1.0.4"
@@ -7845,12 +9113,20 @@ timers-ext@0.1, timers-ext@^0.1.2:
es5-ext "~0.10.14"
next-tick "1"
+tinycolor2@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
+
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
dependencies:
os-tmpdir "~1.0.2"
+tmpl@1.0.x:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
+
to-arraybuffer@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
@@ -7859,10 +9135,6 @@ to-fast-properties@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
-to-iso-string@0.0.2:
- version "0.0.2"
- resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1"
-
toggle-selection@^1.0.3:
version "1.0.6"
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
@@ -7871,12 +9143,18 @@ toposort-class@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988"
-tough-cookie@>=0.12.0, tough-cookie@^2.3.2, tough-cookie@~2.3.0, tough-cookie@~2.3.3:
+tough-cookie@>=2.3.3, tough-cookie@^2.3.2, tough-cookie@^2.3.3, tough-cookie@~2.3.0, tough-cookie@~2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561"
dependencies:
punycode "^1.4.1"
+tr46@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
+ dependencies:
+ punycode "^2.1.0"
+
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
@@ -7889,9 +9167,11 @@ trim-right@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
-tryit@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb"
+"true-case-path@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.2.tgz#7ec91130924766c7f573be3020c34f8fdfd00d62"
+ dependencies:
+ glob "^6.0.4"
tsscmp@1.0.5:
version "1.0.5"
@@ -7907,7 +9187,7 @@ tunnel-agent@^0.6.0:
dependencies:
safe-buffer "^5.0.1"
-tunnel-agent@~0.4.0, tunnel-agent@~0.4.1:
+tunnel-agent@~0.4.1:
version "0.4.3"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb"
@@ -7915,17 +9195,19 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
-twilio@^2.11.1:
- version "2.11.1"
- resolved "https://registry.yarnpkg.com/twilio/-/twilio-2.11.1.tgz#451099467313c56b3767994df2d19062f10ef8c4"
- dependencies:
- deprecate "^0.1.0"
- jsonwebtoken "5.4.x"
- q "0.9.7"
- request "2.74.x"
+twilio@3.11.2:
+ version "3.11.2"
+ resolved "https://registry.yarnpkg.com/twilio/-/twilio-3.11.2.tgz#879829c51d9f131622808fc4fe9b0b29cc9ca1ec"
+ dependencies:
+ deprecate "1.0.0"
+ jsonwebtoken "^8.1.0"
+ lodash "4.0.0"
+ moment "2.19.3"
+ q "2.0.x"
+ request "2.83.x"
+ rootpath "0.1.2"
scmp "0.0.3"
- string.prototype.startswith "^0.2.0"
- underscore "1.x"
+ xmlbuilder "9.0.1"
type-check@~0.3.2:
version "0.3.2"
@@ -7933,15 +9215,7 @@ type-check@~0.3.2:
dependencies:
prelude-ls "~1.1.2"
-type-detect@0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822"
-
-type-detect@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2"
-
-type-is@^1.5.5, type-is@~1.6.15, type-is@~1.6.6:
+type-is@^1.5.5, type-is@^1.6.14, type-is@~1.6.15:
version "1.6.15"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
dependencies:
@@ -7994,24 +9268,19 @@ uid-safe@2.1.4:
random-bytes "~1.0.0"
ultron@~1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.0.tgz#b07a2e6a541a815fc6a34ccd4533baec307ca864"
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c"
-umzug@^1.12.0:
- version "1.12.0"
- resolved "https://registry.yarnpkg.com/umzug/-/umzug-1.12.0.tgz#a79c91f2862eee3130c6c347f2b90ad68a66e8b8"
+umzug@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/umzug/-/umzug-2.1.0.tgz#c49dd71c7c26d082a9c9d3592dc6dc92cf867761"
dependencies:
+ babel-runtime "^6.23.0"
bluebird "^3.4.1"
lodash "^4.17.0"
- moment "^2.16.0"
- redefine "^0.2.0"
resolve "^1.0.0"
-unc-path-regex@^0.1.0:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
-
-uncontrollable@^3.2.1:
+uncontrollable@3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-3.3.1.tgz#e23b402e7a4c69b1853fb4b43ce34b6480c65b6f"
dependencies:
@@ -8023,7 +9292,7 @@ uncontrollable@^4.0.3:
dependencies:
invariant "^2.1.0"
-underscore.string@^3.2.3, underscore.string@^3.3.4:
+underscore.string@3.3.4, underscore.string@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db"
dependencies:
@@ -8034,10 +9303,14 @@ underscore.string@~2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.4.0.tgz#8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b"
-underscore@1.x, underscore@^1.8.3:
+underscore@^1.8.3:
version "1.8.3"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022"
+underscore@~1.4.4:
+ version "1.4.4"
+ resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.4.4.tgz#61a6a32010622afa07963bf325203cf12239d604"
+
underscore@~1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209"
@@ -8056,9 +9329,11 @@ uniqs@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
-unique-stream@^1.0.0:
+unique-string@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-1.0.0.tgz#d59a4a75427447d9aa6c91e70263f8d26a4b104b"
+ resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
+ dependencies:
+ crypto-random-string "^1.0.0"
universalify@^0.1.0:
version "0.1.1"
@@ -8068,16 +9343,13 @@ unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
-upper-case@^1.1.1:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
-
-url-loader@^0.5.9:
- version "0.5.9"
- resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.9.tgz#cc8fea82c7b906e7777019250869e569e995c295"
+url-loader@0.6.2, url-loader@^0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.6.2.tgz#a007a7109620e9d988d14bce677a1decb9a993f7"
dependencies:
loader-utils "^1.0.2"
- mime "1.3.x"
+ mime "^1.4.1"
+ schema-utils "^0.3.0"
url@^0.11.0:
version "0.11.0"
@@ -8098,6 +9370,13 @@ 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"
+util.promisify@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030"
+ dependencies:
+ define-properties "^1.1.2"
+ object.getownpropertydescriptors "^2.0.3"
+
util@0.10.3, "util@>=0.10.3 <1", util@^0.10.3:
version "0.10.3"
resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
@@ -8109,16 +9388,17 @@ utils-merge@1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
uue@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/uue/-/uue-3.1.0.tgz#5d67d37030e66efebbb4b8aac46daf9b55befbf6"
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/uue/-/uue-3.1.1.tgz#cebb18980e005769ac7254a0a158a49ad173a518"
dependencies:
+ escape-string-regexp "~1.0.5"
extend "~3.0.0"
-uuid@^3.0.0, uuid@^3.0.1, uuid@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
+uuid@^3.0.0, uuid@^3.1.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
-v8flags@^2.0.2, v8flags@^2.1.1:
+v8flags@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"
dependencies:
@@ -8139,6 +9419,19 @@ vary@^1.0.0, vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+velocity-animate@^1.4.0:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/velocity-animate/-/velocity-animate-1.5.1.tgz#606837047bab8fbfb59a636d1d82ecc3f7bd71a6"
+
+velocity-react@^1.3.1:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/velocity-react/-/velocity-react-1.3.3.tgz#d6d47276cfc8be2a75623879b20140ac58c1b82b"
+ dependencies:
+ lodash "^3.10.1"
+ prop-types "^15.5.8"
+ react-transition-group "^1.1.2"
+ velocity-animate "^1.4.0"
+
vendors@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22"
@@ -8151,40 +9444,24 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
-vinyl-fs@^0.3.0:
- version "0.3.14"
- resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-0.3.14.tgz#9a6851ce1cac1c1cea5fe86c0931d620c2cfa9e6"
- dependencies:
- defaults "^1.0.0"
- glob-stream "^3.1.5"
- glob-watcher "^0.0.6"
- graceful-fs "^3.0.0"
- mkdirp "^0.5.0"
- strip-bom "^1.0.0"
- through2 "^0.6.1"
- vinyl "^0.4.0"
-
-vinyl@^0.4.0:
- version "0.4.6"
- resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847"
- dependencies:
- clone "^0.2.0"
- clone-stats "^0.0.1"
-
-vinyl@^0.5.0:
- version "0.5.3"
- resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde"
- dependencies:
- clone "^1.0.0"
- clone-stats "^0.0.1"
- replace-ext "0.0.1"
-
vm-browserify@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
dependencies:
indexof "0.0.1"
+w3c-hr-time@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045"
+ dependencies:
+ browser-process-hrtime "^0.1.2"
+
+walker@~1.0.5:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
+ dependencies:
+ makeerror "1.0.x"
+
warning@^2.0.0, warning@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/warning/-/warning-2.1.0.tgz#21220d9c63afc77a8c92111e011af705ce0c6901"
@@ -8197,6 +9474,13 @@ warning@^3.0.0:
dependencies:
loose-envify "^1.0.0"
+watch@~0.18.0:
+ version "0.18.0"
+ resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986"
+ dependencies:
+ exec-sh "^0.2.0"
+ minimist "^1.2.0"
+
watchpack@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.4.0.tgz#4a1472bcbb952bd0a9bb4036801f954dfb39faac"
@@ -8205,7 +9489,11 @@ watchpack@^1.4.0:
chokidar "^1.7.0"
graceful-fs "^4.1.2"
-web-push@^3.2.1:
+weak-map@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/weak-map/-/weak-map-1.0.5.tgz#79691584d98607f5070bd3b70a40e6bb22e401eb"
+
+web-push@3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/web-push/-/web-push-3.2.3.tgz#269492aa06d1481a8222425baf4c68fe23fcbefc"
dependencies:
@@ -8219,11 +9507,11 @@ webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
-webidl-conversions@^4.0.0:
+webidl-conversions@^4.0.0, webidl-conversions@^4.0.1, webidl-conversions@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
-webpack-bundle-analyzer@^2.9.0:
+webpack-bundle-analyzer@2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.9.0.tgz#b58bc34cc30b27ffdbaf3d00bf27aba6fa29c6e3"
dependencies:
@@ -8239,7 +9527,7 @@ webpack-bundle-analyzer@^2.9.0:
opener "^1.4.3"
ws "^2.3.1"
-webpack-dev-middleware@^1.10.0, webpack-dev-middleware@^1.12.0:
+webpack-dev-middleware@1.12.0:
version "1.12.0"
resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz#d34efefb2edda7e1d3b5dbe07289513219651709"
dependencies:
@@ -8249,16 +9537,26 @@ webpack-dev-middleware@^1.10.0, webpack-dev-middleware@^1.12.0:
range-parser "^1.0.3"
time-stamp "^2.0.0"
-webpack-hot-middleware@2.x:
- version "2.19.1"
- resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.19.1.tgz#5db32c31c955c1ead114d37c7519ea554da0d405"
+webpack-dev-middleware@^1.10.0, webpack-dev-middleware@^1.12.2:
+ version "1.12.2"
+ resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz#f8fc1120ce3b4fc5680ceecb43d777966b21105e"
+ dependencies:
+ memory-fs "~0.4.1"
+ mime "^1.5.0"
+ path-is-absolute "^1.0.0"
+ range-parser "^1.0.3"
+ time-stamp "^2.0.0"
+
+webpack-hot-middleware@2.x, webpack-hot-middleware@^2.21.0:
+ version "2.21.0"
+ resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.21.0.tgz#7b3c113a7a4b301c91e0749573c7aab28b414b52"
dependencies:
ansi-html "0.0.7"
html-entities "^1.2.0"
querystring "^0.2.0"
strip-ansi "^3.0.0"
-webpack-isomorphic-tools@^3.0.3:
+webpack-isomorphic-tools@3.0.5:
version "3.0.5"
resolved "https://registry.yarnpkg.com/webpack-isomorphic-tools/-/webpack-isomorphic-tools-3.0.5.tgz#60f04dcaf61cfe54c5b6bc771dde1ea3ed9ff3bc"
dependencies:
@@ -8271,13 +9569,13 @@ webpack-isomorphic-tools@^3.0.3:
uglify-js "^2.7.0"
webpack-sources@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.0.1.tgz#c7356436a4d13123be2e2426a05d1dad9cbe65cf"
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54"
dependencies:
source-list-map "^2.0.0"
- source-map "~0.5.3"
+ source-map "~0.6.1"
-webpack@^3.5.5:
+webpack@3.7.1:
version "3.7.1"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.7.1.tgz#6046b5c415ff7df7a0dc54c5b6b86098e8b952da"
dependencies:
@@ -8304,7 +9602,34 @@ webpack@^3.5.5:
webpack-sources "^1.0.1"
yargs "^8.0.2"
-websocket@^1.0.22:
+webpack@^3.10.0:
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.10.0.tgz#5291b875078cf2abf42bdd23afe3f8f96c17d725"
+ dependencies:
+ acorn "^5.0.0"
+ acorn-dynamic-import "^2.0.0"
+ ajv "^5.1.5"
+ ajv-keywords "^2.0.0"
+ async "^2.1.2"
+ enhanced-resolve "^3.4.0"
+ escope "^3.6.0"
+ interpret "^1.0.0"
+ json-loader "^0.5.4"
+ json5 "^0.5.1"
+ loader-runner "^2.3.0"
+ loader-utils "^1.1.0"
+ memory-fs "~0.4.1"
+ mkdirp "~0.5.0"
+ node-libs-browser "^2.0.0"
+ source-map "^0.5.3"
+ supports-color "^4.2.1"
+ tapable "^0.2.7"
+ uglifyjs-webpack-plugin "^0.4.6"
+ watchpack "^1.4.0"
+ webpack-sources "^1.0.1"
+ yargs "^8.0.2"
+
+websocket@1.0.24:
version "1.0.24"
resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.24.tgz#74903e75f2545b6b2e1de1425bc1c905917a1890"
dependencies:
@@ -8313,20 +9638,24 @@ websocket@^1.0.22:
typedarray-to-buffer "^3.1.2"
yaeti "^0.0.6"
-what-input@^4.0.3:
+what-input@^4.0.3, what-input@^4.1.3:
version "4.3.1"
resolved "https://registry.yarnpkg.com/what-input/-/what-input-4.3.1.tgz#b8ea7554ba1d9171887c4c6addf28185fec3d31d"
-whatwg-encoding@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4"
+whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3"
dependencies:
- iconv-lite "0.4.13"
+ iconv-lite "0.4.19"
-whatwg-fetch@>=0.10.0, whatwg-fetch@^0.11.1:
+whatwg-fetch@0.11.1:
version "0.11.1"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-0.11.1.tgz#6d3ded245fdd97cd728e0e2587b54b733949e663"
+whatwg-fetch@2.0.3, whatwg-fetch@>=0.10.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
+
whatwg-url@^4.3.0:
version "4.8.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.8.0.tgz#d2981aa9148c1e00a41c5a6131166ab4683bbcc0"
@@ -8334,6 +9663,14 @@ whatwg-url@^4.3.0:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"
+whatwg-url@^6.4.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.4.0.tgz#08fdf2b9e872783a7a1f6216260a1d66cc722e08"
+ dependencies:
+ lodash.sortby "^4.7.0"
+ tr46 "^1.0.0"
+ webidl-conversions "^4.0.1"
+
whet.extend@~0.9.9:
version "0.9.9"
resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1"
@@ -8346,9 +9683,9 @@ which-module@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
-which@1, which@1.2.x, which@^1.2.12, which@^1.2.9:
- version "1.2.14"
- resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
+which@1, which@^1.2.10, which@^1.2.12, which@^1.2.9, which@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
dependencies:
isexe "^2.0.0"
@@ -8389,6 +9726,21 @@ wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+wreck@^12.5.1:
+ version "12.5.1"
+ resolved "https://registry.yarnpkg.com/wreck/-/wreck-12.5.1.tgz#cd2ffce167449e1f0242ed9cf80552e20fb6902a"
+ dependencies:
+ boom "5.x.x"
+ hoek "4.x.x"
+
+write-file-atomic@^2.0.0, write-file-atomic@^2.1.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab"
+ dependencies:
+ graceful-fs "^4.1.11"
+ imurmurhash "^0.1.4"
+ signal-exit "^3.0.2"
+
write@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
@@ -8402,9 +9754,17 @@ ws@^2.3.1:
safe-buffer "~5.0.1"
ultron "~1.1.0"
-ws@^3.0.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/ws/-/ws-3.2.0.tgz#d5d3d6b11aff71e73f808f40cc69d52bb6d4a185"
+ws@^3.3.2:
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"
+ dependencies:
+ async-limiter "~1.0.0"
+ safe-buffer "~5.1.0"
+ ultron "~1.1.0"
+
+ws@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-4.0.0.tgz#bfe1da4c08eeb9780b986e0e4d10eccd7345999f"
dependencies:
async-limiter "~1.0.0"
safe-buffer "~5.1.0"
@@ -8414,15 +9774,27 @@ x-xss-protection@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/x-xss-protection/-/x-xss-protection-1.0.0.tgz#898afb93869b24661cf9c52f9ee8db8ed0764dd9"
+xdg-basedir@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
+
xml-name-validator@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
-xmldom@^0.1.22:
+xml-name-validator@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
+
+xmlbuilder@9.0.1:
+ version "9.0.1"
+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.1.tgz#91cd70897755363eba57c12ddeeab4a341a61f65"
+
+xmldom@0.1.27:
version "0.1.27"
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9"
-"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.1:
+xtend@^4.0.0, xtend@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
@@ -8450,6 +9822,29 @@ yargs-parser@^7.0.0:
dependencies:
camelcase "^4.1.0"
+yargs-parser@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950"
+ dependencies:
+ camelcase "^4.1.0"
+
+yargs@^10.0.3:
+ version "10.1.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5"
+ dependencies:
+ cliui "^4.0.0"
+ decamelize "^1.1.1"
+ find-up "^2.1.0"
+ get-caller-file "^1.0.1"
+ os-locale "^2.0.0"
+ require-directory "^2.1.1"
+ require-main-filename "^1.0.1"
+ set-blocking "^2.0.0"
+ string-width "^2.0.0"
+ which-module "^2.0.0"
+ y18n "^3.2.1"
+ yargs-parser "^8.1.0"
+
yargs@^7.0.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"
@@ -8468,7 +9863,7 @@ yargs@^7.0.0:
y18n "^3.2.1"
yargs-parser "^5.0.0"
-yargs@^8.0.1, yargs@^8.0.2:
+yargs@^8.0.2:
version "8.0.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360"
dependencies:
@@ -8486,6 +9881,24 @@ yargs@^8.0.1, yargs@^8.0.2:
y18n "^3.2.1"
yargs-parser "^7.0.0"
+yargs@^9.0.1:
+ version "9.0.1"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c"
+ dependencies:
+ camelcase "^4.1.0"
+ cliui "^3.2.0"
+ decamelize "^1.1.1"
+ get-caller-file "^1.0.1"
+ os-locale "^2.0.0"
+ read-pkg-up "^2.0.0"
+ require-directory "^2.1.1"
+ require-main-filename "^1.0.1"
+ set-blocking "^2.0.0"
+ string-width "^2.0.0"
+ which-module "^2.0.0"
+ y18n "^3.2.1"
+ yargs-parser "^7.0.0"
+
yargs@~3.10.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"