Retroid Pocket 3 review, comparison to Retroid Pocket 2+

After using the Retroid 3, I can create a fair, and unbiased review of the Retroid 3.

If you’re unfamiliar, the Retroid 1, and 2, were about as fast as needed to play Sega, NES, SNES, and Game Boy, and maybe a few others like GBA. With the release of the 2+ ($99) the ability to play PSP, Gamecube, PS2, and other newer consoles (especially full PS1 Support).

Abernic (They have devices ranging from $100-400 and the most powerful runs Windows 10 off of an nVME m2. SSD

, Odin, and many others exist, but in terms of fully featured, Google’s Android is still a fully functioning OS which when AOSP (Android Open Source Project) is used, it makes for a great time with the device.


  • $99 Retroid 2+
  • $129 Retroid 3 (3GB, there’s a 2GB model, we do not recommend)
  • Just released, so you’ve got a year at least before the Retroid 4, which will have native support for PS2, and Gamecube, as both are lacking on the 3
  • The devices both feel great, and just one will last the whole trip to North Carolina by car. Easily getting 8-20 hours depending on game, and use
  • Extra parts / controls / tools included, and very easy to open, and change


  • SAME INTERNALS (except an optional, and recommended bump in RAM)
  • Android 11 upgrade was needed, but more customization would be nice
  • Still sloppy to configure, and RetroArch basically dominates Android
  • No set backup software, so tranferring data from one device to the next is a pain, so I have to start over on the 3.
  • Still no full PS2 support, despite PCs running PS2 without a video card since 2014.
  • The RP2+ is MOST LIKELY getting the same update to Android 11, as they already did 8.1 to 9, and now 10 would give it internal audio recording feature.

Here comes the Retroid 3.

First we were hearing promises about a superior console, and let me say this, the new screen is widescreen, ruining the 4:3 aspect ALL games used from 1989-2004. So why Widescreen? Well with the newer Android, and the 3 GB of RAM, you can now stream PC games directly to the device (remember, it is a phone, it just happens to have controls, and only Wifi (they should release SIM version as well, but they want it to be retro, despite Netplay AND Retro Achievements both being available, which begs for at LEAST a basic 4G connection.

Retroid Pocket 3The thumbsticks are now true thumbsticks, before it was a good one, and a SLIDER stick, and now both can be clicked in for R3/L3

Screen, although no longer retro, is incredible. Device build is fantastic, and they give you extras in the box you’ll never see anywhere else.

If you need a ton of power, look for the Odin Pro ($350) or even Odin Lite ($200) to be able to run PS2, GC, and newer systems on your device.

No games included, but for $25 you can get a SANDISK ULTRA 256 GB which will hold 100 PS1 games, and every game for N64, NES, SNES, Genesis, 32x, and GB, GBC, and GBA etc

And still have memory for movies, music, as both have an included headphone jack.

Final Thoughts (use RP2+ for 4:3 Nostalgia in FFVII and BOF III, and use the 3 for some old, and a lot of new! But still old 😉

I personally use the Retroid 2 for games I NEED in the correct format, and the Retroid 3 to stream PC to handheld on Android very, very well. People get so mad at my kills, and you can even play Android apps like COD Android, and  you will destroy people using a touchscreen when you have 16+ buttons.

If you need the retro feel, get the 2+, and if you need newer Android or don’t mind black bars, stretching, etc, or need the minor upgrades, and better screen, go for the 3, but get the 3 GB one, as it plays much smoother especially for streams.

I give it 4 out of 5 stars. Taking 1 star only because it could have had upgraded internals.

How to create an ERC20 Token right now for use with NFTs and smart contracts


Ethereum network’s launch in 2015 created a lot of buzz in the developer community and sprouted a lot of tokens on the network. Initially there weren’t any templates or guidelines for token development. This resulted in a variety of tokens quite different from each other. To bring this diversity to order the community came up with an ERC-20 standard to make all tokens more or less uniform.

What is an ERC-20 token?

ERC stands for Ethereum Request for Comment, and 20 is the proposal identifier number. ERC-20 was designed to improve the ETH network.

ERC-20 is one of the most significant ERCs. It has emerged as the technical standard for writing smart contracts on the Ethereum blockchain network, used for token implementation. ERC-20 contains a set of rules that all Ethereum based tokens must follow.
ERC-20 defines tokens as blockchain-based assets that can be sent/received and have value. ERC-20 tokens are similar to Bitcoin and Litecoin in many aspects. However, the most significant difference is that instead of running on their own blockchain network, ERC-20 coins run on Ethereum’s blockchain network and use gas as the transaction fee.
Before the emergence of ERC-20, everyone who created tokens had to reinvent the wheel, which means all tokens were different from each other. For example, if a developer wanted to work with another token, they had to understand the entire smart contract code of that token due to the lack of any specific structure or guidelines for building new tokens. This was particularly painful for wallets and exchange platforms –  adding different types of tokens required developers to go through the code of each and every token and understand it in order to handle those tokens on their platforms. Needless to say, it was rather difficult to add new tokens to any app. Today wallets and exchanges use the ERC-20 standard to integrate various standardized tokens onto their platforms and also facilitate easy exchange between ERC-20 tokens and other tokens. The ERC-20 token standard has made interaction between tokens almost seamless and painless.
Token smart contracts are not only responsible for creating tokens but also for handling transactions and keeping track of the balances of each token holder. To get some tokens one has to send some ETH to the token’s contract in return for allocated tokens.
ERC-20 is a standard or guideline for creating new tokens. The standard defines six mandatory functions that a smart contract should implement and three optional ones.
To start you can give your token a name, a symbol, and mention how dividable your token is, by specifying the decimals. ERC specifies a set of mandatory functions, which are a bit more complex and listed below:
  • totalSupply: A method that defines the total supply of your tokens, When this limit is reached the smart contract will refuse to create new tokens.
  • balanceOf: A method that returns the number of tokens a wallet address has.
  • transfer: A method that takes a certain amount of tokens from the total supply and gives it to a user.
  • transferFrom: Another type of transfer method which is used to transfer tokens between users.
  • approve: This method verifies whether a smart contract is allowed to allocate a certain amount of tokens to a user, considering the total supply.
  • allowance: This method is exactly the same as the approved method except that it checks if one user has enough balance to send a certain amount of tokens to another.
If you know something about Object Oriented programming you can compare ERC-20 to an Interface. If you want your token to be an ERC-20 token, you have to implement the ERC-20 interface and that forces you to implement these 6 methods.

Creating our own token.

Now that we know what ERC-20 tokens are and how they work, let’s see how we can build and deploy our own token.
We’ll deploy our contract on the Ropsten testnet. To get started, you will need the Metamask browser extension to create an ETH wallet and some test ETH, which you can get by going to the Ropsten faucet. You’ll need to select Ropsten Test Network on your Metamask wallet and copy-paste the wallet address into the text field in the faucet, then click Send me test Ether.
Head over to the Ethereum Remix IDE and make a new Solidity file, for example – token.sol
Paste the following code into your new Solidity script:

Replace the symbol and name with your own:
62 symbol = “QKC“;
63 name = “QuikNode Coin“;
set the decimal (value in which tokens can be divided, 0to8 decimal units can be used) and establish a total supply value as you wish:
64 decimals = 2;
65 _totalSupply = 100000;
Please change YOUR_METAMASK_WALLET_ADDRESS to your own wallet address (same wallet you specified to obtain test currency):
66 balances[YOUR_METAMASK_WALLET_ADDRESS] = _totalSupply;
67 emit Transfer(address(0), YOUR_METAMASK_WALLET_ADDRESS, _totalSupply);

Note: The total supply value must have additional trailing zeros as specified by the decimals field. For example, the decimals value in this contract is 2 and we need a total supply of 1000 tokens, so we’ll have to set the total supply variable to 100000 (simply because it won’t allow a decimal point).

Explanation of the code above:
Line 1: Declaring the solidity version
Line 3-4: Calling the Safe Math interface to use math functions in our contract.
Line 29-41: Calling the ERC-20 Interface to implement its functions.
Line 44-48: A Contract function to receive approval and execute a function in one call.
Line 52-56: Starting our QKCToken contract, creating a variable symbol of string type to hold our token’s symbol, a variable name of string type to hold our token’s name, variable decimals of unsigned integer type to hold the decimal value for the token division.
Line 58-59: Creating two mapping functions that will grant users the ability to spend these tokens.
Line 61-68: Initializing the constructor, setting symbol, name, decimals, and total supply value for our token. Declaring the total supply of the token to be equal to your wallet’s balance for this token.
Line 70-72: Function totalSupply which will govern the total supply of our token.
Line 74-76: Function balanceOf which will check the balance of a wallet address.
Line 78-83: Function transfer which will execute the transfer of tokens from the total supply to users.
Line 85-89: Function approve which will check if the total supply has the amount of token which needs to be allocated to a user.
Line 91-97: Function transferFrom which will facilitate the transfer of token between users.
Line 99-101: Function allowance which will check if a user has enough balance to perform the transfer to another user.
Line 103-108: Function approveAndCall which executes the transactions of buying and spending of tokens.
Line 110-112: Fallback function to prevent accounts from directly sending ETH to the contract, this prevents the users from spending gas on transactions in which they forget to mention the function name.
Compile the smart-contract and deploy it using injected Web3 (make sure to select Ropsten testnet on Metamask before compiling the contract). Approve the transaction from metamask.

Note: We need to deploy the main token contract, select the name of the contract appropriately under the contracts section before deploying the contract (QKCToken here).

If you receive an error message before deployment “This contract may be abstract”, make sure to select the appropriate contract under the Contract tab. Confirm the transaction in Metamask:

Screenshot of Metamask transaction confirmation
That’s it! your token contract is now deployed on Ethereum’s Ropsten testnet!
To get the token in Metamask, go to the “Deployed Contracts” section in Remix and copy the deployed contract’s address using the copy button near the contract’s name.
Open Metamask and click on the Add Token button, select the Custom Token option and paste the contract’s address in the first field. Metamask will fetch the Token Symbol and decimals automatically.
Click on next and your token will be added to the wallet, it will be available under the assets section in Metamask.


Congratulations on successfully creating your very own token/coin on the Ethereum network! Read more about the ERC-20 standard here.

How to implement staking into your NFT smart contract in a few easy steps

Introduction to staking

Someone is said to have a stake in a venture when they contribute some assets in exchange of exercising some level of control, influence, or participation in its activities.

In the cryptocurrency world this is understood as giving users some kind of right or reward for as long as they don’t transfer some tokens in their possession. A staking mechanism usually encourages token holding against token trading, which in turn is expected to drive up the token valuation.

At Sean Frohman we believe that knowledge exists to be shared, and in this article we are going to show how to implement a staking mechanism in solidity. The whole project including development environment and tests is available on public github.

To build this staking mechanism we will need:

  1. A staking token.
  2. Data structures to keep track of stakes, stakeholders and rewards.
  3. Methods to create and remove stakes.
  4. A rewards system.

Let’s get on with it.

Staking Token

A staking token can be created as an ERC20 token. I’m going to need SafeMath and Ownable later on, so let’s import and use those as well.

pragma solidity ^0.5.0;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";

* @title Staking Token (STK)
* @author Alberto Cuesta Canada
* @notice Implements a basic ERC20 staking token with incentive distribution.
contract StakingToken is ERC20, Ownable {
   using SafeMath for uint256;

    * @notice The constructor for the Staking Token.
    * @param _owner The address to receive all tokens on construction.
    * @param _supply The amount of tokens to mint on construction.
   constructor(address _owner, uint256 _supply)
       _mint(_owner, _supply);

That’s it, nothing else is required.


In this implementation we are going to keep track of the stakeholders to facilitate a robust distribution of incentives later on. In theory it would be possible to not keep track of them as a normal ERC20 token would do, but in practice it is difficult to ensure that stakeholders don’t game the distribution system if you don’t track them.

For implementation we will just use a dynamic array of stakeholder addresses.

     * @notice We usually require to know who are all the stakeholders.
    address[] internal stakeholders;

The following methods add a stakeholder, remove a stakeholder, and verify whether an address belongs to a stakeholder. Other more efficient implementations are surely possible but I like this one for readability.

    * @notice A method to check if an address is a stakeholder.
    * @param _address The address to verify.
    * @return bool, uint256 Whether the address is a stakeholder,
    * and if so its position in the stakeholders array.
   function isStakeholder(address _address)
       returns(bool, uint256)
       for (uint256 s = 0; s < stakeholders.length; s += 1){
           if (_address == stakeholders[s]) return (true, s);
       return (false, 0);

    * @notice A method to add a stakeholder.
    * @param _stakeholder The stakeholder to add.
   function addStakeholder(address _stakeholder)
       (bool _isStakeholder, ) = isStakeholder(_stakeholder);
       if(!_isStakeholder) stakeholders.push(_stakeholder);

    * @notice A method to remove a stakeholder.
    * @param _stakeholder The stakeholder to remove.
   function removeStakeholder(address _stakeholder)
       (bool _isStakeholder, uint256 s) = isStakeholder(_stakeholder);
           stakeholders[s] = stakeholders[stakeholders.length - 1];


A stake at its simplest form will need to record the stake size and the stake holder. A really simple implementation of this could be just a mapping from the address of the stakeholder to the stake size.

    * @notice The stakes for each stakeholder.
   mapping(address => uint256) internal stakes;

I’m going to follow the function names from ERC20 and create equivalents to get the data from the stakes mapping.

    * @notice A method to retrieve the stake for a stakeholder.
    * @param _stakeholder The stakeholder to retrieve the stake for.
    * @return uint256 The amount of wei staked.
   function stakeOf(address _stakeholder)
       return stakes[_stakeholder];

    * @notice A method to the aggregated stakes from all stakeholders.
    * @return uint256 The aggregated stakes from all stakeholders.
   function totalStakes()
       uint256 _totalStakes = 0;
       for (uint256 s = 0; s < stakeholders.length; s += 1){
           _totalStakes = _totalStakes.add(stakes[stakeholders[s]]);
       return _totalStakes;

We are now going to give STK holders the capability to create and remove stakes. We will burn the tokens as they are staked to stop users from transferring them until the stake is removed.

Please note that on stake creation _burn will revert if the user tries to stake more tokens than he owns, and on stake removal the update of the stakes mapping will revert if there is an attempt to remove more tokens that were staked.

Finally, we use addStakeholder and removeStakeholder to have a record of who has stakes, to be used later in the rewards system.

    * @notice A method for a stakeholder to create a stake.
    * @param _stake The size of the stake to be created.
   function createStake(uint256 _stake)
       _burn(msg.sender, _stake);
       if(stakes[msg.sender] == 0) addStakeholder(msg.sender);
       stakes[msg.sender] = stakes[msg.sender].add(_stake);

    * @notice A method for a stakeholder to remove a stake.
    * @param _stake The size of the stake to be removed.
   function removeStake(uint256 _stake)
       stakes[msg.sender] = stakes[msg.sender].sub(_stake);
       if(stakes[msg.sender] == 0) removeStakeholder(msg.sender);
       _mint(msg.sender, _stake);


Rewards mechanisms can have many different implementations and be quite heavy to run. For this contract we will implement a very simple version where the stakeholders periodically receive a reward in STK tokens equivalent to a 1% of their individual stakes.

In more sophisticated contracts the distribution of rewards would be automatically triggered when certain conditions are met, but in this case we will let the owner trigger it manually. Following best practice we will also keep track of the rewards and implement a method to withdraw them.

As before, to make the code readable we have followed the naming conventions from the ERC20.sol contract, first the data structure and data management methods:

    * @notice The accumulated rewards for each stakeholder.
   mapping(address => uint256) internal rewards;
    * @notice A method to allow a stakeholder to check his rewards.
    * @param _stakeholder The stakeholder to check rewards for.
   function rewardOf(address _stakeholder)
       return rewards[_stakeholder];

    * @notice A method to the aggregated rewards from all stakeholders.
    * @return uint256 The aggregated rewards from all stakeholders.
   function totalRewards()
       uint256 _totalRewards = 0;
       for (uint256 s = 0; s < stakeholders.length; s += 1){
           _totalRewards = _totalRewards.add(rewards[stakeholders[s]]);
       return _totalRewards;

Next are the methods to calculate, distribute and withdraw rewards:

    * @notice A simple method that calculates the rewards for each stakeholder.
    * @param _stakeholder The stakeholder to calculate rewards for.
   function calculateReward(address _stakeholder)
       return stakes[_stakeholder] / 100;

    * @notice A method to distribute rewards to all stakeholders.
   function distributeRewards()
       for (uint256 s = 0; s < stakeholders.length; s += 1){
           address stakeholder = stakeholders[s];
           uint256 reward = calculateReward(stakeholder);
           rewards[stakeholder] = rewards[stakeholder].add(reward);

    * @notice A method to allow a stakeholder to withdraw his rewards.
   function withdrawReward()
       uint256 reward = rewards[msg.sender];
       rewards[msg.sender] = 0;
       _mint(msg.sender, reward);


No contract can be complete without a comprehensive set of tests. I tend to produce a bug per function at least, and often things don’t work the way I think they do. You could say I get things wrong most of the time, and surely I’m not alone in this.

Apart from allowing you to produce code that works, tests also are quite useful in developing a process to set up and use contracts. I always write my Getting Started documentation from the code that sets up the environment for the tests.

Follows an extract of how the test environment is set up and used. We will mint 1000 STK tokens and give them to a user to play with the system. We use truffle for testing which gives us the accounts to use.

contract('StakingToken', (accounts) => {
   let stakingToken;
   const manyTokens = BigNumber(10).pow(18).multipliedBy(1000);
   const owner = accounts[0];
   const user = accounts[1];

   before(async () => {
       stakingToken = await StakingToken.deployed();

   describe('Staking', () => {
       beforeEach(async () => {
           stakingToken = await

When creating tests I always write the tests that make the code revert, but those are not very interesting to see. The test for createStake shows what needs to be done to create a stake, and what should change afterwards.

It is important to notice how in this staking contract we have two parallel data structures, one for STK balances and one for stakes and how their sum remains constant through stake creation and removal. In this example we give 3 STK wei to the user, and the sum of balance plus stakes for that user will always be 3.

       it('createStake creates a stake.', async () => {
           await stakingToken.transfer(user, 3, { from: owner });
           await stakingToken.createStake(1, { from: user });

           assert.equal(await stakingToken.balanceOf(user), 2);
           assert.equal(await stakingToken.stakeOf(user), 1);
               await stakingToken.totalSupply(), 
           assert.equal(await stakingToken.totalStakes(), 1);

For rewards, the test below shows how the owner fires up the distribution of fees, with the user getting a reward of a 1% of his stake.

       it('rewards are distributed.', async () => {
           await stakingToken.transfer(user, 100, { from: owner });
           await stakingToken.createStake(100, { from: user });
           await stakingToken.distributeRewards({ from: owner });
           assert.equal(await stakingToken.rewardOf(user), 1);
           assert.equal(await stakingToken.totalRewards(), 1);

The total supply for STK is increased when rewards are distributed, and this test shows how the three data structures (balances, stakes and rewards) relate to each other. The amount of existing and promised STK will always be the amount minted on creation plus the amount distributed in rewards, which might or might not be minted. The amount of STK minted on creation will be equal to the sum of balances and stakes until a distribution is done.

       it('rewards can be withdrawn.', async () => {
           await stakingToken.transfer(user, 100, { from: owner });
           await stakingToken.createStake(100, { from: user });
           await stakingToken.distributeRewards({ from: owner });
           await stakingToken.withdrawReward({ from: user });
           const initialSupply = manyTokens;
           const existingStakes = 100;
           const mintedAndWithdrawn = 1;

           assert.equal(await stakingToken.balanceOf(user), 1);
           assert.equal(await stakingToken.stakeOf(user), 100);
           assert.equal(await stakingToken.rewardOf(user), 0);
               await stakingToken.totalSupply(),
           assert.equal(await stakingToken.totalStakes(), 100);
           assert.equal(await stakingToken.totalRewards(), 0);


A staking and rewards mechanism is a powerful incentive tool that only needs to be as complex as we want to make it. The methods provided in the ERC20 standard and SafeMath allows us to code it in about 200 lines of sparse code.

Contact Me if you need me to do it, or more info!

Tech Round Up August 20th 2021 – OnlyFans changes and lies,


OnlyFans now no longer allows “explicit adult content” whatever that may mean? Here’s the official statement, and here it is in plain text, as some prefer.

A few recent article titles to get you up to speed on the backlash:

“Sex workers who earn thousands on OnlyFans say it’s unclear how the company will enforce its ‘disgusting’ porn ban — and some may leave the platform because of it”

“OnlyFans bans sexually explicit content to appease banks and payment services”

(Also, entirely not in the news, and actually VERY SUSPICIOUSLY HIDDEN MOSTLY OnlyFans is launching a YouTube of their own, with NO PLANS TO MONETIZE, and NO ADS? What the FUCK is going on over there? We are being destroyed with ads, and most of the battle is trying to decide how much of your life to want to sign away when the iPhone turns on and you click agree, or you have to stop sites from tracking you SO MUCH that it’s built into the OS now, pissing off Facebook, which relies on selling ALL of your data, movements, voice, friends list, to make more money. Now this ad free monetize free service comes from an established company with their own server farms, with the ability to destroy Vimeo and other’s already being destroyed by Twitch which comes at a great time, and may buffer some of the fall  explain below, check that out here [no spam, no ads], but back on topic…

So no more SEXUALLY EXPLICIT MATERIAL? What does that mean? No one knows. Not even OnlyFans I suspect.

Ok, so we know sex, masturbation, and probably sucking a dildo are all out, both in video, and picture form, and we know that regular nude, burlesque, and what most people would call ‘tasteful’ like Michelangelo’s David will be allowed. Unfortunately this is a dizaster for everyone, including non nude models, and content creators all over the world, and of every kind. I like to get to the point:

OnlyFans was specifically founded, and succeeded on nudity, and pornography. Playboy tried to get rid of nudity once, and the magazine fell entirely to 0 new subscribers and losing from their larger base, by almost 80% and I think that’s due to the fact that they reversed SO QUICKLY. Had they given it a year, I’m sure re-subscribers would have fallen to almost non existent as well. Playboy has never been about the tits, and always into the tits at the same time. People could get “better” cheaper smut with much dirtier camera angles, and 100 pics per magazine instead of 20 just by moving 2 magazines over to Penthouse, or Hustler.

However simple, and however “lacking” Playboy was, that brief bit of nudity, and the nostalgia of “finding dad’s old Playboys” come back to mental images of an area where 5-10 magazines from the basement were a fun hiding spot time to be away from parents. It has a feeling, a moment, a smell of the pages, and the inevitable CENTERFOLD of a girl who was 50% real girl size in 3 bent panels for you to view, in all her basic nude glory, without a single distasteful image, and that’s almost OBJECTIVELY spoken.

You probably see where I am going with this. OnlyFans has been here 5 years, since 2021.

[IC Media Direct] – Reputation Management Service – Links and Reviews Removal – }Sean’s True Review]

IC MEDIA DIRECT REVIEW 2021I needed some help with dealing with some negative review in Google, and I had heard about ICMediaDIrect. About 5 years ago, I hired them to help me handle it, and they have not only ruined the work I had put it, but they did weird, unnecessary things like submitting weird Google forms it looks like to trick Google into thinking something else (which works, but I don’t do it, I am better than that. So I gave them about 6 months before I collected my data, and I can safely say I paid over $10,000 for the service that proHow-to-Remove-Google-Reviews-–-Is-it-Possible_-Copy@3x-2048x1195vided little to no help with my situation.

Founded in what looks to be 2002 if the domain registration is any sign of it. They look very professional, the video is custom, and the pricing is indicative of having the skills of someone or a group of people who are serious about getting links in Google “removed’ so to speak.

Even further so, they say they DO NOT remove links, and that’s because anyone who DOES remove links, is LYING. Google rule  #22 : IF it’s the the internet, we can index if, and if you want it down, take it off the internet. Otherwise fuck off.

Aanyway, I was elated to see they offered a service to help me with Google ad after speaking with them. They did not help, and cost me a lot.

Also, I don’t think they knew they were dealing with a Slackware age hacker, from back when we were bored enough to hack ANYTHING with fear of going to jail, in 1998-2003.remove-bad-google-reviews

I hired them again, much more than $10,000 this time, and they were to remove 2 links at the tippity top, and move them off of page 1.

6 months, and over $20,000 later, I can safely say this company is worth 1 out of 5 stars. Some technical expertise, but not much. This is why I want people to compare my competitors. I am obviously advertising a bit here, but let’s be honest. I’ll find some company, and keep evaluating their skills, so you don’t have to.


Disclaimer I cannot be paid for good or bad reviews, this is a hobby I started when I realized people needed it. 🙂