This commit is contained in:
chenyan 2023-04-16 23:02:48 +08:00
parent 9f31a3f918
commit 5e19e11719
17 changed files with 779 additions and 23 deletions

View File

@ -71,14 +71,14 @@
{% endif %}
<span>最新构建于: {{ site.time | date: "%Y-%m-%d %H:%M" }}</span><br><br>
<span>
<a href="http://www.beian.miit.gov.cn" rel="nofollow">闽ICP备19012687号</a>
<a href="http://beian.miit.gov.cn" rel="nofollow">闽ICP备17033777号</a>
</span><br><br>
<span>开源地址: https://gitee.com/apihub/feling.net</span>
</div>
{% if page.url contains "/pages/" or page.url contains "/rank/" %}
<script>
<!-- <script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</script> -->
{% else %}
<script>
if (localStorage.shyFooter == 'true') {
@ -87,7 +87,7 @@
$('#shy-footer-on').show()
$('#shy-footer-off').hide()
} else {
(adsbygoogle = window.adsbygoogle || []).push({});
// (adsbygoogle = window.adsbygoogle || []).push({});
$('#shy-footer-on').hide()
$('#shy-footer-off').show()
}

View File

@ -9,6 +9,7 @@
<ul class="uk-navbar-nav">
<li
{% if page.url contains "/json/" %}class="uk-active"{% endif %}
{% if page.url contains "/jwt/" %}class="uk-active"{% endif %}
{% if page.url contains "/base64/" %}class="uk-active"{% endif %}
{% if page.url contains "/unicode/" %}class="uk-active"{% endif %}
{% if page.url contains "/wsp/" %}class="uk-active"{% endif %}
@ -27,6 +28,7 @@
<li class="uk-nav-divider"></li>
<li><a href="/json/">Json 格式化</a></li>
<li><a href="/jwt/">JWT 解码</a></li>
<li><a href="/wsp/">WebSocket 联调</a></li>
<li><a href="/base64/">Base64 编解码</a></li>
<li><a href="/unicode/">\uxxxx 转中文</a></li>
@ -47,6 +49,7 @@
<div class="uk-navbar-flip">
<ul class="uk-navbar-nav uk-hidden-small" >
{% if page.url contains "/json/" %}{% else %}<li><a href="/json/">Json 格式化</a></li>{% endif %}
{% if page.url contains "/jwt/" %}{% else %}<li><a href="/jwt/">JWT 解码</a></li>{% endif %}
{% if page.url contains "/base64/" %}{% else %}<li><a href="/base64/">Base64 编解码</a></li>{% endif %}
{% if page.url contains "/wsp/" %}{% else %}<li><a href="/wsp/">WebSocket 联调</a></li>{% endif %}
<li><a href="/">更多 <i class="uk-icon-angle-double-right"></i></a></li>

View File

@ -140,9 +140,9 @@ layout: default
style="display:inline-block;width:336px;height:280px"
data-ad-client="ca-pub-3779740765441924"
data-ad-slot="6169161876"></ins>
<script>
<!-- <script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</script> -->
</li>
</ul>
</div>
@ -229,7 +229,7 @@ layout: default
$('#x-left-content').show();
</script>
<link rel="stylesheet" href="//cdn.feling.net/css/gitalk.css">
<!-- <link rel="stylesheet" href="//cdn.feling.net/css/gitalk.css">
<script src="//cdn.feling.net/js/gitalk.min.js"></script>
<script>
var gitalk = new Gitalk({
@ -243,6 +243,6 @@ layout: default
})
gitalk.render('gitalk-container')
</script>
</script> -->
</div>
</div>

View File

@ -393,7 +393,7 @@ soc.send(buf)
现在的程序还是多线程的模型,虽然功能已经实现。但是至少我自己在用的时候,明显感觉网速很慢。尤其是像腾讯、新浪这种门户网站的首页。一个页面的请求太他妈多了!!一下子就开了巨多的线程。线程相互之间切换的代价也是很大的,每个线程时间没做多少事,多数时间都在等待 IO。带宽没利用上多少cpu 就快耗尽了,还都是耗在切换线程上,然后网速还很慢。
有一种叫协程的东西。内部好象是用 select poll epoll 那三个实现的。具体实现还没花时间研究过。它的效果大概是这样的:在一个线程里,有多个 socket当一个 socket 在等待 IO 的时候,切换到其他的程序语句去执行。这个时候的切换,就相当于是函数调用的时候的切换,代价非常非常的小。用一个线程就能处理巨多的 socket ,充分利用 cpu 。
有一种叫协程的东西。内部好象是用 select poll epoll 那三个实现的。具体实现还没花时间研究过[什么是epoll](/pages/2023/01/select-epoll.html)。它的效果大概是这样的:在一个线程里,有多个 socket当一个 socket 在等待 IO 的时候,切换到其他的程序语句去执行。这个时候的切换,就相当于是函数调用的时候的切换,代价非常非常的小。用一个线程就能处理巨多的 socket ,充分利用 cpu 。
实际用起来的效果在代理运行在本地的时候浏览器设置了代理几乎感觉不到代理的存在。内存、cpu 等资源都占用得很少。部署到服务器上,带宽都耗尽了 cpu 资源都还剩余很多。

View File

@ -2,7 +2,7 @@
layout: pages
title: 关于机械硬盘
categories: 杂谈
tags: [os, middleware, hdd]
tags: [os, middleware, hdd, mq, mysql]
---

View File

@ -204,6 +204,17 @@ ReentrantLock 还把 AQS 的 ConditionObject 暴露了出来,可以创建多
AQS.ConditionObject 类实现了 Condition 接口。每个 ConditionObject 里存着一条 Node 组成的等待队列。 ConditionObject 队列的 await()、signal() 方法,也已经由 AQS 模板实现好了。
### CountDownLatch
CountDownLatch 对 AQS 的使用方式是这样的:
首先,在构造方法中,就把 state 设置成了 count。
然后,使用者调用 countDown() 实质是走到了 AQS.releaseShared() 去释放锁。CountDownLatch 通过 CAS 的操作对 state 的值减1。如果成功被减到了0返回值才会是truetrue 代表释放成功的含义,以触发 AQS.releaseShared() 去执行唤醒等待线程的操作。
最后,使用者调用 await() 实质是对应 AQS.acquireSharedInterruptibly() 去获取锁。CountDownLatch 判断如果 state == 0就反馈给 AQS 获取锁成功,那么线程将直接继续运行。如果 state != 0反馈给 AQS 获取锁失败AQS 就会把线程阻塞,加入到等待队列。等待被上一小节中描述的 countDown() 操作唤醒。
## 展开讨论下CAS
### AtomicInteger

View File

@ -1,11 +0,0 @@
---
layout: pages
title:
categories: 杂谈
tags: [os, epoll]
published: false
---
* 文章目录
{:toc}

View File

@ -1,11 +1,12 @@
---
layout: pages
title:
title: 关于MQ
categories: 杂谈
tags: [os, epoll]
published: false
---
* 文章目录
{:toc}

View File

@ -0,0 +1,66 @@
---
layout: pages
title: MySQL InnoDB 中的索引覆盖
categories: 杂谈
tags: [mysql]
---
## 什么是索引覆盖
新建一张表的时候,必须有一个主键。为什么必须呢?因为 InnoDB 存储引擎中表里的数据就存在主键索引这颗B+树的叶子节点里。
而其他索引的叶子节点存储的主要是主键id是不包括这行的全量数据的。
使用普通索引查询数据的时候,走到叶子节点,也只能拿到 主键id 和 索引字段。还需要根据主键id再走一遍主键索引才能拿到整行的数据。
什么是索引覆盖呢? 就是 select 的时候,如果只 select 主键id 和 当前查询使用的索引树对应的索引字段。就不需要回到主键索引里拿整行数据了。
## 错误的应用
经常在维护的代码里见到不用 `select *`,只 `select 具体字段` 的情况。 那些人是出于什么考虑,一个简单的星号不写,费劲去把字段一个个列出来呢?
也许是为了省带宽?
也许是觉得少几个字段能减少反序列化的开销?
也许最大的原因,是学到了 索引覆盖 这个知识点。就开始滥用了。。。
---
**我是推荐尽量使用 `select *` 的**。dao 层对外返回的数据,应该尽量是全量的。整体的模型,应该是越底层,越接近数据层,提供的数据字段越全面。越上层,越接近逻辑层、业务层,取用的字段越精细。
我们的业务在不断变化,需求在不停的提出。假如某天要给表增加一个字段。不用 select * 就得挨个 sql 改一遍。
更严重的情况不是给表增加字段。而是这个字段在表里原本就有,业务层原本没有使用。现在要用了,必然会出现直接在业务层代码里直接取用的操作,然而 dao 层根本没给返回值对象里设置这个字段的值。只能拿到null等到自测、测试、甚至是上线后才发现。
---
在这个案例里,可维护性才是最重要的。真的不在乎那点计算资源的损耗。
## 恰当应用的例子
使用 offset 关键字在 mysql 里执行分页操作。页数越大,性能越差。
什么原因呢?
跳出 mysql 的范畴,我们设计一个数据库的粗浅架构。可以分为 计算层 和 数据层。offset 的操作被划分在了计算层,数据层在执行 where 条件 筛选数据的时候并不知道哪些数据是该 offset 跳过的。
于是在查询 每页十条,第十页的数据 的时候,使用了 select *。数据层就只能查出一百条数据并且一百条数据都需要回到主键索引去查出全量数据。走到主键索引的叶子节点这个步骤大概率是要走磁盘IO的。一百条完整数据交给计算层后才开始去做跳过前九页的操作。
mysql 不去做针对 offset 的优化。只能是我们使用者换个使用方式。把 sql 分成两条,第一条与原 sql 几乎一致,只把 select * 改成 select 主键id。第二条 sql 再根据 主键id 查全量数据。分两条 sql 操作就避免了前九页数据的回主键索引走磁盘IO了。
如果要严守 sql 只 select * 的规范,可以把两条 sql 用子查询、join 的方式合并成一条。这里是为了实现技术目的使用的join并且join的驱动集非常小。尽量不要为了业务目的使用join。
## 针对 offset推荐另一个方案
另一个处理 offset 问题的方案,是不用 sql 自带的 offset。由使用者增加一个 where 条件:(升序时) `where sort_field > 上一页最后一个 sort_field 的值`
这也是变相的 “计算向数据转移”。把 offset 的计算转换成了 where 条件where 条件是在数据层执行的。这个思想在大数据中常见。
说到大数据,假设 mysql 将来要平滑替换到 分布式的 TiDB。数据层肯定是分片的。类似于 mysql 中分表了,又没有分页规则,只能每张表都执行一遍。分页的场景下,要取 每页十条,第十页的数据,每个分片必须返回前一百条数据,才能保证拿到完整的第十页数据。把 offset 转换成 where 条件,每个分片就只需要各自的第十页数据就能拼出整体的第十页。
* 文章目录
{:toc}

View File

@ -0,0 +1,41 @@
---
layout: pages
title: select、epoll
categories: 杂谈
tags: [os, epoll]
---
讲网络IO模型先区分下两个层级一是操作系统层二是我们的用户代码层。
一切都依赖于操作系统的内核代码的发展,
## BIO
早期,操作系统只提供阻塞式的系统调用。用户代码也就只好用 “来一个socket连接就为它单独起一个线程来接收数据” 的线程模型。不单独分配线程的话,程序阻塞在那,一次就只能处理一个请求。这个阶段最突出的问题,在于大量线程的创建、回收、切换的损耗。
## NIO
后来发展出了非阻塞的系统调用。也就是 accept() 方法会立即返回了只不过没有连接的时候返回的是null。recv() 也支持立即返回,可以去询问某个连接是不是可以读数据了。这解决了大量线程的创建、回收、切换的问题。用户程序可以在一个线程里循环 accept()不是null就放到列表里存起来。甚至再拮据一点就在这段循环里把列表里的连接挨个拿到操作系统那边询问是不是可以读数据了。一个线程可以维护多个连接了。这个阶段最突出的问题在于大量向操作系统询问连接是否可用的操作系统调用的消耗极大又只有少数的询问能得到肯定回复。
## NIO 中的多路复用器
再后来多路复用器出现了select() 支持一次传多个连接做参数虽然还是需要挨个连接判断一遍但这个遍历过程全程在内核态完成。减少了系统调用的次数。这个阶段最突出的问题在于内核内部依然需要遍历所有连接。poll() 这个多路复用器会更新一点,但它的实现也是需要遍历所有连接。
## 多路复用器的更新
再后来,多路复用器出了一个新的版本,叫 epoll。
epoll_create() 创建一个实例,
epoll_ctl() 往里添加要监控的连接,
epoll_wait() 去询问有没有可读的连接。
比起 select() 的直接询问epoll 的调用方式多了创建实例和添加被监控连接这两个前置步骤。在前置的步骤里它需要给这个epoll实例分配一颗红黑树和一个列表把连接放进树里。当网卡的中断来临select 需要的只是有人能把连接状态标记为可以读数据就行了。而 epoll 还多了一步,维护红黑树的节点,把这个可读的连接移动到专门的列表里。用户程序来询问的时候,直接查看可读列表的数据,不需要遍历所有节点了。
## New IO 还是 Non-Blocking IO
NIO 这个词,操作系统里叫 Non-Blocking IO指的是提供了一套非阻塞的系统调用。java 里叫 New IO它伴随着操作系统网络IO的发展新封装了操作系统的调用装成统一的java的 Selector类底下实际用的是select 还是 epoll又或者是windows才有的其他多路复用器要看操作系统的支持。
* 文章目录
{:toc}

View File

@ -0,0 +1,80 @@
---
layout: pages
title: 读 CopyOnWriteArrayList
categories: [Java]
---
随机挑一个java类来读今天读的是 JUC 下的 CopyOnWriteArrayList。
## 线程安全 与 CopyOnWrite
CopyOnWrite 是保证线程安全的一个常用手段,这让我联想到刚接触 guava 的时候,大多数被传说是线程安全的类,在修改的时候都是返回了一个新的对象。
比如 Splitter
```java
// 使用
Splitter splitter = Splitter.on("|").omitEmptyStrings();
// omitEmptyStrings() 源码
public Splitter omitEmptyStrings() {
return new Splitter(strategy, true, trimmer, limit); // 第二个参数对应 omitEmptyStrings = true
}
```
在设置是否忽略空白字符串的时候,返回了新的对象。使用的是不同的对象,自然就不存在线程的安全的问题。
## 主要作用于 iterator
CopyOnWriteArrayList 中的 CopyOnWrite主要作用发挥在遍历的操作。让遍历操作是基于快照的方式进行不会有遍历时修改数据的问题不需要做线程同步的操作。
```java
// CopyOnWriteArrayList.iterator() 方法
public Iterator<E> iterator() {
return new COWIterator<E>(getArray(), 0); // 是一个自定义的特殊 Iterator: COWIterator
}
// COWIterator 构造方法
private COWIterator(Object[] elements, int initialCursor) {
cursor = initialCursor;
snapshot = elements; // 取得快照
}
```
iterator 对象拿到的只是快照,所以这必须是个特殊的 iterator。iterator.remove()、iterator.set(E e)、iterator.add(E e) 都是 UnsupportedOperation。因为修改的操作没办法影响到当前实际列表。
## 要完整的线程安全,还是需要加锁的
CopyOnWrite 对 List 的 add() 之类的操作其实是不友好的。每次都创建新的,代价是很大的。
而且因为 Copy、 Write、Replace 的操作都不是原子操作CopyOnWrite 本身是不可能保证 add() 的线程安全的。所有的修改操作都还是要加锁。CopyOnWriteArrayList 有个 ReentrantLock 成员变量,所有的写操作都加锁了。
## synchronizedList
到目前为止,是否选用这个类,判断依据就很明显了。重遍历 的场景下适合用。
如果是 重修改 的场景该用哪个类呢?怎么找?回到 ArrayList 类里面,这种注意事项级别的问题,通常 jdk 的开发者都会把答案写在基础类的注释里的。
看下注释就得到了 `Collections.synchronizedList` 这个答案,并且也有 synchronizedList 在遍历方面存在各种问题的描述。
## ArrayList
顺带看下 ArrayList
1. 默认容量是10
2. add 的时候。先做扩容相关的确认,再设置数据
3. 容量完全使用光的时候才扩容。这点和 Map 的有小于1的负荷系数不一样Map 的填充是一个概率问题。但是 Array 的填充是明确的。
4. 新的容量取的是 new = old + (old >> 1),也就是原来的 1.5 倍。
(有个神奇的 MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8为啥 -8 呢...答案就在源码注释里 →.→)
* 文章目录
{:toc}

View File

@ -0,0 +1,81 @@
---
layout: pages
title: 读 HashSet(读 HashMap)
categories: [Java]
---
随机挑一个java类来读今天读的是 HashSet。
HashSet 就是 HashMap 的 key。。。就。。。读完了。。。
得改个题目,读 HashMap。
## 翻译下 HashMap 类的注释
基于散列表实现的 Map 接口。实现了所有可选的 map 操作,并且允许 null 值 和 null key。大体上和 Hashtable 功能类似,除了 HashMap 不是线程同步的,并且允许 null。这个类不保证顺序甚至不保证已有的元素顺序的可重复读。
假设散列函数能恰当地把元素分散到哈希桶里,那么对于基础的操作,比如 get() 和 put(),能提供 O(1) 的时间复杂度. 对于集合视图的遍历所需要的时间,跟其 “容量” (桶的数量)加上其大小(内含键值对的数量)成正比。所以如果遍历的性能比较重要,就不要把初始容量设置得太大,或者把触发扩容用的负载系数设置得太低。
一个 HashMap 的实例有两个影响性能的参数初始容量initial capacity 和 负载系数load factor
原文逐字翻译的话废话太多了接下来用自己的话说吧。。load factor 描述了哈希表有多满,是判断哈希表是否需要扩容的标准,当 键值对的数量 > load factor 乘以 HashMap 的容量,就会自动扩容,容量翻倍,这个操作需要对数据进行 rehash。
load factor 默认 0.75,是权衡的结果,较高的值减少了空间开销,但增加了查找成本(影响绝大部分的操作,包括 get 和 put。在设置初始容量时应考虑预期条目数量及其负载系数以尽量减少 rehash 操作的次数。如果初始容量大于最大条目数除以负载系数,则不会发生 rehash。
如果预期要存储的条目数比较大,一开始就设置一个大的初始容量,比让它自动 rehash 并扩容要好得多。
如果大部分条目的 hashCode 是相同的也就是hash冲突比较多会大大降低哈希表的性能。所以如果 key 是 Comparable 的类,也会结合他们比大小的结果。(这句就有点不太理解了)
要注意它的是非同步的。多线程使用时必须自己外加同步操作。或者直接用 Collections.synchronizedMap 包一层。
除非用 iterator 对象下自带的 remove 方法,不然的话,在通过 iterator 遍历期间,如果对 Map 进行了结构修改iterator 会尽可能快速失败,立即报错的。(总之就是说一边遍历,一边并发的修改 是很奇葩的操作。我是建议试下搞个快照出来遍历)
---
抽几个关键词出来:
允许null、
初始容量、
负载系数、
非同步的操作、
不要遍历时并发修改、
下面开始看代码了。。。希望能发现一些新东西。。。还有最初的目的 "keySet" 呀。。。
## 解决哈希冲突
一个桶里要对应多个元素。数量少的时候是链表。达到 TREEIFY_THRESHOLD = 8 个元素且容量大于64时转换成树结构。6个元素时变回链表。桶里存的是链表或树的根节点。
## HashSet
HashSet 就是 HashMap 的 keySet。那么 key 的值都存在哪里?集合内元素不可以重复这个特性怎么得来的?
key 跟 value 一起打包成了 Node 对象。Node 存到了哈希表里。
要拿到 keySet 里所有的 key 的值只能从哈希表里遍历额。HashIterator 会有一些遍历到空白桶位的额外消耗。
好处是 Set 的集合内元素不可以重复这个特性,可以直接从哈希表传承到一大部分,再从处理哈希冲突的数据结构里传承到剩下的部分。
## 扩容
容量翻倍
```java
newCap = oldCap << 1
```
## containsValue() 性能有点惨
``` java
for(哈希桶)
for(单个桶里所有元素)
```
* 文章目录
{:toc}

View File

@ -0,0 +1,23 @@
---
layout: pages
title: 读 类加载器
categories: [Java]
published: false
---
挑一个java类来读今天读的是 sun.misc.Launcher
为啥会看到这个类?因为复习到了 java 的类加载机制,点进去看 ClassLoader 的源码,追溯到了这个类。
## 双亲委派
## 双亲委派模型的破坏
## 单例模式
## 基于类加载实现的单例,实质都是用的 synchronized
* 文章目录
{:toc}

View File

@ -0,0 +1,40 @@
---
layout: pages
title: ArrayBlockingQueue
categories: [Java]
---
ArrayBlockingQueue闭着眼睛自己构思一个用不着翻 jdk 的源码。
要用数组实现一个阻塞队列。可以拆出三个部分分别讨论。
1. 队列
2. 阻塞
3. 并发
## 队列
首先需要一个数组来存储队列中的数据。
然后讨论先进先出的特性如何实现我们需要两个标记分别记录入队的数据要添加到数组的哪个位置、出队的数据要从哪个位置取。这两个标记都从0下标开始往后走。
这就出现了一个问题标记指向的位置不停的往前走数组不可能为了它无限延长。就需要在逻辑上把数组看成一个环。假设队列容量是12标志到11后再往前走一格就该变到0了。
注意限制出队标志不能走到入队标志前面去。
## 阻塞
用 ReentrantLock 建两个 Condition 出来。一个用来队列满时阻塞生产者,一个用来队列空时阻塞消费者。在数据入队的时候去唤醒消费者,数据出队的时候去唤醒生产者。
## 并发
修改数组数据的操作,都用 ReentrantLock 加一下锁。
* 文章目录
{:toc}

View File

@ -85,6 +85,12 @@
<hr style="margin:0">
<p style="text-align:left;font-size:11px;margin:0px;">格式化、高亮、折叠你的 json 字符串</p>
</a>
<a class="uk-button" style="margin: 0px 0px 10px 10px;" href="/jwt/">
<div style="text-align:left;font-size:18px">JWT 解码</div>
<hr style="margin:0">
<p style="text-align:left;font-size:11px;margin:0px;">JSON Web Token 在线解码</p>
</a>
<a class="uk-button" style="margin: 0px 0px 10px 10px;" href="/base64/"
onclick="localStorage.base64_activeTab = 1;">
@ -228,6 +234,7 @@
<li><a href="/pages/base64.html">理解 Base64 编码</a></li>
<li><a href="/pages/rank_tip.html">垃圾页面提示</a></li>
<li><a href="/404.html">404页面提示</a></li>
<li><a href="/proxy.pac">pac配置</a></li>
</div>
</div>
@ -238,7 +245,7 @@
开源地址: https://gitee.com/apihub/feling.net
</span><br><br>
<span>
<a href="http://www.beian.miit.gov.cn" rel="nofollow">闽ICP备19012687号</a>
<a href="http://beian.miit.gov.cn" rel="nofollow">闽ICP备17033777号</a>
</span><br><br>
<br>
</div>

350
jwt/index.html Normal file
View File

@ -0,0 +1,350 @@
---
title: JWT 解码
layout: default_tool
keywords: [jwt, JSON Web Token, jwt在线解码]
description: jwt 在线解码工具
---
<style type="text/css">
.json_key {
color: #92278f;
font-weight: bold;
}
.json_string {
color: #3ab54a;
font-weight: bold;
}
.json_link {
color: #61D2D6;
font-weight: bold;
text-decoration:none;
}
.json_link:hover {
color: #005599;
font-weight: bold;
text-decoration:none;
}
.json_number {
color: #25aae2;
font-weight: bold;
}
.json_boolean {
color: #f98280;
font-weight: bold;
}
.json_null {
color: #ccc;
font-weight: bold;
}
.fold_icon{
font-size: 12px;
color: #ccc;
}
#json_src {
word-break: break-all;
height: 100%;
resize: vertical;
padding: 10px;
font-size: 13px;
font-family: Consolas, monospace;
}
#json_result {
font-family: Consolas, monospace;
}
@media (min-width: 960px) {
#content {
display: flex;
}
#json_src_box {
width: 38%;
}
#json_result_box {
padding-left: 10px;
width: 62%;
}
}
@media (max-width: 960px) {
#json_src_box {
width: 100%;
height: 200px;
}
#json_result_box {
margin-top: 10px;
width: 100%;
}
}
</style>
<script>
if (!String.prototype.repeat) {
String.prototype.repeat = function(count) {
'use strict';
if (this == null)
throw new TypeError('can\'t convert ' + this + ' to object');
var str = '' + this;
// To convert string to integer.
count = +count;
// Check NaN
if (count != count)
count = 0;
if (count < 0)
throw new RangeError('repeat count must be non-negative');
if (count == Infinity)
throw new RangeError('repeat count must be less than infinity');
count = Math.floor(count);
if (str.length == 0 || count == 0)
return '';
// Ensuring count is a 31-bit integer allows us to heavily optimize the
// main part. But anyway, most current (August 2014) browsers can't handle
// strings 1 << 28 chars or longer, so:
if (str.length * count >= 1 << 28)
throw new RangeError('repeat count must not overflow maximum string size');
var maxCount = str.length * count;
count = Math.floor(Math.log(count) / Math.log(2));
while (count) {
str += str;
count--;
}
str += str.substring(0, maxCount - str.length);
return str;
}
}
if (!String.prototype.startsWith) {
Object.defineProperty(String.prototype, 'startsWith', {
value: function(search, pos) {
pos = !pos || pos < 0 ? 0 : +pos;
return this.substring(pos, pos + search.length) === search;
}
});
}
if (!String.prototype.endsWith) {
String.prototype.endsWith = function(search, this_len) {
if (this_len === undefined || this_len > this.length) {
this_len = this.length;
}
return this.substring(this_len - search.length, this_len) === search;
};
}
</script>
<div id="content">
<div id="json_src_box" class="uk-width-10-10">
<textarea id="json_src" class="uk-width-1-1" autofocus spellcheck="false" v-model="jsonSrc"
v-on:click="$('#cursor-position').show();cursorPosition = $('#json_src').prop('selectionStart')"
v-on:keydown="cursorPosition = $('#json_src').prop('selectionStart')"
v-on:blur="cursorPosition = '?'"
v-on:input="cursorPosition = $('#json_src').prop('selectionStart');jsonSrcChange()">
</textarea>
</div>
<div id="json_result_box" class="uk-width-10-10" style="overflow: auto;">
<div class="uk-width-1-1">
<pre style="margin:0;"><code v-html="jsonResult_header" id="json_result_header"></code></pre>
</div>
<div class="uk-width-1-1" style="margin-top: 10px;">
<pre style="margin:0;"><code v-html="jsonResult" id="json_result"></code></pre>
</div>
</div>
</div>
<script>
(function(global){"use strict";var _Base64=global.Base64;var version="2.3.2";var buffer;if(typeof module!=="undefined"&&module.exports){try{buffer=require("buffer").Buffer}catch(err){}}var b64chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var b64tab=function(bin){var t={};for(var i=0,l=bin.length;i<l;i++)t[bin.charAt(i)]=i;return t}(b64chars);var fromCharCode=String.fromCharCode;var cb_utob=function(c){if(c.length<2){var cc=c.charCodeAt(0);return cc<128?c:cc<2048?fromCharCode(192|cc>>>6)+fromCharCode(128|cc&63):fromCharCode(224|cc>>>12&15)+fromCharCode(128|cc>>>6&63)+fromCharCode(128|cc&63)}else{var cc=65536+(c.charCodeAt(0)-55296)*1024+(c.charCodeAt(1)-56320);return fromCharCode(240|cc>>>18&7)+fromCharCode(128|cc>>>12&63)+fromCharCode(128|cc>>>6&63)+fromCharCode(128|cc&63)}};var re_utob=/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;var utob=function(u){return u.replace(re_utob,cb_utob)};var cb_encode=function(ccc){var padlen=[0,2,1][ccc.length%3],ord=ccc.charCodeAt(0)<<16|(ccc.length>1?ccc.charCodeAt(1):0)<<8|(ccc.length>2?ccc.charCodeAt(2):0),chars=[b64chars.charAt(ord>>>18),b64chars.charAt(ord>>>12&63),padlen>=2?"=":b64chars.charAt(ord>>>6&63),padlen>=1?"=":b64chars.charAt(ord&63)];return chars.join("")};var btoa=global.btoa?function(b){return global.btoa(b)}:function(b){return b.replace(/[\s\S]{1,3}/g,cb_encode)};var _encode=buffer?buffer.from&&buffer.from!==Uint8Array.from?function(u){return(u.constructor===buffer.constructor?u:buffer.from(u)).toString("base64")}:function(u){return(u.constructor===buffer.constructor?u:new buffer(u)).toString("base64")}:function(u){return btoa(utob(u))};var encode=function(u,urisafe){return!urisafe?_encode(String(u)):_encode(String(u)).replace(/[+\/]/g,function(m0){return m0=="+"?"-":"_"}).replace(/=/g,"")};var encodeURI=function(u){return encode(u,true)};var re_btou=new RegExp(["[À-ß][€-¿]","[à-ï][€-¿]{2}","[ð-÷][€-¿]{3}"].join("|"),"g");var cb_btou=function(cccc){switch(cccc.length){case 4:var cp=(7&cccc.charCodeAt(0))<<18|(63&cccc.charCodeAt(1))<<12|(63&cccc.charCodeAt(2))<<6|63&cccc.charCodeAt(3),offset=cp-65536;return fromCharCode((offset>>>10)+55296)+fromCharCode((offset&1023)+56320);case 3:return fromCharCode((15&cccc.charCodeAt(0))<<12|(63&cccc.charCodeAt(1))<<6|63&cccc.charCodeAt(2));default:return fromCharCode((31&cccc.charCodeAt(0))<<6|63&cccc.charCodeAt(1))}};var btou=function(b){return b.replace(re_btou,cb_btou)};var cb_decode=function(cccc){var len=cccc.length,padlen=len%4,n=(len>0?b64tab[cccc.charAt(0)]<<18:0)|(len>1?b64tab[cccc.charAt(1)]<<12:0)|(len>2?b64tab[cccc.charAt(2)]<<6:0)|(len>3?b64tab[cccc.charAt(3)]:0),chars=[fromCharCode(n>>>16),fromCharCode(n>>>8&255),fromCharCode(n&255)];chars.length-=[0,0,2,1][padlen];return chars.join("")};var atob=global.atob?function(a){return global.atob(a)}:function(a){return a.replace(/[\s\S]{1,4}/g,cb_decode)};var _decode=buffer?buffer.from&&buffer.from!==Uint8Array.from?function(a){return(a.constructor===buffer.constructor?a:buffer.from(a,"base64")).toString()}:function(a){return(a.constructor===buffer.constructor?a:new buffer(a,"base64")).toString()}:function(a){return btou(atob(a))};var decode=function(a){return _decode(String(a).replace(/[-_]/g,function(m0){return m0=="-"?"+":"/"}).replace(/[^A-Za-z0-9\+\/]/g,""))};var noConflict=function(){var Base64=global.Base64;global.Base64=_Base64;return Base64};global.Base64={VERSION:version,atob:atob,btoa:btoa,fromBase64:decode,toBase64:encode,utob:utob,encode:encode,encodeURI:encodeURI,btou:btou,decode:decode,noConflict:noConflict};if(typeof Object.defineProperty==="function"){var noEnum=function(v){return{value:v,enumerable:false,writable:true,configurable:true}};global.Base64.extendString=function(){Object.defineProperty(String.prototype,"fromBase64",noEnum(function(){return decode(this)}));Object.defineProperty(String.prototype,"toBase64",noEnum(function(urisafe){return encode(this,urisafe)}));Object.defineProperty(String.prototype,"toBase64URI",noEnum(function(){return encode(this,true)}))}}if(global["Meteor"]){Base64=global.Base64}if(typeof module!=="undefined"&&module.exports){module.exports.Base64=global.Base64}else if(typeof define==="function"&&define.amd){define([],function(){return global.Base64})}})(typeof self!=="undefined"?self:typeof window!=="undefined"?window:typeof global!=="undefined"?global:this);
</script>
<script>
function hideIcon() {
$('.uk-icon-angle-right').hide();
$('.uk-icon-angle-down').hide();
}
function showIcon() {
$('.uk-icon-angle-right').show();
$('.uk-icon-angle-down').show();
}
function fold(icon) {
icon.classList.remove('uk-icon-angle-down')
icon.classList.add('uk-icon-angle-right')
icon.setAttribute('onClick', 'javascript: unFold(this)')
icon.childNodes[0].style.display = 'inline'
icon.nextSibling.style.display = 'none'
}
function unFold(icon) {
icon.classList.remove('uk-icon-angle-right')
icon.classList.add('uk-icon-angle-down')
icon.setAttribute('onClick', 'javascript: fold(this)')
icon.childNodes[0].style.display = 'none'
icon.nextSibling.style.display = 'inline'
}
var vm = new Vue({
el: "#content",
data: {
reLink: /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig,
cursorPosition: '?',
jsonSrc: ``,
jsonResultTemp:[],
jsonObject: undefined,
jsonResult_header: '',
jsonResult: '',
tab: ' ',
keyEnd: '"</span>: '
},
mounted: function () {
if (localStorage.jwt_jsonSrc) {
this.jsonSrc = localStorage.jwt_jsonSrc
}
this.jsonSrcChange()
},
methods: {
isArray: function (obj) {
return obj && typeof obj === 'object' && typeof obj.length === 'number' && !(obj.propertyIsEnumerable('length'))
},
jsonLinkWarpper: function (str) {
return str.replace(this.reLink, '<a class="json_link" target="_blank" href="$1">$1</a>');
},
genKey: function (key, depth) {
this.jsonResultTemp.push("<br><span class='json_key'>")
this.jsonResultTemp.push(this.tab.repeat(depth + 1))
this.jsonResultTemp.push("\"")
this.jsonResultTemp.push($('<div/>').text(key).html())
this.jsonResultTemp.push(this.keyEnd)
},
genValue: function (obj, depth) {
if (!this.jsonResultTemp[this.jsonResultTemp.length - 1].endsWith(this.keyEnd)) { // 冒号后面不换行
this.jsonResultTemp.push('<br>')
this.jsonResultTemp.push(this.tab.repeat(depth))
}
var type = obj === null ? 'null' : typeof obj
this.jsonResultTemp.push('<span class="json_')
this.jsonResultTemp.push(type)
this.jsonResultTemp.push('">')
if (type === 'string') {
this.jsonResultTemp.push('"')
this.jsonResultTemp.push(this.jsonLinkWarpper($('<div/>').text(obj === null ? 'null' : obj).html()))
this.jsonResultTemp.push('"')
} else {
this.jsonResultTemp.push(obj === null ? 'null' : obj)
}
this.jsonResultTemp.push('</span>,')
},
genStart: function (start, depth, itemCount) {
if (this.jsonResultTemp.length > 0
&& !this.jsonResultTemp[this.jsonResultTemp.length - 1].endsWith(this.keyEnd)) { // 冒号后面不换行
this.jsonResultTemp.push('<br>')
this.jsonResultTemp.push(this.tab.repeat(depth))
}
this.jsonResultTemp.push(start)
if (depth > this.defaultFold || itemCount === 0) {
this.jsonResultTemp.push('<i class="uk-icon-angle-right" onClick="unFold(this)">'
+ '<span class="fold_icon">...' + itemCount + '</span>'
+ '</i>'
+ '<span class="foldContent" style="display:none">')
} else {
this.jsonResultTemp.push('<i class="uk-icon-angle-down" onClick="fold(this)">'
+ '<span class="fold_icon" style="display:none;">...' + itemCount + '</span>'
+ '</i>'
+ '<span class="foldContent">')
}
},
genEnd: function (end, depth) {
this.deletLastComma()
this.jsonResultTemp.push('<br>')
this.jsonResultTemp.push(this.tab.repeat(depth))
this.jsonResultTemp.push('</span>') // <span class="foldContent">
this.jsonResultTemp.push(end)
this.jsonResultTemp.push(',')
},
deletLastComma: function () {
var old = this.jsonResultTemp.pop()
var index = old.lastIndexOf(',')
var index1 = old.lastIndexOf('{')
var index2 = old.lastIndexOf('[')
if (index > index1 && index > index2) {
this.jsonResultTemp.push(old.substring(0, index))
this.jsonResultTemp.push(old.substring(index + 1))
return true
}
this.jsonResultTemp.push(old)
return false
},
genResult: function (obj, depth) {
if (this.isArray(obj)) {
this.genStart('[', depth, obj.length)
for(var i = 0; i < (this.arraySampling ? Math.min(obj.length, 1) : obj.length); i++) {
this.genResult(obj[i], depth + 1)
}
this.genEnd(']', depth)
return
}
if ((typeof obj) === 'object' && obj !== null) {
this.genStart('{', depth, Object.keys(obj).length)
for (key in obj) {
this.genKey(key, depth)
this.genResult(obj[key], depth + 1)
}
this.genEnd('}', depth)
return
}
this.genValue(obj, depth)
},
jsonSrcChange: function () {
if (this.jsonSrc === '') {
return
}
try {
jwtSrc = this.jsonSrc.replace("Bearer ", "").split(".")
this.jsonObject = JSON.parse(Base64.decode(jwtSrc[0]))
this.jsonResultTemp = []
this.genResult(this.jsonObject, 0)
this.deletLastComma()
this.jsonResult_header = this.jsonResultTemp.join("")
this.jsonObject = JSON.parse(Base64.decode(jwtSrc[1]))
this.jsonResultTemp = []
this.genResult(this.jsonObject, 0)
this.deletLastComma()
this.jsonResult = this.jsonResultTemp.join("")
localStorage.jwt_jsonSrc = this.jsonSrc
} catch (e) {
this.jsonResult_header = ''
this.jsonResult = e.message
}
},
traverseChildren: function (element, func, depth) {
for(var i = 0; i < element.childNodes.length; i++){
this.traverseChildren(element.childNodes[i], func, depth + 1)
}
func(element, depth)
}
}
})
</script>
<script>
$(function() {
$('#json_result_box').scroll(function() {
if ($('#json_result_box').scrollTop() > 400)
$('div.go-top').show();
else
$('div.go-top').hide();
});
$('div.go-top').click(function() {
$('#json_result_box').animate({scrollTop: 0}, 400);
});
});
</script>

64
proxy.pac Normal file
View File

@ -0,0 +1,64 @@
// var proxy = "PROXY localhost:7890";
var proxy = "SOCKS5 localhost:7890";
function FindProxyForURL(url, host) {
if (shExpMatch(host,"*qunar*")
|| shExpMatch(host,"*.cn")
|| shExpMatch(host,"*baidu*")
|| shExpMatch(host,"*bdstatic*")
|| shExpMatch(host,"*aliyun*")
|| shExpMatch(host,"*alicdn*")
|| shExpMatch(host,"*mmstat*")
|| shExpMatch(host,"*alipay*")
|| shExpMatch(host,"*99.com")
|| shExpMatch(host,"*.qq.com")
|| shExpMatch(host,"*.99.com")
|| shExpMatch(host,"101.com")
|| shExpMatch(host,"*.101.com")
|| shExpMatch(host,"*.sdp")
|| shExpMatch(host,"*.nd")
|| shExpMatch(host,"*.ndaeweb.com")
|| shExpMatch(host,"*.hdslb.com")
) {
return "DIRECT";
}
if (shExpMatch(host,"*google*")
|| shExpMatch(host,"*chrome*")
|| shExpMatch(host,"*gstatic*")
|| shExpMatch(host,"*youtube*")
|| shExpMatch(host,"*ytimg*")
|| shExpMatch(host,"*ggpht*")
|| shExpMatch(host,"*facebook*")
|| shExpMatch(host,"*fbcdn*")
|| shExpMatch(host,"*twitter*")
|| shExpMatch(host,"*twimg*")
|| shExpMatch(host,"*gist*")
|| shExpMatch(host,"*github*")
|| shExpMatch(host,"*wikipedia*")
|| shExpMatch(host,"*stackoverflow*")
|| shExpMatch(host,"*wikimedia*")
|| shExpMatch(host,"*xvideos*")
|| shExpMatch(host,"*porn*")
|| shExpMatch(host,"*.phncdn.com")
|| shExpMatch(host,"*.trafficjunky.net")
|| shExpMatch(host,"*sis001*")
|| shExpMatch(host,"*rubygems*")
|| shExpMatch(host,"*weather*")
|| shExpMatch(host,"*amazonaws*")
|| shExpMatch(host,"*doubleclick.net")
|| shExpMatch(host,"*.doubleclick.net")
|| shExpMatch(host,"*cloudfront.net")
|| shExpMatch(host,"*shadowsocks.com")
|| shExpMatch(host,"*.io")
|| shExpMatch(host,"*.binance.com")
|| shExpMatch(host,"*.bnbstatic.com")
|| shExpMatch(host,"ntotheblock.com")
|| shExpMatch(host,"disqus.com")
|| shExpMatch(host,"*.disqus.com")
) {
return proxy;
}
return "DIRECT";
}