___|  _ \   |  |    |   |_ _|\ \     / ____|
 |     |   |  |  |    |   |  |  \ \   /  __|
 |   | |   | ___ __|  ___ |  |   \ \ /   |
\____|\___/     _|   _|  _|___|   \_/   _____| 

 --- A GOPHER-LIKE INTERFACE FOR HIVE BLOCKCHAIN ---

HiveStats: Developer's Insight

BY: @yokunjon | CREATED: Feb. 12, 2022, 5:55 a.m. | VOTES: 263 | PAYOUT: $183.58 | [ VOTE ]

HiveStats: Developer's Insight

[IMAGE: https://images.hive.blog/DQmUiVWhPMVaUd8SWaezvkTPMztFwcUNeXMfYz6KDSBcM3Q/image.png]

Introduction

As I do reply to some of the posts about HiveStats, you might already know that I'm the developer who is working on it, on behalf of LeoFinance. It might feel like I'm trying to steal their credit and trying to shout out to the whole universe about it; I do also feel a little like so, not going to lie. But, frankly, I'm rather a bit excited about it, that's all the reason. I was eager to do a project on Hive and working on HiveStats allowed me that even though it isn't my project. I'm excited because lots of people use it, and give feedback about it. I try to engage, fix bugs as quickly as possible to keep the illusion as if it is imperfect. So, in summary, this is the way I'm fighting my anxiety back.

I do love talking about programming concepts, I sometimes talk all day long. I did write up two posts about it last year, in the hopes of getting some engagement. While they got some votes from curation accounts, I got no reply, which discouraged me from writing any further posts. It could be because maybe my content wasn't up to the standards, or it was too abstract. Fast forward to 2022 and I now have the experience of developing an already existing app from scratch, which is less abstract and more practical, and popular, of course. So, allow me to share my shortcomings, struggles and solutions to those, so to call my experience, while developing HiveStats. I do apologize to all of you for my brashness for using this HiveStats popularity as an opportunity.

Lack of Documentation

[IMAGE: https://images.hive.blog/DQmb1evof3FCZwLRm76VhhBNyRiPQkG2McWC88R1cnzfyrq/image.png]
(searching what rshare means and its denominator)

I struggled with documentation the most, this was the most time-consuming issue by far. Documentation on Hive API methods was ok, but I can't say the same for the formulas and terms. To overcome it, I scraped example applications in the documentation, checked open-source projects that I know of, read lots of old discord messages. My Hive Engine experience was also similar.

I do plan to develop a handbook kind of website with search functionality due to this, to help other people like me.

Account History

[IMAGE: https://images.hive.blog/DQmRJos517z5dJdH1tyUVvLDrcH1XFj36ZYUWEQRmFECq5d/image.png]
(showing partly loaded analytics)

Most of the stuff is calculated through parsing accounts' operations over time. For inactive account's like mine, it is just a simple call; but for people like @taskmaster4450, it gets dirty pretty quick. The thing is, reading the history is limited to 1000 items per request. There isn't a way of reading a week of history or month, so results of requests are read to figure out if it's past a month or not. Using that way, getting 50 history requests becomes sync as each request depends on another.

It was an issue of the old iteration of HiveStats, which I did solve in the V3 update. I did also improve upon it in the current iteration. The trick is making them partly async. Without boring details, I do predict how many requests it would take by using the first several requests. Later, I fetch them in batches. If they overshoot, I filter, if not, batch again. That way, it becomes several sync requests of async rather than all sync.

Curation Rewards and Operations

[IMAGE: https://images.hive.blog/DQmcSNtQ13gJTeD9Dez5YHwco28dPceD82YQ9iiLyoNgjuh/chrome_2022-02-12_08-31-05.gif]
(scrolling through 1657 rows)

Visualizing lots of data without combining them into something, like a chart is demanding. Rendering several thousands of complex elements as rows of a table takes time. Updating it on the go several hundred times makes the framerate unstable. It doesn't matter how fast it is fetched or parsed, if it feels sluggish, that's a bad UX. I did solve this by using a technique called windowing. So, rendering only the parts user is currently seeing, and reusing old elements in the process. While doing that, simulating scroll behaviour and memoizing heavy renders is also crucial. That way, it creates an illusion of lots of items, in reality, showing only a dozen of them.

Mobile Support

[IMAGE: https://images.hive.blog/DQmWQYvDZ1dq3unw3s9f8mv4u5GTMgVjiLWUR9wmS7z4b61/chrome_2022-02-12_08-34-11.gif]
(simulating narrower screen view)

Mobile support is hard, making tables mobile friendly is harder. I struggle a lot to fit every bit of information on the tables, without horizontal scrolling. I did reduce the font size, used abbreviations, cut most of the title on lower screens to fit everything. While the execution was easy, it took lots of time to test and figure perfect values.

Making it Feel Reactive

[IMAGE: https://images.hive.blog/DQmYKLSmC1yRgREz7Gkkgv76qGQToNCrMwd2QGQwyZX5imq/chrome_2022-02-12_08-36-17.gif]
(fetching post data while updating the table)

As I said in a previous paragraph, if a UI feels sluggish, that's a bad UX. In the frontend world, the most important thing is controlling how a user feels. Websites with more features might get lower traffic due to how they act to the user's actions and vice-versa. For HiveStats, unlike other sites, loading an account is the most important action of the user, so making it reactive was necessary. The difference between V3 and V4 is not much in terms of raw speed, but as the latter feels more reactive and updates constantly, it makes the user focus on updated data rather than waiting for it. That way, it cheats badly, creates the illusion of being far faster. That's the power of UX. React's one-way data flow and using memoization was crucial in this process.

Important Techs/Libraries I Used

So, hope you like it. I tried to not be boring while providing enough data and making it a quick read. If you have any questions, I am happy to reply to all of them. See you later, thanks for tuning in!

Posted Using LeoFinance Beta

TAGS: [ #hivestats ] [ #development ] [ #devblog ] [ #react ] [ #javascript ] [ #proofofbrain ] [ #neoxian ] [ #leofinance ]

Replies

@niallon11 | Feb. 12, 2022, 6:24 a.m. | Votes: 3 | [ VOTE ]

>I did write up two posts about it last year, in the hopes of getting some engagement. While they got some votes from curation accounts, I got no reply.

That's a shame as the work that you have done here is amazing and deserves recognition. There are a few people that i follow who put up similar post about development and programming but it does go above my head.

Without any knowledge of programming all i can do is appreciate the final result and hive stats is an amazing piece of work.

So well laid out, so reactive, so useful. Congrats on the achievement and its worth a little brag when you hit a winner.

I know from other teams that have tried building projects that it can be tough to develop on hive as there is not as much support documentation compared to the likes of Ethereum. Will this be made easier with the upcoming HAF project form blocktrades or do we need people to take the time and put together the content for others to use?

Posted Using LeoFinance Beta

@yokunjon | Feb. 12, 2022, 7:18 a.m. | Votes: 2 | [ VOTE ]

Thank you so much!
> There are a few people that i follow who put up similar post about development and programming but it does go above my head.

I'd like to follow them if you remember their names.

> I know from other teams that have tried building projects that it can be tough to develop on the hive as there is not as much support documentation compared to the likes of Ethereum.

I never worked with Ethereum, though I believe there should be lots of volunteer work on documenting things due to its popularity. Contrary to that, Hive requires you to know someone who already knows about it. It would be much harder for me without me asking my friend every day about the Hive.

> Will this be made easier with the upcoming HAF project form blocktrades or do we need people to take the time and put together the content for others to use?

The only thing that I know that's related to HAF is history revamp. So, I can only guess that documenting the new and easier to use API be easier on their end too.

@jfang003 | Feb. 12, 2022, 7:26 a.m. | Votes: 3 | [ VOTE ]

It sounds like these are probably issues most people writing up the UI will probably face when dealing with blockchain data (you can't avoid reading the history). Have you thought of writing up some documentation on the stuff you did use for other people? Maybe just a few blog posts here and there might be able to help people and later someone can put them up together for everyone else.

Posted Using LeoFinance Beta

@yokunjon | Feb. 13, 2022, 2:03 a.m. | Votes: 1 | [ VOTE ]

Yes, definitely. I did mention it as "handbook", in one of the chapters. I do really think of doing that kind of, easy-to-reach documentation. 😁

@blocktrades | Feb. 12, 2022, 11:12 p.m. | Votes: 0 | [ VOTE ]

At some point it would probably make sense to look into changing this into a HAF app. That would have eliminated all the issues you had with account history fetches and batching, because you would have a database that you could create custom queries on. It does come with storage costs, of course (unless you get someone to host the HAF server for you and run your app there).

@yokunjon | Feb. 13, 2022, 2:01 a.m. | Votes: 0 | [ VOTE ]

I was thinking of using the browser's local storage to cache data to reduce the burden on the nodes, before seeing HAF. Though, I do have a bigger issue going on right now. Each pending curation reward is calculated by using get_content, so that equals thousands of calls to the node. I guess HAF also could solve that, right?

@blocktrades | Feb. 13, 2022, 4:21 a.m. | Votes: 1 | [ VOTE ]

Yes, you would be able to create your own API calls, so you could create a single call that met your needs. If your app is already dependent on a lot of hivemind-based API calls, one option would be to use the HAF-based hivemind that we'll be releasing soon, then adding your own custom call support to that.

@hironakamura | Feb. 13, 2022, 6:38 a.m. | Votes: 0 | [ VOTE ]

Yeah! , but I see the team is working tirelessly to put out a better product. But I feel at first trial they did a good job and as time progresses they will definitely improve. Are you a programmer mate? Mehn your post was mind blowing.

Posted using LeoFinance Mobile

@yokunjon | Feb. 13, 2022, 7:29 a.m. | Votes: 0 | [ VOTE ]

Yeah, I'm a programmer, though I prefer the title "software engineer" as my skillset is generic. I'm not sure but it looks like there is a misunderstanding going on. I believe you mistook this as a review, but it is actually a devblog! πŸ˜…

@hironakamura | Feb. 13, 2022, 7:54 a.m. | Votes: 0 | [ VOTE ]

Oh, thanks for the clarity!

@finguru | Feb. 13, 2022, 1:31 p.m. | Votes: 1 | [ VOTE ]

You did a great job mate. Love the new Hivestats. Now I can easily have a good look at my hive portfolio, all in one place.πŸ”₯

Posted Using LeoFinance Beta

@klevn | Feb. 15, 2022, 4:52 a.m. | Votes: 0 | [ VOTE ]

Hello, i found this most interesting. I am working to create a small TCL library that works with the ap.hive.blog .. I have figured much out.. but like you have run into many problems with the documentation being less than complete, or rather lacking in details that would help you understand what is happening.

What I hope you can help me with is a figuring out what is the estimated curation rewards on votes given.

I've found so many values, but can't find the formula for this.

@yokunjon | Feb. 15, 2022, 2:14 p.m. | Votes: 1 | [ VOTE ]

It requires multiple calculations (at least it is how I seperate them from eachother), so it would be hard to explain it here. Do you have Discord? You can add me over there: Belial#6132

If not, no worries, we can communicate in other ways. Though I'm going to sleep soon, so I'll be away for 10 hours πŸ˜„.

@klevn | Feb. 15, 2022, 11:47 p.m. | Votes: 0 | [ VOTE ]

i have not been on discord. let me set a level of understanding. hopefully you can decode this.

I have gotten the majority of the values below. I have not found what the 'weight' is .. it is not actually found on this page, however is used in the formula.

total_vests = vesting_shares + received_vesting_shares - delegated_vesting_shares
final_vest = total_vests * 1e6
power = (voting_power * weight / 10000) / 50
rshares = power * final_vest / 10000
estimate = rshares / recent_claims * reward_balance * hbd_median_price

I found this and tried to follow and find the values it used...

curation reward estimation tool appears to be helpful..

The Details

For those of you who are interested, the calculations work as follows:

let [before] = the value of votes before the specified account voted
let [vote] = the value of the specified account's vote
let [total] = the total payout value of the post (as specified using the slider bar)
let [reverse_auction_%] = the portion of your curation rewards that will go to the author if you voted before the post was 30 minutes old

Each of the above amounts is multiplied by 25% since that is the amount of rewards that go to curation. Then the curation value can be calculated by:

(√([before] + [vote]) - √([before])) * √([total]) * (1 - [reverse_auction_%])

i have not found reverse_auction_% yet.

my understanding is, I need to total the value of all the votes on the post.. as the post total value affects how much you get depending upon when you voted.

so estimating it implies guessing how much the post value would be, or leaving it as is and estimating it as if it received no more upvotes (which is what I planned to do, not actually ignoring the other option just not having thought about how to do it yet)

this is result from my code, with a effective_comment_vote that I think holds the part of the key

op = effective_comment_vote {voter klevn author leny28 permlink flor-aspilia-africana-african-aspilia-flower weight 54948050199 rshares 54948050199 total_vote_weight 110142200252 pending_payout {0.148 HBD}}

and here are the values I've pulled that I thought would be used to calculate this

voteValues>>
   reward_balance:755637.683
   recentClaims:600562913345957605
   base:1.049
>>

accountInfo>>[klevn]
   vesting_shares:3109480.378777 
   received_vesting_shares:3109480.378777 
   delegated_vesting_shares:0.000000 
   voting_power'current:97.75

it appears to me the best I could do it search on the post for the most recent upvote

from there I pull the pending_payout {0.148 HBD}} (which will have changed.. i think) along with the other values there.. are used to calculate it.

thanks for any/all help. appreciated so much . I hope I have been clear. I am working to wrap my mind around the concepts used.

a side note (in regards to documentation not being good) .. but this threw me for a loop..

condenser_api.get_account_history

"alice" -1 1000 Queries the account named alice starting on the oldest item in history, up to 1,000 results.

it says oldest item in history. it is actually the newest item in history. because I was so new I thought I must be thinking wrong, but no .. well maybe you can explain it. but i think it is wrong.

@yokunjon | Feb. 16, 2022, 6:23 a.m. | Votes: 2 | [ VOTE ]

> I have gotten the majority of the values below. I have not found what the 'weight' is .. it is not actually found on this page, however is used in the formula.

This one is estimated upvote/vote value calculation. Weight is voting mana ratio (out of 10000, not percentage), so it calculates user's vote value rather than post's. Hope it is clear! Don't hesitate to ask further if not.

> i have not found reverse_auction_% yet.

It is probably an old way of calculating it, I don't know about it.

> my understanding is, I need to total the value of all the votes on the post.. as the post total value affects how much you get depending upon when you voted.

so estimating it implies guessing how much the post value would be

Exactly!

Rest about curation is not correct, I'll provide the details.

> it says oldest item in history. it is actually the newest item in history.

I did also struggle with several wording there, one of was that. What it means is, data it returns is sorted oldest to newest. So, imagine getting last 50 history of an account. The array it returns is sorted from the oldest, so if the latest operation was with index 24424, that would be the last index of the array. So, it is reverse than what you expect. This isn't true for HiveEngine for example, if you ever go into that route!

Now, about curation rewards. I'll provide examples as pseudocode:

You'll need these methods and fields:
- get_current_median_history_price -> base // median price of Hive/HBD
- get_reward_fund-> percent_curation_reward // curation reward ratio (50/50 as of now)
- get_content -> pending_payout_value, max_accepted_payout, total_vote_weight, active_votes

You do need to calculate post rewards first:

function post_reward(median_price, pending_payout_value, max_accepted_payout) {
  // We do only use max allowed value (read about min function if this looks nonsense)
  // I don't know where max_accepted_payout is used, it could be declined rewards.
  let payout = min(pending_payout_value, max_accepted_payout);

  // We do convert Hive to HBD as pending_payout_value is Hive.
  return payout / median_price;
}

Next, you need to calculate how much of this is curation reward:

function curation_reward(post_reward, percent_curation_rewards) {
  // percent_curation_rewards is a ratio. I'm not native and don't know
  // how I can describe it, but it is like 24/100, but scaled up to 10000
  // so like 2400/10000. percent_curation_rewards is the 2400 part of it
  // They do use 10k instead of normalized value, probably for precision reasons.
  if (post_reward == 0) {
    // If we don't this, it could return NaN in rare cases.
    return 0;
  }

  // 1000 is denominator here, used for precision calc.
  let hive = post_reward * 1000;
  // we do multiply high precision high value by percent, later floor it to cut out
  // possible unnecessary precision bits. later divide it by 10000. I described
  // reason at top.
  let curation_reward = floor(hive * percent_curation_rewards) / 10000;

  // As we don't need to make calculations over this, we can divide it back.
  return curation_reward / 1000;  
}

Now, we can calculate the vote reward:

function vote_reward(curation_reward, total_vote_weight, weight) {
  // Self explanatory I believe
  let ratio = curation_reward * 1000 * weight / total_vote_weight;
  // Making sure negative values result in 0 (due to downvotes). Then floor and denom
  // as like above.
  return floor(max(0, ratio) / 1000);
}

Ta da, now you have curation reward as Hive/HP. You can combine these into one function and reduce the amount of denom operations you do. So it could be like this:

function curation_reward(
  median_price,
  pending_payout_value,
  max_accepted_payout
  percent_curation_rewards,
  total_vote_weight
  weight
) {
  let payout = min(pending_payout_value, max_accepted_payout);
  let post_reward = payout / median_price;

  if (post_reward == 0) {
    return 0;
  }

  let hive = post_reward * 1000;
  let curation_reward = floor(hive * percent_curation_rewards) / 10000;

  let ratio = curation_reward * weight / total_vote_weight;
  return floor(max(0, ratio) / 1000);
}

I didn't show how weight is calculated, about that: Well, you can find it by filtering active_votes. It has a limitation though, active_votes don't show more than 1000 votes. I didn't solve it in HiveStats as it is quite rare. But I do believe that a workaround should be possible, like calculating weight by yourself using shares or using another method like: https://developers.hive.io/apidefinitions/#database_api.list_votes

@klevn | Feb. 16, 2022, 11:48 a.m. | Votes: 0 | [ VOTE ]

Thank you! So wonderful!

The following, is one issue. and a question about that. and reason why I care about it.

>I did also struggle with several wording there, one of was that. What it means is, data it returns is sorted oldest to newest. So, imagine getting last 50 history of an account. The array it returns is sorted from the oldest, so if the latest operation was with index 24424, that would be the last index of the array. So, it is reverse than what you expect. This isn't true for HiveEngine for example, if you ever go into that route!

I understand this, the array is reversed, what is not clear is there is no other way to get to the newest item.. there is no way to have it ordered newest first..

so as you read thru it .. very unclear how to achieve this .. and given your struggle as well.. is there someone who we can bring this up with? because I actually find it super annoying to have things so unclear.

I have just stepped away from linux because I found it 'less than' open source in its actual implementation. so here I am curious the level of feedback we could get on such an issue. on linux they care not what the users think and projects, like gnome, often corporate entities.. and have just become bad if you ask a search engine .. this bit made me laugh from a comment..

>- Gnome really looks like it has been designed for and tested against mentally challenged people. It's infuriating, most of its utilities lack menus and basic options/settings, to the point where having a GUI is more of an impediment rathen than being something useful.

>I am very worried by the fact that Ubuntu is reverting back to Gnome.

source

this is what happens if we don't mind our source !

can we help make such improvements? are there ways to get in touch that you are aware of ? i feel like discord is the way.. but I haven't really seen any obvious 'avenue' inviting me there .. or i just missed it. (aside from you, of course)

it will take me a moment to digest the code . thanks for taking the time. wanted to push that out of my thoughts before I continued to think on this.

@yokunjon | Feb. 16, 2022, 11:57 a.m. | Votes: 1 | [ VOTE ]

> I understand this, the array is reversed, what is not clear is there is no other way to get to the newest item.. there is no way to have it ordered newest first..

It is only reverse in returned data, not whole history. So, it contains newest, it isn't the first, it is the last element. So, imagine getting limit = 1000, index = -1. The newest is result[result.length - 1]

> I have just stepped away from linux

Haha, I don't like linux either. I don't use it unless I have to.

> can we help make such improvements? are there ways to get in touch that you are aware of ?

You can open an issue if you think you found a bug:
https://gitlab.syncad.com/hive

As for discord, there are two community discords you can hang around!

HiveDevs discord server:
https://discord.gg/JAEDPH3HVs
Hive (more general) discord server:
https://discord.gg/GUB7BCrE3x

I do know there are other chatting applications people use but I don't use them so I don't know specific details.

@klevn | Feb. 16, 2022, 1:44 p.m. | Votes: 0 | [ VOTE ]

thanks for the links to the devs. i think i will log in and see the conversations.

>Haha, I don't like linux either. I don't use it unless I have to.

i use netBSD and freeBSD. what is your os of choice?

>It is only reverse in returned data, not whole history. So, it contains newest, it isn't the first, it is the last element. So, imagine getting limit = 1000, index = -1. The newest is result[result.length - 1]

i get it, but i don't get why . just seems backwards somehow. not something i really want to pursue.

thanks for the links to the HiveDevs chat. I will enjoy listening in. and you said you found answers in the chat logs.

@yokunjon | Feb. 16, 2022, 5:27 p.m. | Votes: 0 | [ VOTE ]

> i use netBSD and freeBSD. what is your os of choice?

Haha, WindπŸ‘€ws, nothing special there

> i get it, but i don't get why

Well I don't really know. Probably due to how it is filtered (it is rocksdb as far as I know). So, reversing it is twice the cost, so they don't I assume.

@klevn | Feb. 17, 2022, 10:50 p.m. | Votes: 0 | [ VOTE ]

Hello again. I have been working on this again, and found it very useful. Thank you. I was able to take your pseudo code and basically copy-pasta with little translation necessary.

At least, I think I have it working, there is one key element I don't have an answer for..

database_api.list_votes is the best I can find to get my current votes.. but this api doesn't have an option to reverse the search and get the most recent votes by an account.

any thoughts or another way that can give me the answers I am after?

my other choice is to go entirely thru the list, until I get to recent times.. and record a link in the vicinity that I can use later to avoid redundantly recalling the entire history.

@yokunjon | Feb. 18, 2022, 2 p.m. | Votes: 1 | [ VOTE ]

Hey, happy to hear that it works as you want it!

> database_api.list_votes is the best I can find to get my current votes

I didn't use it much, just experimented with it. So, instead of getting account's upvotes, getting post's upvotes the way to go I believe. So, you have to call it for each post. get_content already has active_votes field, so you can use that instead. Only difference is, active_votes field is limited at 1000 votes while you can query more with list_votes method.

@klevn | Feb. 18, 2022, 2:54 p.m. | Votes: 1 | [ VOTE ]

i've succeeded using list_votes for a user, then get_content on each of those posts that is less than 7 days old (voting time) .. then check that cashout_time > currentTime .. if so I run the calc for curation rewards.

to avoid running the whole list_votes, I am retaining the closest link .. right now hardcoded in. that saves a ton of time.

query all the posts is slow, wouldn't want to run it very often.

the estimations appears close to my 7 day average.

this whole project has been a major success, thank you for helping me get a grasp on working with the hive api!

you saved me a ton of time.

i found this that is sort of an error (I could check that cash-out is zero and not send it here)

but ended up dividing by zero in the vote_reward

so I added

if { $total_vote_weight == 0 } {
    # If we don't this, divide by zero error on no-cashout.
    set ratio 0
} else {
    set ratio [expr { $curation_reward * 1000 * $weight / $total_vote_weight }]
}

an fyi.

thank you!

namaste

Posted Using LeoFinance Beta

@yokunjon | Feb. 19, 2022, 2:44 p.m. | Votes: 1 | [ VOTE ]

Happy to hear that, you are welcome!

> but ended up dividing by zero in the vote_reward

I probably wrote something wrong, idk, but thanks for pointing out.

@yokunjon | June 4, 2022, 2:20 a.m. | Votes: 0 | [ VOTE ]

Testing

Posted Using LeoFinance Beta

@yokunjon | June 4, 2022, 7:28 a.m. | Votes: 0 | [ VOTE ]

test
Posted Using LeoFinance Beta

@keys-defender | June 4, 2022, 7:47 a.m. | Votes: 0 | [ VOTE ]

     

It looks like this comment contains a link that does not use a secure protocol: http://localhost:3000/@yokunjon/re-yokunjon-5dcebg.
HTTP is in use instead of HTTPS and no protocol redirection is in place.
Be careful and do not enter sensitive information in that website as your data won't be encrypted.
It's also a good habit to always hover links before clicking them in order to see the actual link in the bottom-left corner of your browser.

More info on this service here. For more information on HTTP unsafety read: https://whynohttps.com   https://web.dev/why-https-matters.{average of post/comments with HTTP links I found per hour: 42.9}
This auto-reply is throttled 1/20 to reduce spam but if it still bothers you reply "OFF HTTP". Or reply REVIEW for manual review and whitelisting.

@yokunjon | June 4, 2022, 8:02 a.m. | Votes: 0 | [ VOTE ]

comment add test

Posted Using LeoFinance Beta

@yokunjon | June 4, 2022, 8:04 a.m. | Votes: 0 | [ VOTE ]

comment add test 2

Posted Using LeoFinance Beta

@yokunjon | June 4, 2022, 8:18 a.m. | Votes: 0 | [ VOTE ]

hey, test

Posted Using LeoFinance Beta

@yokunjon | June 4, 2022, 8:18 a.m. | Votes: 0 | [ VOTE ]

test, another one

Posted Using LeoFinance Beta

@yokunjon | June 4, 2022, 9:21 a.m. | Votes: 0 | [ VOTE ]

test

@leothreads | Sept. 14, 2022, 1:27 p.m. | Votes: 0 | [ VOTE ]

test container

@leothreads | Sept. 14, 2022, 1:35 p.m. | Votes: 0 | [ VOTE ]

test container2

@leothreads | Sept. 14, 2022, 1:36 p.m. | Votes: 0 | [ VOTE ]

test container3

@leothreads | Sept. 15, 2022, 8:49 p.m. | Votes: 0 | [ VOTE ]

Multi-container thread chain.

@leothreads | Sept. 15, 2022, 9:02 p.m. | Votes: 0 | [ VOTE ]

Multi-container thread chain.

@leothreads | Sept. 15, 2022, 9:26 p.m. | Votes: 0 | [ VOTE ]

Multi-container thread chain.

[ BACK TO TRENDING ] [ BACK TO MENU ]
CMD>