早起的鸟有虫吃

STEEMIT社区内好多健身和跑步达人,让我这即宅且腐的人十分羡慕。
心动不如行动,向健身和跑步达人们学习,开始运动起来。

不过话说打算跑起来的时候,才惊觉手脚都生锈了,百公里提速多少秒也上不去了,那么慢跑改漫步吧,要循序渐进。话说慢步也有慢步的好处,一边溜达一边欣赏风景也不错嘛。

空气清新、草木葳蕤,心情也豁然开朗。



小树林,有人来约会吗?



两个造型奇特的椅子,不得不佩服设计者的脑洞。



草木墙,前后都有喷泉,可惜拍照的时候没开启


通往健身器材处

业主会所

健身器械哦,不要要钱哦

枝繁叶茂

小路

上边有美女哦

商业区,人还都没有出来

车道


林间小路


好啦,今天就漫步到这啦。
向社区运动达人们学习,为了健康,一起动起来吧。


This page is synchronized from the post: 早起的鸟有虫吃

两个栗子引发的冤案

两个栗子引发的冤案

之前发了两篇帖子

为了说明问题,我举了个栗子,就是如何找出没给你帖子投票的好友
然后我看到了神马,各种各样的找出未投票好友的工具诞生啦,不得不说你们的创造力和技术水平都很强大。然而那些被你们找出来的没投票的好友,是不是会一边投票一边骂一句O哥,都怪这丫开了个坏风气的先河

我看了一下窗外,没下雪,但是我依然觉得我比窦娥还冤。
我真的就是举个栗子而已嘛。
哦,不对,是举了两次栗子,至于是不是同一个栗子,我也叫不准了。

真正的目的是检查漏投

假设我有100个账户,oflyhigh0 到 oflyhigh99
然后比如 @deanliu老师发个一个帖子,然后oflyhigh 1、3、5、7、9…等等就欠儿登的投了票
然后我想让这100个ID都给deanliu老师的帖子投票

这时候,有的投了,有的没投,就很麻烦
原来我的办法是一个一个ID判断,因为投票有需要时间,所以我要随时刷新帖子获取新的投票信息,以免我操作投票期间,某个oflyhigh投了过去。这样的弊端很明显啦,效率太低。

但是我如果先用 Python中集合运算的差集,一下子就可以把没投票的oflyhigh抓出来
然后在让他们去投票,这样效率高了好多。

另外,将POST类改成直接读取投票信息,会大大减少数据传输量,节省操作时间。

简单的总结就是:

  • 用差集判断漏投的ID
  • API get_active_votes 减少数据量

正好和我们之前的两篇帖子一一对应。

我不是坏人

所以说,哥不是坏人
不会特意做个查询工具看看你们谁没给我投票的啦

觉得文章看得过眼,就随便投一票,1%还是100%都是对我的支持和鼓励。
如果文章一般般,很水,那么轻轻飘过就好,对不起浪费你的时间了。
觉得文章实在太滥,那么踩一脚也无所谓的啦,谁踩我,我都不会介意的,多说狠狠的踩回去啦。(开个玩笑😡)

另外,顺便说一句,哥最近很忙
@deanliu 老师 以及 @nextgen622 看了我之前YY的帖子
觉得很有前途,他们分别给我投了几个亿, 几千万, 几百万,几十万个STEEM
我正研究怎么挥霍掉呢,哦,不对,我正研究怎么实现之前YY的一些功能呢。
如果漏点了谁的帖子,敬请谅解,不过也用担心啦,还有几个人负责点赞那。
我准备专心学习,早日ICO赚大钱那:)

另外,顺便说一句,(咦,为何这句话这么面熟)
CN区新来的用户太多啦,帖子多到我们都看不过来
其中不乏有滥竽充数、浑水摸鱼的
我想说的是大家一起爱护CN区,那么她就会健康的成长
大家都抱着浑水摸鱼的态度,那么最终肯定就是鱼都跑了
何去何从,选择权在你们手里。

另外,顺便说一句,(咦,为何这句话这么面熟)
不要刷屏! 如果你因为刷屏被人屏蔽,那么就再也得不到他/她的投票了
如果过度刷屏,被踩死,那么就😭去吧

另外,顺便说一句(又来!!!!, 这个是oflyhigh99 要求加上去的)
坏帖子,大家都不去踩,那么你的好帖子自然会被淹没
就好比一个房间中别人都扔垃圾你不去制止,那么最终你就只能生活在垃圾中喽

好了,不啰嗦了
我去研究如何ICO骗钱去了 如何做大事去了。


看你们都发旅游贴啥的,哥也上张照片,假装去海边(把草地PS成沙滩是不是会好一些?)
IMG1008.jpg


This page is synchronized from the post: 两个栗子引发的冤案

继续学习Base58以及Base58Check

昨天学习了Base58编解码
今天来继续学习Base58Check_encoding
https://en.bitcoin.it/wiki/Base58Check_encoding

为什么要Base58Check

你可能会问,既然有了Base58编码,我们已经不会搞错0和O, 1和l和I,也把大整数转换成了可读字符串,明明就足够了,为啥还要折腾?

好,让我们假设一种情况,你在程序中输入一个Base58编码的地址,尽管你已经不会搞错0和O, 1和l和I,但是万一你不小心输错一个字符,或者少写多写一个字符,会咋样?

你可能会说,没啥大不了的,错个字符而已嘛,这不是很常见嘛,我们输入QQ密码啥的也常输错,重新输入呗!但是你有没有考虑到,如果是涉及金钱操作呢?比如你给一个比特币地址转账?

实际上,我们给比特币地址转账等操作,网站或者软件中都会校验地址是否合法,而这个校验合法性的关键操作,就是Base58Check!

《Mastering Bitcoin》中对Base58Check的描述:

To add extra security against typos or transcription errors, Base58Check is a Base58 encoding format, frequently used in bitcoin, which has a built-in error-checking code. The checksum is an additional four bytes added to the end of the data that is being encoded. The checksum is derived from the hash of the encoded data and can therefore be used to detect and prevent transcription and typing errors.

Base58Check的特色

以下是上述Wiki中介绍的Base58Check的特色

  • An arbitrarily sized payload.
  • A set of 58 alphanumeric symbols consisting of easily distinguished uppercase and lowercase letters (0OIl are not used)
  • One byte of version/application information. Bitcoin addresses use 0x00 for this byte (future ones may use 0x05).
    • Four bytes (32 bits) of SHA256-based error checking code. This code can be used to automatically detect and possibly correct typographical errors.
    • An extra step for preservation of leading zeroes in the data.

我们不难看出,相比Base58, 它多出了一个字节的版本/程序信息以及四个字节的校验码

创建Base58Check编码字符串的流程

在上述Wiki中同样列出了创建ase58Check编码字符串的流程,我粗略的翻译如下:
1) 把版本/程序信息字节和负载(payload)按字节连接到一起
2) 对结果一执行两次SHA256操作并取前四个字节
3) 按字节把结果一和结果二的四个字节连接起来
4) 把结果三当成一个大数字,对结果三执行Bash58编码
(原链接第四步,分为4、5、6三个步骤,包括如何处理前导字节零)

上述步骤在《Mastering Bitcoin》一书中有一个图,很好的说明了这个过程

(Figure 4-6. Base58Check encoding: a Base58, versioned, and checksummed format for unambiguously encoding bitcoin data)
Image source Here

Python 库中的实现

有了上述学习和了解,再回过头来看steem python 库中对base58Check编解码的实现,相当容易理解了,就无需赘述了。

1
2
3
4
5
6
7
8
9
10
11
12
13
def base58CheckEncode(version, payload):
s = ('%.2x' % version) + payload
checksum = doublesha256(s)[:4]
result = s + hexlify(checksum).decode('ascii')
return base58encode(result)


def base58CheckDecode(s):
s = unhexlify(base58decode(s))
dec = hexlify(s[:-4]).decode('ascii')
checksum = doublesha256(dec)[:4]
assert(s[-4:] == checksum)
return dec[2:]

其中俩次SHA256对应的函数实现如下:

1
2
def doublesha256(s):
return hashlib.sha256(hashlib.sha256(unhexlify(s)).digest()).digest()

至于hashlib,想必你不会陌生
我们在 这篇文章 中揭秘了我们之前抽奖密码的生成方法
比如一等奖:

>>> hashlib.sha1(bytes('一等奖中奖密码:6', 'utf-8')).hexdigest()
'fcc420adc5de61752db7ecfa837564f45c47852b'

参考链接


This page is synchronized from the post: 继续学习Base58以及Base58Check

学习了一下Base58编解码

之前YY了基于STEEM区块链的聊天工具以及STEEMIT 用户地图
可惜YY不能强国,也不能健身,只有踏踏实实的做事情,才是正道啊。

Base58 简介

最近一些学啊学的,都学吐血了
然后突然又发现一个新东西,Base58
话说以前做网站啊,或者邮件啥的经常听说Base64, 这个Base58又是什么鬼

查了一下维基百科:
https://en.wikipedia.org/wiki/Base58

Base58 is a group of binary-to-text encoding schemes used to represent large integers as alphanumeric text.

粗略一看,原来就是用于把大数字表示成字符形式
那我就不懂了,直接表示成十进制或者十六进制字符就完结了呗,搞什么事情?!!

再仔细一看

Compared to Base64, the following similar-looking letters are omitted: 0 (zero), O (capital o), I (capital i) and l (lower case L) as well as the non-alphanumeric characters + (plus) and / (slash)

输入文本串的时候傻傻的分不清出0和O, I 和l 有木有?中枪的🙋
这个Base58就避免了这个问题,看来凡事出现都是有缘由的。

听说还有个变种Base56,去的更彻底,不过咱没遇到,就不研究它了

A variant, Base56, excludes 1 (one) and o (lowercase o) compared to Base 58.

然后我总结了一下,就是把数字表示成不容易输入错误的文本编码
维基百科里并没有说到,因为这组不容易出错的文本编码一共包含58个字符,所以叫Base58

Base58 编码规则

维基百科中并没有说明Base58详细编码规则
相比之下,Base64 则是亲妈养的
https://en.wikipedia.org/wiki/Base64

但是讨论维基百科是不是Base58的亲妈,貌似于事无补,所以我决定继续我的探索之路。
好在维基百科还算厚道,给出了Base58亲弟弟Base58Check_encoding的链接
https://en.bitcoin.it/wiki/Base58Check_encoding
之所以说亲弟弟,是因为长江后浪推前浪,弟弟比哥哥长得更高更壮,好吧,其实就是这个链接里的信息更多而已

比如说,多出了这么个玩意

我横看,竖看,左看,右看,我脖子哎,咋也没看明白
直到我看到下边这行代码:

code_string = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
我擦,不就是查表法的一个表嘛,何必整那么复杂,再回头看看,上边也就是一个表,我晕

里边说了地址编码的算法

The algorithm for encoding address_byte_string (consisting of 1-byte_version + hash_or_other_data + 4-byte_check_code) is

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
code_string = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
x = convert_bytes_to_big_integer(hash_result)

output_string = ""

while(x > 0)
{
(x, remainder) = divide(x, 58)
output_string.append(code_string[remainder])
}

repeat(number_of_leading_zero_bytes_in_hash)
{
output_string.append(code_string[0]);
}

output_string.reverse();

我又想吐学了,气的我都不会打字了,这分明是把最后生成的地址编码一下嘛,整的我去找半天啥算法呢?
跟这些玩意consisting of 1-byte_version + hash_or_other_data + 4-byte_check_code有啥关系?写一大堆忽悠我。

Python 实现

实现之一:

咦,话说我咋找不到从哪里找到的这个链接了
https://github.com/keis/base58/blob/master/base58.py

steem 官方Python库中Base58 实现

https://github.com/steemit/steem-python/blob/master/steembase/base58.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# https://github.com/tochev/python3-cryptocoins/raw/master/cryptocoins/base58.py
BASE58_ALPHABET = b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

def base58decode(base58_str):
base58_text = bytes(base58_str, "ascii")
n = 0
leading_zeroes_count = 0
for b in base58_text:
n = n * 58 + BASE58_ALPHABET.find(b)
if n == 0:
leading_zeroes_count += 1
res = bytearray()
while n >= 256:
div, mod = divmod(n, 256)
res.insert(0, mod)
n = div
else:
res.insert(0, n)
return hexlify(bytearray(1) * leading_zeroes_count + res).decode('ascii')


def base58encode(hexstring):
byteseq = bytes(unhexlify(bytes(hexstring, 'ascii')))
n = 0
leading_zeroes_count = 0
for c in byteseq:
n = n * 256 + c
if n == 0:
leading_zeroes_count += 1
res = bytearray()
while n >= 58:
div, mod = divmod(n, 58)
res.insert(0, BASE58_ALPHABET[mod])
n = div
else:
res.insert(0, BASE58_ALPHABET[n])
return (BASE58_ALPHABET[0:1] * leading_zeroes_count + res).decode('ascii')

是不是很简单?
神马? 不明白?

其实就是把编码后的文本数字串,转换成一个大整数,然后再按58进制表示

什么? 58进制没听过, 16进制总听说过吧? 略有区别的是16进制字符0-15和0x0 - 0xF是一一对应的,而这个0-57,需要查表对应,仅此而已!解码就是逆过程!

(上边这两段话,是我吐血总结出来的!! )

至于Base58Check是咋check的,就先不研究了,吐学去了。

参考链接


This page is synchronized from the post: 学习了一下Base58编解码

YY 一个STEEMIT 用户地图

之前YY了一个基于STEEM区块链的聊天工具

然后发现YY停不下来了,有木有?
话说现在啥最火,用的最广了?除了聊天工具,当然是地图啦!
做一个基于区块链的地图?貌似没啥必要吧!用不用区块链的地图,美国就是美国,中国就是中国,都不会搞错的。


(来自百度图片搜索)

STEEMIT用户分布地图

但是常玩STEEM的我,总觉得有一点(很多)不完美的地方,比如用户的地理位置。包括我在内的许多人,地理位置上都只写到国别或者城市,我们无法知道一个城市有多少玩家?也无法知道我们附近都多少STEEMIT好友。

于是我就冒出个想法来
如果有一个地图,大家都可以在上边自己标注位置,所有/大多数STEEMIT用户都去标记一下,会不会是一个很有趣的事情。我决定叫它STEEMIT用户分布地图。

有啥用处呢?

你可以会问,这个地图有啥用啊?
用处大着呢!

一: 查看附近的STEEMIT用户
首先声明,什么微信的摇一摇、微信、QQ附近的人、以及神马陌陌之流的乱七八糟的功能我都没有用过的!我这么一个纯洁的人,是不会去约*的。如果有了STEEMIT用户地图,我就可以看看都谁和我在一个城市啦,有空闲的时候,约出来喝杯茶、饮点酒、交流一下STEEMIT的使用经验心得,不失为一件美事啊。

二: 便于组织成规模的聚会
有了这个STEEMIT用户分布图,我们可以进一步统计,哪个省或者哪个市用户最集中。这样便于我们举办城市级别或者省一级的聚会。畅想大家聚在一起,嗯,每人在穿个STEEMIT T恤,大家一起喊喊STEEM涨涨涨,STEEMIT万岁万岁万万岁的口号,该是多么壮观和激动人心啊。(话说,会不会被当成传销抓起来?)

三: 便于有针对性的推广
通过用户分布,我们可以看到对STEEMIT接受程度较高的地区,也可以看到STEEMIT覆盖薄弱地区,然后可以针对这些地区采取不同的推广策略。达到有效扩展的目的。

四: 对用户是一种宣传
地图上显示用户STEEMIT头像,别人点击,自动转到STEEMIT的个人主页上来,这样对用户是一个很好的宣传。比如我就可能把和我一个城市的用户统统Follow了。

其它需要考虑事项

一: 用户只能标记自己

这点非常重要,用户应该只能标记自己,且同一时间内只能标记一处。换言之:

  • 用户不能标记别人
  • 用户同一时间只能在一处标记 (重新标记则清除之前的标记)

如果用户能标记别人,把我标到太平洋深处,我就只能深深太平洋里深深伤心了
如果用户能标记好几处,那么莫非用户会分身大法?

二: 地图支持缩放
这样可以查看全球用户分布,中国用户分布,某个省用户分布,某个市用户分布等等

三: 地图带统计功能
除了靠显示头像密度来估计用户分布情况外,应该支持国家、区域、县市等统计和列表功能

四: 注重保护用户隐私
精度不要太高,否则可能会有隐私等风险,比如说一下子定位到 台湾第一美女 @deanliu 家里去,就爽了, 就不安全了。

结论

即 YY了一个基于STEEM区块链的聊天工具之后
又YY了一个STEEM用户分布地图

我准备开始ICO啦,就做聊天工具和地图,大家快几千亿几千亿的打钱过来吧。


This page is synchronized from the post: YY 一个STEEMIT 用户地图

继续分享有意思的数据,关于声望分

很久很久很久以前,大概11个月以前,我去学习如何计算声望分
为什么要去学习这个呢?因为steem节点返回的用户声望分是这个样子的:

话说你若能从'reputation': '131708387059711'这里分辨出来这个声望分是多少,是高还是低,那么我表示佩服。至少,我是看不出来啊。

声望分计算公式

于是千般周折、百般差找,我总算找到了计算公式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
This is a rough approximation of log10 that works with huge digit-strings.
Warning: Math.log10(0) === NaN
The 0.00000001 offset fixes cases of Math.log(1000)/Math.LN10 = 2.99999999~
*/
function log10(str) {
const leadingDigits = parseInt(str.substring(0, 4));
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

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
// base-line 0 to darken and < 0 to auto hide (grep rephide)
out = parseInt(out)
return out
}

https://github.com/steemit/condenser/blob/master/app/utils/ParsersAndFormatters.js
你让我解释一下?对不起,我也不懂,我多说只能照猫画虎移植一下。

如何与新手 25 声望分说再见?

通过分析上述公式,我发现一些很有趣的事情。

比如这句:
out = Math.max(out - 9, 0); // @ -9, $0.50 earned is approx magnitude 1
也就是说,
reputation值在-1000000000 以及 1000000000 之间的用户声望分都是25
新用户注册reputation值为0,亦即声望分为25。26级为1291549665.01,其实这个还是超级快的,只要你的帖子被大鲸鱼点到,声望分可能一下子就到30以上了。

Score Reputation Difference
25 1000000000.00 1000000000.00
26 1291549665.01 291549665.01
27 1668100537.20 376550872.19
28 2154434690.03 486334152.83
29 2782559402.21 628124712.18
30 3593813663.80 811254261.60

一些有意思的数据

‘reputation’为零的用户有多少?

reputation=0亦即用户注册后声望分没加没减,大致分为两部分用户

  • 一部分是沉寂号,注册后就没有进行任何操作
  • 另一部分可能仅用于点赞和转账等金钱操作

通过数据库查询,’reputation’:0 的用户为: 179611

声望分小于25的用户

我们之前说过
reputation值在-1000000000 以及 1000000000 之间的用户声望分都是25
声望分小于25,亦即用户因为一些错误行为/或者别人恶意踩踏,导致reputation < -1000000000

通过数据库查询,声望分小于25的用户: 43394

声望分大于25的用户

相对于从未活跃的用户或者声望分小于25的用户,我们可以认为声望分大于25的用户,是在STEEMIT上活跃并且好评大于差评的用户
通过数据库查询,声望分大于25的用户: 52538

当前总用户数

我们找出了未活跃用户,以及声望分小于25(差评多余好评) 以及声望分大于25(好评多于差评)的用户,那么当前一共有多少用户呢?

通过数据库查询,当前总用户数: 275573

从上边这组数据看出什么?

通过上边一组数据,我们不难得出以下结论

  • 未活跃用户(从未发帖和回复)占比为: 65.18%
  • 活跃且差评多于好评的用户占比为: 15.75%
  • 活跃且好评多于差评的用户占比为: 19.07%

排除掉被差评误伤的,也就是说仅有不到20%的好评用户在发帖和回复

结论

  • 有大约65%的注册用户从未发帖和回复
  • 其余35%的活跃用户,差评用户和好评用户比例接近 1:1 (15%:19%)

补充说明:
1) 被downvote的原因很多,所以被差评的用户不一定是坏用户
2) 以上所有数据来源于 steemdata
3) 数据库有延迟,并且数据在随时刷新,具体数字仅供参考
4) 经过我核实,数据库有些用户信用计算的不对,应该是25被计算成负的,所有数据仅供参考


This page is synchronized from the post: 继续分享有意思的数据,关于声望分

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×