菠HiFi:何处觅高清无损音乐资源?评仙籁MU与QQ音乐“仙籁至臻”
前几天在菠萝的随笔性质连载专栏——Hifi碎碎念的评论里,有观众在评论里就问到,烧油们都是上哪去找高清音乐资源的?
确实,过去烧油们手头上的音乐资源,往往来自烧油自己从CD抓轨,并通过网络进行相互分享。而今,随着各种云音乐APP的兴起,尤其是各种便携播放器和台式数播也都纷纷通过安卓系统里运行的各种云音乐APP,摇身一变成为网播前端,并且轻松坐享海量的音乐资源。
其中Apple Music固然是当中最具影响力的。但不善于,只使用国区的小伙伴来说,AM的音乐资源确实也谈不上全面,华语流行歌曲相对匮乏。而且AM上大多数标签“无损”的,实际也只有24bits/48kHz。很多烧油对此也是颇有微词。
早在8月份时,仙籁就公布了与国内最大的云音乐平台QQ音乐合作,共同打造“仙籁至臻”会员服务,让仙籁产品的用户可以直接在运行自家VitOS系统的播放器上使用QQ音乐,以及“仙籁至臻”专区的高清无损Hires音乐资源。
其实菠萝本身可是坚定的AM党,不过正好入了台仙籁MU嘛……几经思量后,还是选择先试一下这个“仙籁至臻”到底够不够Hifi?
有小伙伴这时就会跳出来说了,QQ音乐而已嘛,我熟啊!
是,只要是安卓系统的,便携播放器可以直接用手机版的,哪怕是数播/网播也可以跑车机版的QQ音乐。甚至可以直接在手机上运行QQ音乐,然后通过DLAN或AirPlay推流到播放器上。
那跟仙籁的这个“仙籁至臻”有啥区别?
区别还蛮大的,甚至可以说从根本上就是2个不同层级的东西。
首先,QQ音乐本身就是通过API的方式,直接嵌入到MU运行的VitOS系统上,而手机控制端APP【VitOS Orbiter】实际只是起到无线控制面板的作用。当然,同样被嵌入的云音乐还不只QQ音乐,包括TIDAL、Spotify Connect、Amazon Music、HIGHRESAUDIO等这些国际上知名的平台也都有嵌入。但就实际使用体验来说,菠萝我认为对于国内用户来说,首选还是QQ音乐。
其次是在码率方面,常规的QQ音乐绿钻VIP会员在音质选择方面,除了标准音质外,也只有HQ高品质和SQ无损品质这两种,其中后者一般也只有44.1/48kHz的编码频率。相比之下,仙籁至臻除了可以提供192kHz品质的高清无损音乐外,还包括了具备更强空间音效效果的臻品全景声。
有小伙伴就纳闷了,为什么在一般的QQ音乐上会看不到这2个音质选项呢?
因为它们其实都是仙籁至臻会员专享的,并且运行的机制会跟常规的有很大区别。
按照仙籁跟QQ音乐官方公布的信息,仙籁至臻音质实际上是直接从QQ音乐的服务器上下载源码率,之后再由仙籁MU或其他的硬件来负责解码转换。因为不是使用串流的方式传输,因此在过程中就不会存在压缩以及音质的损失。
正巧【仙籁HiFi测试音乐】专区里有不少菠萝也很熟悉的曲目,所以直观地进行了一些比较,来看一下仙籁至臻到底是不是“真·无损、真·高清”?
首先就是《鼓诗》。菠萝手头上的是DSD64版本,而仙籁至臻则提供192kHz/24bits版本、实际码流达到4456kbps。测试使用ONIX的Miracle套机来充当耳放,用于驱动森海的HD660S。
就信息量来说,虽说DSD版本还是会占优,但两者的差距并不明显,只有在刻意去进行AB对比的情况下,才能在鼓皮抖动的残响细节中能感知。而且仙籁至臻的版本在动态和瞬态方面几乎没有什么损失,其根本原因,是通过臻品母带加速优化算法和网格传输路径优化等先进技术,从而实现真实母带原音的效果。
鹭巣诗郎的《Kanon D-dur(Quartet)》本身就是菠萝常用的试听曲目,手头上的是CD音源,通过抓轨的方式将WAV文件导入仙籁的本地硬盘曲库。而仙籁至臻则提供全景声版本的44.1kHz/16bits版本。作为一首弦乐四重奏曲目,仙籁提供的版本有着相当明晰的4把提琴结像定位,而且即便到了中后段的重奏部分,依然能有条不紊地呈现每一把提琴自身的形态。也许是抓轨本身导致的损失,同样由MU回放的本地曲库的同一首曲目,反而会显得毛躁一些,反而不如仙籁至臻那么顺滑。当然,我也试过在另一台支持CD唱盘前端的设备上听,就算我很仔细的比对了,但依然很难区分仙籁至臻跟CD原盘之间的差距,最少盲听是完全分不出来。
我还在仙籁专区里找到了卡拉扬和穆特版本的《四季》,用来跟手头上的FLAC版本进行比较。这里我用到了飞傲的SP3音箱来直接连接到MU上,避免了额外接耳放所带来的影响。仙籁专区提供的虽然只有全景声版本,在码率方面跟本地的FLAC并没有区别,但在声场方面,仙籁至臻的似乎更开阔一些,尤其是中间穆特solo的那一段,结像的立体感会更凸显一些。
当然,我也特意拿来跟Apple Music做了比较。
MU虽然不支持运行AM,但我手头上另一台数播DMP-A6是支持的,我把两者都通过同轴输出的方式,由ONIX Miracle负责解码和放大,并使用平板大耳HE560来进行回放。其中测试了DG出品的穆特与John Williams合作的这张专辑。AM上提供的是杜比全景声版本,而仙籁至臻则是更高一级的192kHz/24bits版本。回放结果来看,最少在素质方面,仙籁至臻的显得更加通透一些,特别是穆特的小提琴线条感会更强烈些。相比之下AM的则会闷一些,但声场左右展开的幅度要稍大一些。何况在乐感方面,MU哪怕在数字信号直出效果来看,也会比A6更甜润一些,后者始终信号会显得有点小毛躁,而且偏直白风格些。所以我也纠结要不要给A6换线电试一下。
然后还有小野丽莎翻唱的JAZZ版本《Fly Me to The Moon》,AM只有44.1kHz/16bit的无损版本,而仙籁至臻则提供了192kHz/24bit的高清无损版本。首先在风格方面,基于MU的仙籁至臻就明显胜出了,那种爵士乐的摇摆感觉,加上小野丽莎磁性的声线,都非常的醉人。而AM配搭A6则显得生硬不少。何况仙籁至臻在细节方面也会有显著优势,伴奏吉他琴弦的泛音,以及镲片的沙沙感都会更加强烈。
但仙籁至臻当下还存在2个比较显著的问题。
一是80元的仙籁至臻会员月租确实有点贵,不过对于购买MU的用户,仙籁直接提供了一年的仙籁至臻会员免费使用,堪称是相当良心了。不过同比之下Apple Music个人月租才11元,哪怕像菠萝我这样为了多台设备同时使用而开通了家庭账号,也不过17元而已,因此后续的月费投入还是一笔不小的开支。
当然,如果是跟索尼精选比,那仙籁至臻还是相当便宜的。
二是目前仙籁至臻的曲目库还不够丰富,其中能提供192kHz音质的并不多。所幸只要开通了仙籁至臻会员,一般的绿钻VIP会员的曲目也是可以免费听的,所以也不亏。何况仙籁也承诺,后续会加大力度扩充仙籁至臻专区的曲目库,这点我觉得还是可以期待一下的。
反正对菠萝我来说,多了仙籁至臻这个音乐资源渠道,也算是很好地补充了AM的不足,还是相当不错的。何况QQ音乐本身在流畅度、华语歌曲丰富程度方面也比AM有优势,眼下仙籁至臻更是在音质方面能超越AM,就更没有不选择它的理由了!
如何在OneFlow中新增算子
撰文|姚迟、郑泽康
本文将以开发一个 leaky_relu(准确说是 leaky_relu_yzh op,因为 master 分支的 leaky_relu 组合了其它知识点)为例介绍如何在 OneFlow 中新增算子(https://github.com/Oneflow-Inc/oneflow/pull/8350)。
1
op 与 kernel
op 与 kernel 是两个有关联的概念。op 是逻辑上的算子,包含 OneFlow Compiler 在构建计算图时所需要的必要信息,如输入、输出形状,哪些张量需要自动求导等信息。有了 op 中的信息,OneFlow Compiler 就可以构建计算图并依据计算图做资源申请、构建等操作(如根据张量的输入输出大小申请内存), 但是 op 中不包含具体的处理数据的逻辑。
在真正需要处理数据时,OneFlow Runtime 会启动 kernel 完成计算,所以 kernel 中包含了具体处理数据的逻辑。对于一个逻辑上的 op,OneFlow Runtime 会根据数据类型、硬件设备(比如是 CPU 还是 CUDA)的具体情况,选择启动不同的 kernel。
OneFlow 中的系统 op 与 user op
在 OneFlow 系统中存在两类算子(op):系统 op 和 user op。
系统 op 定义在:oneflow/core/operator/ 目录, 对应的 kernel 实现在:oneflow/core/kernel 目录。系统 op 是对构图、流水等系统性能较为关键的一些 op。
除极少数 op 属于系统 op 外,大多数 op 都是 user op,这些 user op 和用户模型业务逻辑相关。OneFlow user op 的定义及 kernel 实现分别在 oneflow/user/ops 和 oneflow/user/kernels 目录下。
目前 OneFlow 已实现了丰富的算子库,但是当已有的算子库无法满足搭建模型的需求时,就需要新增算子。本文介绍的新增算子指的是新增 user op。
ODS 与 TableGen
TableGen(https://llvm.org/docs/TableGen/index.html) 是一个代码生成工具,简单而言,它读取并解析一个 .td 格式(语法接近 C++ 模板)的文件,然后交给 TableGen 后端
(https://llvm.org/docs/TableGen/BackEnds.html)生成另外格式的语言。
MLIR 基于 TableGen 制定了一套算子定义规范ODS(https://mlir.llvm.org/docs/OpDefinitions/)以及对应的后端 OpDefinitionsGen(https://github.com/llvm/llvm-project/blob/main/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp。)
OneFlow 在 ODS 的基础上,实现了 TableGen OneFlow 后端(https://github.com/Oneflow-Inc/oneflow/tree/master/tools/oneflow-tblgen),并使用它来定义 OneFlow user op。
因此,OneFlow 的 user op 定义写在 OneFlowUserOps.td 文件中。
2
在 OneFlow 中开发一个新的 user op,主要分为以下4步:
- 定义 op
- 实现 kernel 计算逻辑
- 导出 functional 接口
- 实现用于求导的反向逻辑
定义 op
定义 op 指的是,对 op 的名称,op 的输入、输出数据类型和 op 的属性进行声明。OneFlow 遵循 MLIR 的 ODS(Operation Definition Specification)(https://mlir.llvm.org/docs/OpDefinitions/) 实现了自己的 MLIR OneFlow Dialect。在算子定义方面,这样做的好处是,各种推导函数和序列化/反序列化的接口都可以委托给 ODS,降低了人工手写出错的概率,后续优化、格式转化等流程可以更灵活。
定义一个 OneFlow user op,主要包括 5 个部分,分别是:
- op class
- 输入 input
- 输出 output
- 属性 attrs
- 导出并实现推导接口
op class
可以在 oneflow/ir/include/OneFlow/OneFlowUserOps.td 查看 op 定义的源码。
以 def 关键字开头定义一个 op,该 op 继承 OneFlow_BaseOp,同时指定 OneFlow_BaseOp 的模版参数。模版参数依次为 op type name、Trait (https://mlir.llvm.org/docs/Traits/)列表。
其中 \”leaky_relu_yzh\” 是指定的 op type name。每个 op 都需要指定一个全局唯一的 op type name 作为全局标识符。
第二个模板参数是一个 list([…]),其中的每一项都是一个 Trait,OneFlow 中常用的有:
- NoSideEffect 表示该算子无副作用(即不会改变内存、网络、管道、磁盘等的系统状态),这个特性可以指导某些优化操作
- NoGrad 表示该算子在数学上没有梯度(不可导)
- CpuOnly 表示该算子只支持在 CPU 设备上执行
- SupportNonContiguous 表示该算子是否支持 NonContiguous 张量(关于 Contiguous Tensor 的概念,可以参考 PyTorch Internals 中的相关内容 )
输入 input 与输出 output
通过重写 input 域来定义 op 的输入,比如
定义了一个输入张量 x。输入的格式为 输入类型:$name。
输入类型目前包括:
- OneFlow_Tensor
- Variadic<OneFlow_Tensor>:指可变 tensor,比如 concat op,支持 concat 可变个数的 tensor。
- Optional<OneFlow_Tensor>:表示这个 tensor 是可选的,既可以有也可以没有,比如 conv op 中的 add_output。
一个 op 也可以定义多个输入,比如:
通过重写 output 域来定义 op 的输出,比如下面定义了 2 个输出张量:
属性 attrs
通过重写 attrs 域定义 op 的属性,比如定义 dropout (https://oneflow.readthedocs.io/en/master/functional.html#oneflow.nn.functional.dropout)中的 rate 属性:
它表示名为 $rate 的类型是 F32Attr,默认值是 0.。这里也可以不指定默认值:
I32Attr、F32Attr、BoolAttr、StrAttr、I32ArrayAttr 等常见基础数据类型定义在 OpBase.td
(https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/IR/OpBase.td#L1077-L1086)中。
OneFlow 自定义数据类型,如 ShapeAttr、DTArrayAttr 等定义在 OneFlowBase.td
(https://github.com/Oneflow-Inc/oneflow/blob/master/oneflow/ir/include/OneFlow/OneFlowBase.td#L27-L35)中。
导出并实现推导接口
还有一些其它域,用于指定是否生成对应的接口。这些接口往往是构建计算图过程中的推导接口。
比如 shape 推导(根据输入的 shape 推导输出的推导)、data type 推导、SBP 推导等。
OneFlow-TableGen 仅负责生成这些函数的接口,开发者需要在其自动生成的 cpp 文件中实现这些接口。默认情况不会生成下列任何接口,开发者需要显式指定需要生成哪些接口。
一般常用的是下面几个:
了解完上面这些概念和用法后,可以开始修改 oneflow/ir/include/OneFlow/OneFlowUserOps.td文件。
leaky_relu_yzh op 完整的定义见 这里(https://github.com/Oneflow-Inc/oneflow/blob/7ab4b0f08c86a6f8af08b44daa510725942288fb/oneflow/ir/include/OneFlow/OneFlowUserOps.td#L8418-L8433)。
在 OneFlowUserOps.td 中新增Op定义之后,重新 make 后会自动在 build 目录下的 oneflow/core/framework/ 目录下生成文件以下几个文件:
- op_generated.h:由解析 .td 文件生成的 op C++ 类
- op_generated.cpp:由解析 .td 文件生成的 op 注册代码(包含调用 REGISTER_USER_OP 宏的代码)
之后需要做的就是在 oneflow/user/ops (https://github.com/Oneflow-Inc/oneflow/tree/master/oneflow/user/ops)目录下新加一个 cpp 文件,用于实现 op 的接口。
比如 leaky_relu_yzh 对应的文在 oneflow/user/ops/leaky_relu_yzh_op.cpp(https://github.com/Oneflow-Inc/oneflow/blob/7ab4b0f08c86a6f8af08b44daa510725942288fb/oneflow/user/ops/leaky_relu_yzh_op.cpp#L21-L79),实现了推导逻辑张量、推导物理张量、推导 SBP 信息以及推导输出数据类型各接口。
实现 Kernel 逻辑
op 的计算支持多种设备(如 CPU、GPU、DCU 等),所以要分别实现计算逻辑。
相关代码:
- Leaky ReLU CPU Kernel
- (https://github.com/Oneflow-Inc/oneflow/blob/7ab4b0f08c86a6f8af08b44daa510725942288fb/oneflow/user/kernels/leaky_relu_yzh_kernel.cpp)
- Leaky ReLU GPU KernelCPU
- (https://github.com/Oneflow-Inc/oneflow/blob/7ab4b0f08c86a6f8af08b44daa510725942288fb/oneflow/user/kernels/leaky_relu_yzh_kernel.cu)
计算逻辑
在 OneFlow 中实现 kernel, 必须定义一个继承自 oneflow::user_op::OpKernel 的类,并重写其中的虚函数。在以上代码中,重写了 Compute 与 AlwaysComputeWhenAllOutputsEmpty 两个虚函数,它们的意义分别是:
- Compute 必须重写,在其中实现具体的运算逻辑
- AlwaysComputeWhenAllOutputsEmpty 必须重写,对于绝大多数 op 而言,直接返回 false 即可。对于极少数内部需要维护状态,即使输出为空也需要调用 kernel 进行计算的 op 而言,应该返回 true
Compute 方法中通过调用 user_op::KernelComputeContext* ctx 中的接口,可以获取输入张量、输出张量、attr 具体的数据,再按照算子的算法逻辑对它们进行处理。以下是对 CpuLeakyReluKernel::Compute 处理逻辑的解读:
- 首先取得 \”x\”,\”y\” 两个 Tensor。传入Tensor4ArgNameAndIndex的字符串要和之前在OneFlowUserOps.td设置的名称一致
- 获取 x 的元素个数,以便后续用于 for 循环进行计算
- 获取属性 alpha
- 进入次数为 elem_cnt 的 for 循环,将结果写入
注册 Kernel
实现 kernel 类后,需要调用 REGISTER_USER_KERNEL 注册。
这里会调用REGISTER_USER_KERNEL宏,包括以下信息:
- op type name:为哪个 op 注册 kernel
- SetCreateFn<T>():该模板方法的模板参数 T,就是我们实现的 kernel 类,OneFlow Runtime 将使用它创建 kernel 对象。
- SetIsMatchedHob:因为一个 op 可能有多个 kernel,要想根据物理设备及数据格式的不同而选择不同的 kernel 进行计算,就需要调用 SetIsMatchedHob 进行设置。该方法接受一个表达式,表达式为 true 时,OneFlow 将调用该 kernel 完成计算。以上代码的匹配逻辑是:当硬件设备为 cpu,且 y 的数据类型和 dtype 一致时,选择调用注册的 kernel 类(CpuLeakyReluYZHKernel<dtype>)。
GPU 计算逻辑
CUDA 编程基础知识入门可以参考:
- 视频:CUDA 的由来(https://www.bilibili.com/video/BV1Mb4y1p7BG)
- 视频:CUDA 的入门小程序(https://www.bilibili.com/video/BV1bF411s76k)
- 视频:线程层级(https://www.bilibili.com/video/BV1MZ4y127Sq)
不过以上的视频都无法替代自己认真学习官方资料:CUDA C Programming Guide(https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html)
了解了 CUDA 的基础知识,就不难理解 leaky_relu CUDA 版本的实现。
首先定义了 leaky_relu 前向运算的 CUDA 核函数
其中调用了宏 CUDA_1D_KERNEL_LOOP (https://github.com/Oneflow-Inc/oneflow/blob/master/oneflow/core/device/cuda_util.h#L91-L94)进行运算
在 Compute 函数中,调用了 RUN_CUDA_KERNEL (也是定义在 cuda_util.h 这个文件中)这个宏启动核函数。
对应的 GPU kernel 类的实现见:
https://github.com/Oneflow-Inc/oneflow/blob/7ab4b0f08c86a6f8af08b44daa510725942288fb/oneflow/user/kernels/leaky_relu_yzh_kernel.cu#L32-L49
其中用到了启动 kernel 的宏 RUN_CUDA_KERNEL,它的定义是:
- 第一个参数是核函数名字
- 第二个参数是 device context,后续获取对应的 cuda_stream
- 第三个参数是要启动的线程数量,会根据线程数量来计算所需的 Block 数目。
因为 leaky relu 是 elementwise 运算,各个元素互不影响,所以我们启动了 elem_cnt 个线程。
后续的注册与 CPU 版本类似,这里不再赘述。直接参考以下代码即可:
https://github.com/Oneflow-Inc/oneflow/blob/7ab4b0f08c86a6f8af08b44daa510725942288fb/oneflow/user/kernels/leaky_relu_yzh_kernel.cu#L51-L62
可以看到不同设备类的 Compute 中大部分代码是重复的。一种更优的代码组织方式是用一个 .cpp 文件完成 kernel 和注册的逻辑,.cu 文件编写 GPU Kernel 函数和 GPU 模板特化的代码,.h 文件用于定义和编写注册宏。可参考 dim_gather_kernel_*
(https://github.com/Oneflow-Inc/oneflow/tree/master/oneflow/user/kernels)中的代码。
OneFlow 为了适配多种设备,还提供了 Primitive 组件,可以参考:Primitive PR(https://github.com/Oneflow-Inc/oneflow/pull/6234)
导出 functional 接口
关于 functional 接口层的详细介绍在这里: https://github.com/Oneflow-Inc/oneflow/wiki/Functional-Interface
概括而言,functional 层起到了“上接 Python,下联 C++”的作用:
因此,在上文定义 op 和注册 kernel 后,需要为算子导出 functional 接口,才能使用户通过 Python 代码调用该算子。
导出 functional 接口分为以下几个步骤:
- 实现对应的 functor 并注册
- 在 oneflow/core/functional/functional_api.yaml 中添加接口描述
实现对应的 functor 并注册
对于 leaky_relu_yzh op,在 activation_functor.cpp
(https://github.com/Oneflow-Inc/oneflow/blob/7ab4b0f08c86a6f8af08b44daa510725942288fb/oneflow/core/functional/impl/activation_functor.cpp#L391-L421) 中,对其进行定义:
- 在构造函数里,构造了 leaky_relu 这个op
- 实现 operator() 重载运算符,通过 Dispatch 调用构造好的 op,并分别传入输入,属性
类似的我们也给 LeakyReluGrad 导出 functional 接口,以便后续编写求导逻辑使用。
最后我们需要注册到 Functional Library:
https://github.com/Oneflow-Inc/oneflow/blob/7ab4b0f08c86a6f8af08b44daa510725942288fb/oneflow/core/functional/impl/activation_functor.cpp#L610-L611
通过 m.add_functor 注册后的 functor,可以在 C++ 层使用,如通过 functional::LeakyRelu 就可以调用 LeakyReluFunctor。
在 functional_api.yaml 中添加接口描述
functional 通过解析 yaml 配置文件,在 build 过程中自动帮我们生成接口。
在functional_api.yaml
(https://github.com/Oneflow-Inc/oneflow/blob/master/oneflow/core/functional/functional_api.yaml)文件中,编写相关配置。
https://github.com/Oneflow-Inc/oneflow/pull/8350/files#diff-4b35c1dcdbae81b75439ba570bc149554ca85b83757430613fcb612ae25972afR572-R579
- 其中 name 表示导出到 Python 接口后函数的名字,比如导出后在 Python 下使用就是
- signature 用于描述接口原型及 C++ 代码的对应关系。=> 左边的为原型;=> 右边为对应的 Functional Library 中的名字。这里LeakyRelu 和前面导出时指定的字符串是一致的。
- bind_python,表示这个接口是否需要绑定 Python 接口 。比如下面的 leaky_relu_grad,我们不会在 Python 层用到(但会在 C++ 层求导使用),所以设置为 False。
完成以上工作后,新增的算子已经支持正向运算,编译好代码便可以进行如下简单的测试:
但是,还需要注册反向,才能支持反向传播。我们也先将反向需要的 LeakyReluGrad 导出为 functional 接口。
反向传播的本质就是高数中的链式法则,只不过 Autodiff 将链式法则变得模块化、易复用。
可以先阅读 CSC321 Lecture 10: Automatic Differentiation(https://www.cs.toronto.edu/~rgrosse/courses/csc321_2018/slides/lec10.pdf )了解 autodiff 的基本概念。
从逻辑上而言,一个算子在反向过程中能够求导数,一般需要以下信息:
- 正向过程中的输入、输出
- 正向过程的 attr
- 反向过程中上一层(正向过程中的下一层)传递过来的正向输出的梯度
未来 Graph 模式和 Eager 模式下的反向逻辑会合并,但目前还是需要分别注册。
为 Eager 模式注册反向
求导部分在 oneflow/core/autograd/gradient_funcs/activation.cpp
(https://github.com/Oneflow-Inc/oneflow/pull/8350/files#diff-36aeebf7fd5a8b88bd5af87774e7b0b4f76fed42cfb75044d6eebdfe65628347R213-R253)完成
主要有以下几部分:
- LeakyReluYZHCaptureState :用于存储数据的结构体
这是一个简单的结构体,继承自 AutoGradCaptureState,用于存储 op 的属性,以便于后续求导。
- LeakyReluYZH 类:继承自 OpExprGradFunction 的类。需要重写三个函数:Init、Capture、Apply。
- Init:做的是一些初始化的工作,可以根据前向 op 的配置,来初始化属性。
- Capture:用于捕捉前向的 Tensor,属性,用于后续的求导。
以 LeakyReluYZH 为例子,我们需要得到:a) 输入的 Tensor,当 Tensor 数值大于 0,梯度为 1,当小于 0,梯度为 alpha b) alpha的数值
- Apply:实际计算梯度的函数,我们可以拿到先前的 Tensor,并调用 functional 接口册的 LeakyReluGrad,求得梯度,并返回
最后一步是注册,第一个参数是 op type name,第二个参数是继承自 OpExprGradFunction 的类。
为 Graph 模式注册反向
为 Graph 模式注册 leaky_relu_yzh op 的反向代码在:
https://github.com/Oneflow-Inc/oneflow/pull/8350/files#diff-ef94ddb8f5c25689f2c6fab7a9675f16c95a22018a8c01647b4398ce2fb85a8bR81-R97
3
本文覆盖的内容完成后,只是“跑通”算子,还需要进一步完善,包括为算子添加测试和 API 文档,这些将在后续的文章中介绍。
欢迎下载体验 OneFlow v0.8.0 最新版本:https://github.com/Oneflow-Inc/oneflow/
javascript实现获取中文汉字拼音首字母
今天分享一个日常开发中可能会用到的一个小功能,简单说就是输入中文汉字可转换得到中文汉字拼音首字母。当然我可写不出这样的功能,源码来自于其他民间大神的分享,博主在此记录一下功能demo,方便日后复用,同时方便需要此功能的各位。
如下输入名字张三。
点击按钮获取,得到中文拼音首字母
博主整理了一下代码可阅读性,下面直接上代码。
<!doctype html>
<html>
<head>
<meta charset=\”UTF-8\”>
<title></title>
<meta name=\”viewport\” content=\”width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\” />
</head>
<body>
<input type=\”text\” id=\”text\”>
<button onclick=\”makePy()\”>首字母获取</button><br>
<p id=\”text_value\”></p>
<script type=\”text/javascript\”>
// 汉字拼音首字母列表 本列表包含了20902个汉字,用于配合 ToChineseSpell
//函数使用,本表收录的字符的Unicode编码范围为19968至40869, XDesigner 整理
var strChineseFirstPY = \”YDYQSXMWZSSXJBYMGCCZQPSSQBYCDSCDQLDYLYBSSJGYZZJJFKCCLZDHWDWZJLJPFYYNWJJTMYHZWZHFLZPPQHGSCYYYNJQYXXGJHHSDSJNKKTMOMLCRXYPSNQSECCQZGGLLYJLMYZZSECYKYYHQWJSSGGYXYZYJWWKDJHYCHMYXJTLXJYQBYXZLDWRDJRWYSRLDZJPCBZJJBRCFTLECZSTZFXXZHTRQHYBDLYCZSSYMMRFMYQZPWWJJYFCRWFDFZQPYDDWYXKYJAWJFFXYPSFTZYHHYZYSWCJYXSCLCXXWZZXNBGNNXBXLZSZSBSGPYSYZDHMDZBQBZCWDZZYYTZHBTSYYBZGNTNXQYWQSKBPHHLXGYBFMJEBJHHGQTJCYSXSTKZHLYCKGLYSMZXYALMELDCCXGZYRJXSDLTYZCQKCNNJWHJTZZCQLJSTSTBNXBTYXCEQXGKWJYFLZQLYHYXSPSFXLMPBYSXXXYDJCZYLLLSJXFHJXPJBTFFYABYXBHZZBJYZLWLCZGGBTSSMDTJZXPTHYQTGLJSCQFZKJZJQNLZWLSLHDZBWJNCJZYZSQQYCQYRZCJJWYBRTWPYFTWEXCSKDZCTBZHYZZYYJXZCFFZZMJYXXSDZZOTTBZLQWFCKSZSXFYRLNYJMBDTHJXSQQCCSBXYYTSYFBXDZTGBCNSLCYZZPSAZYZZSCJCSHZQYDXLBPJLLMQXTYDZXSQJTZPXLCGLQTZWJBHCTSYJSFXYEJJTLBGXSXJMYJQQPFZASYJNTYDJXKJCDJSZCBARTDCLYJQMWNQNCLLLKBYBZZSYHQQLTWLCCXTXLLZNTYLNEWYZYXCZXXGRKRMTCNDNJTSYYSSDQDGHSDBJGHRWRQLYBGLXHLGTGXBQJDZPYJSJYJCTMRNYMGRZJCZGJMZMGXMPRYXKJNYMSGMZJYMKMFXMLDTGFBHCJHKYLPFMDXLQJJSMTQGZSJLQDLDGJYCALCMZCSDJLLNXDJFFFFJCZFMZFFPFKHKGDPSXKTACJDHHZDDCRRCFQYJKQCCWJDXHWJLYLLZGCFCQDSMLZPBJJPLSBCJGGDCKKDEZSQCCKJGCGKDJTJDLZYCXKLQSCGJCLTFPCQCZGWPJDQYZJJBYJHSJDZWGFSJGZKQCCZLLPSPKJGQJHZZLJPLGJGJJTHJJYJZCZMLZLYQBGJWMLJKXZDZNJQSYZMLJLLJKYWXMKJLHSKJGBMCLYYMKXJQLBMLLKMDXXKWYXYSLMLPSJQQJQXYXFJTJDXMXXLLCXQBSYJBGWYMBGGBCYXPJYGPEPFGDJGBHBNSQJYZJKJKHXQFGQZKFHYGKHDKLJQXPQYKYBNQSXQNSZSWHBSXWHXWBZZXDMNSJBSBKBBZKLYLXGWXDRWYQZMYWSJQLCJXXJXKJEQXSCYETLZHLYYYSDZPAQYZCMTLSHTZCFYZYXYLJSDCJQAGYSLCQLYYYSHMRQQKLDXZSCSSSYDYCJYSFSJBFRSSZQSBXXPXJYSDRCKGJLGDKZJZBDKTCSYQPYHSTCLDJDHMXMCGXYZHJDDTMHLTXZXYLYMOHYJCLTYFBQQXPFBDFHHTKSQHZYYWCNXXCRWHOWGYJLEGWDQCWGFJYCSNTMYTOLBYGWQWESJPWNMLRYDZSZTXYQPZGCWXHNGPYXSHMYQJXZTDPPBFYHZHTJYFDZWKGKZBLDNTSXHQEEGZZYLZMMZYJZGXZXKHKSTXNXXWYLYAPSTHXDWHZYMPXAGKYDXBHNHXKDPJNMYHYLPMGOCSLNZHKXXLPZZLBMLSFBHHGYGYYGGBHSCYAQTYWLXTZQCEZYDQDQMMHTKLLSZHLSJZWFYHQSWSCWLQAZYNYTLSXTHAZNKZZSZZLAXXZWWCTGQQTDDYZTCCHYQZFLXPSLZYGPZSZNGLNDQTBDLXGTCTAJDKYWNSYZLJHHZZCWNYYZYWMHYCHHYXHJKZWSXHZYXLYSKQYSPSLYZWMYPPKBYGLKZHTYXAXQSYSHXASMCHKDSCRSWJPWXSGZJLWWSCHSJHSQNHCSEGNDAQTBAALZZMSSTDQJCJKTSCJAXPLGGXHHGXXZCXPDMMHLDGTYBYSJMXHMRCPXXJZCKZXSHMLQXXTTHXWZFKHCCZDYTCJYXQHLXDHYPJQXYLSYYDZOZJNYXQEZYSQYAYXWYPDGXDDXSPPYZNDLTWRHXYDXZZJHTCXMCZLHPYYYYMHZLLHNXMYLLLMDCPPXHMXDKYCYRDLTXJCHHZZXZLCCLYLNZSHZJZZLNNRLWHYQSNJHXYNTTTKYJPYCHHYEGKCTTWLGQRLGGTGTYGYHPYHYLQYQGCWYQKPYYYTTTTLHYHLLTYTTSPLKYZXGZWGPYDSSZZDQXSKCQNMJJZZBXYQMJRTFFBTKHZKBXLJJKDXJTLBWFZPPTKQTZTGPDGNTPJYFALQMKGXBDCLZFHZCLLLLADPMXDJHLCCLGYHDZFGYDDGCYYFGYDXKSSEBDHYKDKDKHNAXXYBPBYYHXZQGAFFQYJXDMLJCSQZLLPCHBSXGJYNDYBYQSPZWJLZKSDDTACTBXZDYZYPJZQSJNKKTKNJDJGYYPGTLFYQKASDNTCYHBLWDZHBBYDWJRYGKZYHEYYFJMSDTYFZJJHGCXPLXHLDWXXJKYTCYKSSSMTWCTTQZLPBSZDZWZXGZAGYKTYWXLHLSPBCLLOQMMZSSLCMBJCSZZKYDCZJGQQDSMCYTZQQLWZQZXSSFPTTFQMDDZDSHDTDWFHTDYZJYQJQKYPBDJYYXTLJHDRQXXXHAYDHRJLKLYTWHLLRLLRCXYLBWSRSZZSYMKZZHHKYHXKSMDSYDYCJPBZBSQLFCXXXNXKXWYWSDZYQOGGQMMYHCDZTTFJYYBGSTTTYBYKJDHKYXBELHTYPJQNFXFDYKZHQKZBYJTZBXHFDXKDASWTAWAJLDYJSFHBLDNNTNQJTJNCHXFJSRFWHZFMDRYJYJWZPDJKZYJYMPCYZNYNXFBYTFYFWYGDBNZZZDNYTXZEMMQBSQEHXFZMBMFLZZSRXYMJGSXWZJSPRYDJSJGXHJJGLJJYNZZJXHGXKYMLPYYYCXYTWQZSWHWLYRJLPXSLSXMFSWWKLCTNXNYNPSJSZHDZEPTXMYYWXYYSYWLXJQZQXZDCLEEELMCPJPCLWBXSQHFWWTFFJTNQJHJQDXHWLBYZNFJLALKYYJLDXHHYCSTYYWNRJYXYWTRMDRQHWQCMFJDYZMHMYYXJWMYZQZXTLMRSPWWCHAQBXYGZYPXYYRRCLMPYMGKSJSZYSRMYJSNXTPLNBAPPYPYLXYYZKYNLDZYJZCZNNLMZHHARQMPGWQTZMXXMLLHGDZXYHXKYXYCJMFFYYHJFSBSSQLXXNDYCANNMTCJCYPRRNYTYQNYYMBMSXNDLYLYSLJRLXYSXQMLLYZLZJJJKYZZCSFBZXXMSTBJGNXYZHLXNMCWSCYZYFZLXBRNNNYLBNRTGZQYSATSWRYHYJZMZDHZGZDWYBSSCSKXSYHYTXXGCQGXZZSHYXJSCRHMKKBXCZJYJYMKQHZJFNBHMQHYSNJNZYBKNQMCLGQHWLZNZSWXKHLJHYYBQLBFCDSXDLDSPFZPSKJYZWZXZDDXJSMMEGJSCSSMGCLXXKYYYLNYPWWWGYDKZJGGGZGGSYCKNJWNJPCXBJJTQTJWDSSPJXZXNZXUMELPXFSXTLLXCLJXJJLJZXCTPSWXLYDHLYQRWHSYCSQYYBYAYWJJJQFWQCQQCJQGXALDBZZYJGKGXPLTZYFXJLTPADKYQHPMATLCPDCKBMTXYBHKLENXDLEEGQDYMSAWHZMLJTWYGXLYQZLJEEYYBQQFFNLYXRDSCTGJGXYYNKLLYQKCCTLHJLQMKKZGCYYGLLLJDZGYDHZWXPYSJBZKDZGYZZHYWYFQYTYZSZYEZZLYMHJJHTSMQWYZLKYYWZCSRKQYTLTDXWCTYJKLWSQZWBDCQYNCJSRSZJLKCDCDTLZZZACQQZZDDXYPLXZBQJYLZLLLQDDZQJYJYJZYXNYYYNYJXKXDAZWYRDLJYYYRJLXLLDYXJCYWYWNQCCLDDNYYYNYCKCZHXXCCLGZQJGKWPPCQQJYSBZZXYJSQPXJPZBSBDSFNSFPZXHDWZTDWPPTFLZZBZDMYYPQJRSDZSQZSQXBDGCPZSWDWCSQZGMDHZXMWWFYBPDGPHTMJTHZSMMBGZMBZJCFZWFZBBZMQCFMBDMCJXLGPNJBBXGYHYYJGPTZGZMQBQTCGYXJXLWZKYDPDYMGCFTPFXYZTZXDZXTGKMTYBBCLBJASKYTSSQYYMSZXFJEWLXLLSZBQJJJAKLYLXLYCCTSXMCWFKKKBSXLLLLJYXTYLTJYYTDPJHNHNNKBYQNFQYYZBYYESSESSGDYHFHWTCJBSDZZTFDMXHCNJZYMQWSRYJDZJQPDQBBSTJGGFBKJBXTGQHNGWJXJGDLLTHZHHYYYYYYSXWTYYYCCBDBPYPZYCCZYJPZYWCBDLFWZCWJDXXHYHLHWZZXJTCZLCDPXUJCZZZLYXJJTXPHFXWPYWXZPTDZZBDZCYHJHMLXBQXSBYLRDTGJRRCTTTHYTCZWMXFYTWWZCWJWXJYWCSKYBZSCCTZQNHXNWXXKHKFHTSWOCCJYBCMPZZYKBNNZPBZHHZDLSYDDYTYFJPXYNGFXBYQXCBHXCPSXTYZDMKYSNXSXLHKMZXLYHDHKWHXXSSKQYHHCJYXGLHZXCSNHEKDTGZXQYPKDHEXTYKCNYMYYYPKQYYYKXZLTHJQTBYQHXBMYHSQCKWWYLLHCYYLNNEQXQWMCFBDCCMLJGGXDQKTLXKGNQCDGZJWYJJLYHHQTTTNWCHMXCXWHWSZJYDJCCDBQCDGDNYXZTHCQRXCBHZTQCBXWGQWYYBXHMBYMYQTYEXMQKYAQYRGYZSLFYKKQHYSSQYSHJGJCNXKZYCXSBXYXHYYLSTYCXQTHYSMGSCPMMGCCCCCMTZTASMGQZJHKLOSQYLSWTMXSYQKDZLJQQYPLSYCZTCQQPBBQJZCLPKHQZYYXXDTDDTSJCXFFLLCHQXMJLWCJCXTSPYCXNDTJSHJWXDQQJSKXYAMYLSJHMLALYKXCYYDMNMDQMXMCZNNCYBZKKYFLMCHCMLHXRCJJHSYLNMTJZGZGYWJXSRXCWJGJQHQZDQJDCJJZKJKGDZQGJJYJYLXZXXCDQHHHEYTMHLFSBDJSYYSHFYSTCZQLPBDRFRZTZYKYWHSZYQKWDQZRKMSYNBCRXQBJYFAZPZZEDZCJYWBCJWHYJBQSZYWRYSZPTDKZPFPBNZTKLQYHBBZPNPPTYZZYBQNYDCPJMMCYCQMCYFZZDCMNLFPBPLNGQJTBTTNJZPZBBZNJKLJQYLNBZQHKSJZNGGQSZZKYXSHPZSNBCGZKDDZQANZHJKDRTLZLSWJLJZLYWTJNDJZJHXYAYNCBGTZCSSQMNJPJYTYSWXZFKWJQTKHTZPLBHSNJZSYZBWZZZZLSYLSBJHDWWQPSLMMFBJDWAQYZTCJTBNNWZXQXCDSLQGDSDPDZHJTQQPSWLYYJZLGYXYZLCTCBJTKTYCZJTQKBSJLGMGZDMCSGPYNJZYQYYKNXRPWSZXMTNCSZZYXYBYHYZAXYWQCJTLLCKJJTJHGDXDXYQYZZBYWDLWQCGLZGJGQRQZCZSSBCRPCSKYDZNXJSQGXSSJMYDNSTZTPBDLTKZWXQWQTZEXNQCZGWEZKSSBYBRTSSSLCCGBPSZQSZLCCGLLLZXHZQTHCZMQGYZQZNMCOCSZJMMZSQPJYGQLJYJPPLDXRGZYXCCSXHSHGTZNLZWZKJCXTCFCJXLBMQBCZZWPQDNHXLJCTHYZLGYLNLSZZPCXDSCQQHJQKSXZPBAJYEMSMJTZDXLCJYRYYNWJBNGZZTMJXLTBSLYRZPYLSSCNXPHLLHYLLQQZQLXYMRSYCXZLMMCZLTZSDWTJJLLNZGGQXPFSKYGYFZPDKMWGHCXMSGDXJMCJZDYCABXJDLNBCDQYGSKYDQTXDJJYXMSZQAZDZFSLQXYJSJZYLBTXXWXQQZBJZUFBBLYLWDSLJHXJYZJWTDJCZFQZQZZDZSXZZQLZCDZFJHYSPYMPQZMLPPLFFXJJNZZYLSJEYQZFPFZKSYWJJJHRDJZZXTXXGLGHYDXCSKYSWMMZCWYBAZBJKSHFHJCXMHFQHYXXYZFTSJYZFXYXPZLCHMZMBXHZZSXYFYMNCWDABAZLXKTCSHHXKXJJZJSTHYGXSXYYHHHJWXKZXSSBZZWHHHCWTZZZPJXSNXQQJGZYZYWLLCWXZFXXYXYHXMKYYSWSQMNLNAYCYSPMJKHWCQHYLAJJMZXHMMCNZHBHXCLXTJPLTXYJHDYYLTTXFSZHYXXSJBJYAYRSMXYPLCKDUYHLXRLNLLSTYZYYQYGYHHSCCSMZCTZQXKYQFPYYRPFFLKQUNTSZLLZMWWTCQQYZWTLLMLMPWMBZSSTZRBPDDTLQJJBXZCSRZQQYGWCSXFWZLXCCRSZDZMCYGGDZQSGTJSWLJMYMMZYHFBJDGYXCCPSHXNZCSBSJYJGJMPPWAFFYFNXHYZXZYLREMZGZCYZSSZDLLJCSQFNXZKPTXZGXJJGFMYYYSNBTYLBNLHPFZDCYFBMGQRRSSSZXYSGTZRNYDZZCDGPJAFJFZKNZBLCZSZPSGCYCJSZLMLRSZBZZLDLSLLYSXSQZQLYXZLSKKBRXBRBZCYCXZZZEEYFGKLZLYYHGZSGZLFJHGTGWKRAAJYZKZQTSSHJJXDCYZUYJLZYRZDQQHGJZXSSZBYKJPBFRTJXLLFQWJHYLQTYMBLPZDXTZYGBDHZZRBGXHWNJTJXLKSCFSMWQYSJTXKZSCFWJLBXFTZLLJZLLQBLSQMQQCGCZFPBPHZCZJLPYYGGDTGWDCFCZQYYYQYSSCLXZSKLZZZGFFCQNWGLHQYZJJCZLQZZYJPJZZBPDCCMHJGXDQDGDLZQMFGPSYTSDYFWWDJZJYSXYYCZCYHZWPBYKXRYLYBHKJKSFXTZJMMCKHLLTNYYMSYXYZPYJQYCSYCWMTJJKQYRHLLQXPSGTLYYCLJSCPXJYZFNMLRGJJTYZBXYZMSJYJHHFZQMSYXRSZCWTLRTQZSSTKXGQKGSPTGCZNJSJCQCXHMXGGZTQYDJKZDLBZSXJLHYQGGGTHQSZPYHJHHGYYGKGGCWJZZYLCZLXQSFTGZSLLLMLJSKCTBLLZZSZMMNYTPZSXQHJCJYQXYZXZQZCPSHKZZYSXCDFGMWQRLLQXRFZTLYSTCTMJCXJJXHJNXTNRZTZFQYHQGLLGCXSZSJDJLJCYDSJTLNYXHSZXCGJZYQPYLFHDJSBPCCZHJJJQZJQDYBSSLLCMYTTMQTBHJQNNYGKYRQYQMZGCJKPDCGMYZHQLLSLLCLMHOLZGDYYFZSLJCQZLYLZQJESHNYLLJXGJXLYSYYYXNBZLJSSZCQQCJYLLZLTJYLLZLLBNYLGQCHXYYXOXCXQKYJXXXYKLXSXXYQXCYKQXQCSGYXXYQXYGYTQOHXHXPYXXXULCYEYCHZZCBWQBBWJQZSCSZSSLZYLKDESJZWMYMCYTSDSXXSCJPQQSQYLYYZYCMDJDZYWCBTJSYDJKCYDDJLBDJJSODZYSYXQQYXDHHGQQYQHDYXWGMMMAJDYBBBPPBCMUUPLJZSMTXERXJMHQNUTPJDCBSSMSSSTKJTSSMMTRCPLZSZMLQDSDMJMQPNQDXCFYNBFSDQXYXHYAYKQYDDLQYYYSSZBYDSLNTFQTZQPZMCHDHCZCWFDXTMYQSPHQYYXSRGJCWTJTZZQMGWJJTJHTQJBBHWZPXXHYQFXXQYWYYHYSCDYDHHQMNMTMWCPBSZPPZZGLMZFOLLCFWHMMSJZTTDHZZYFFYTZZGZYSKYJXQYJZQBHMBZZLYGHGFMSHPZFZSNCLPBQSNJXZSLXXFPMTYJYGBXLLDLXPZJYZJYHHZCYWHJYLSJEXFSZZYWXKZJLUYDTMLYMQJPWXYHXSKTQJEZRPXXZHHMHWQPWQLYJJQJJZSZCPHJLCHHNXJLQWZJHBMZYXBDHHYPZLHLHLGFWLCHYYTLHJXCJMSCPXSTKPNHQXSRTYXXTESYJCTLSSLSTDLLLWWYHDHRJZSFGXTSYCZYNYHTDHWJSLHTZDQDJZXXQHGYLTZPHCSQFCLNJTCLZPFSTPDYNYLGMJLLYCQHYSSHCHYLHQYQTMZYPBYWRFQYKQSYSLZDQJMPXYYSSRHZJNYWTQDFZBWWTWWRXCWHGYHXMKMYYYQMSMZHNGCEPMLQQMTCWCTMMPXJPJJHFXYYZSXZHTYBMSTSYJTTQQQYYLHYNPYQZLCYZHZWSMYLKFJXLWGXYPJYTYSYXYMZCKTTWLKSMZSYLMPWLZWXWQZSSAQSYXYRHSSNTSRAPXCPWCMGDXHXZDZYFJHGZTTSBJHGYZSZYSMYCLLLXBTYXHBBZJKSSDMALXHYCFYGMQYPJYCQXJLLLJGSLZGQLYCJCCZOTYXMTMTTLLWTGPXYMZMKLPSZZZXHKQYSXCTYJZYHXSHYXZKXLZWPSQPYHJWPJPWXQQYLXSDHMRSLZZYZWTTCYXYSZZSHBSCCSTPLWSSCJCHNLCGCHSSPHYLHFHHXJSXYLLNYLSZDHZXYLSXLWZYKCLDYAXZCMDDYSPJTQJZLNWQPSSSWCTSTSZLBLNXSMNYYMJQBQHRZWTYYDCHQLXKPZWBGQYBKFCMZWPZLLYYLSZYDWHXPSBCMLJBSCGBHXLQHYRLJXYSWXWXZSLDFHLSLYNJLZYFLYJYCDRJLFSYZFSLLCQYQFGJYHYXZLYLMSTDJCYHBZLLNWLXXYGYYHSMGDHXXHHLZZJZXCZZZCYQZFNGWPYLCPKPYYPMCLQKDGXZGGWQBDXZZKZFBXXLZXJTPJPTTBYTSZZDWSLCHZHSLTYXHQLHYXXXYYZYSWTXZKHLXZXZPYHGCHKCFSYHUTJRLXFJXPTZTWHPLYXFCRHXSHXKYXXYHZQDXQWULHYHMJTBFLKHTXCWHJFWJCFPQRYQXCYYYQYGRPYWSGSUNGWCHKZDXYFLXXHJJBYZWTSXXNCYJJYMSWZJQRMHXZWFQSYLZJZGBHYNSLBGTTCSYBYXXWXYHXYYXNSQYXMQYWRGYQLXBBZLJSYLPSYTJZYHYZAWLRORJMKSCZJXXXYXCHDYXRYXXJDTSQFXLYLTSFFYXLMTYJMJUYYYXLTZCSXQZQHZXLYYXZHDNBRXXXJCTYHLBRLMBRLLAXKYLLLJLYXXLYCRYLCJTGJCMTLZLLCYZZPZPCYAWHJJFYBDYYZSMPCKZDQYQPBPCJPDCYZMDPBCYYDYCNNPLMTMLRMFMMGWYZBSJGYGSMZQQQZTXMKQWGXLLPJGZBQCDJJJFPKJKCXBLJMSWMDTQJXLDLPPBXCWRCQFBFQJCZAHZGMYKPHYYHZYKNDKZMBPJYXPXYHLFPNYYGXJDBKXNXHJMZJXSTRSTLDXSKZYSYBZXJLXYSLBZYSLHXJPFXPQNBYLLJQKYGZMCYZZYMCCSLCLHZFWFWYXZMWSXTYNXJHPYYMCYSPMHYSMYDYSHQYZCHMJJMZCAAGCFJBBHPLYZYLXXSDJGXDHKXXTXXNBHRMLYJSLTXMRHNLXQJXYZLLYSWQGDLBJHDCGJYQYCMHWFMJYBMBYJYJWYMDPWHXQLDYGPDFXXBCGJSPCKRSSYZJMSLBZZJFLJJJLGXZGYXYXLSZQYXBEXYXHGCXBPLDYHWETTWWCJMBTXCHXYQXLLXFLYXLLJLSSFWDPZSMYJCLMWYTCZPCHQEKCQBWLCQYDPLQPPQZQFJQDJHYMMCXTXDRMJWRHXCJZYLQXDYYNHYYHRSLSRSYWWZJYMTLTLLGTQCJZYABTCKZCJYCCQLJZQXALMZYHYWLWDXZXQDLLQSHGPJFJLJHJABCQZDJGTKHSSTCYJLPSWZLXZXRWGLDLZRLZXTGSLLLLZLYXXWGDZYGBDPHZPBRLWSXQBPFDWOFMWHLYPCBJCCLDMBZPBZZLCYQXLDOMZBLZWPDWYYGDSTTHCSQSCCRSSSYSLFYBFNTYJSZDFNDPDHDZZMBBLSLCMYFFGTJJQWFTMTPJWFNLBZCMMJTGBDZLQLPYFHYYMJYCHDZJWJCCTLJCLDTLJJCPDDSQDSSZYBNDBJLGGJZXSXNLYCYBJXQYCBYLZCFZPPGKCXZDZFZTJJFJSJXZBNZYJQTTYJYHTYCZHYMDJXTTMPXSPLZCDWSLSHXYPZGTFMLCJTYCBPMGDKWYCYZCDSZZYHFLYCTYGWHKJYYLSJCXGYWJCBLLCSNDDBTZBSCLYZCZZSSQDLLMQYYHFSLQLLXFTYHABXGWNYWYYPLLDLLBJCYXJZMLHLJDXYYQYTDLLLBUGBFDFBBQJZZMDPJHGCLGMJJPGAEHHBWCQXAXHHHZCHXYPHJAXHLPHJPGPZJQCQZGJJZZUZDMQYYBZZPHYHYBWHAZYJHYKFGDPFQSDLZMLJXKXGALXZDAGLMDGXMWZQYXXDXXPFDMMSSYMPFMDMMKXKSYZYSHDZKXSYSMMZZZMSYDNZZCZXFPLSTMZDNMXCKJMZTYYMZMZZMSXHHDCZJEMXXKLJSTLWLSQLYJZLLZJSSDPPMHNLZJCZYHMXXHGZCJMDHXTKGRMXFWMCGMWKDTKSXQMMMFZZYDKMSCLCMPCGMHSPXQPZDSSLCXKYXTWLWJYAHZJGZQMCSNXYYMMPMLKJXMHLMLQMXCTKZMJQYSZJSYSZHSYJZJCDAJZYBSDQJZGWZQQXFKDMSDJLFWEHKZQKJPEYPZYSZCDWYJFFMZZYLTTDZZEFMZLBNPPLPLPEPSZALLTYLKCKQZKGENQLWAGYXYDPXLHSXQQWQCQXQCLHYXXMLYCCWLYMQYSKGCHLCJNSZKPYZKCQZQLJPDMDZHLASXLBYDWQLWDNBQCRYDDZTJYBKBWSZDXDTNPJDTCTQDFXQQMGNXECLTTBKPWSLCTYQLPWYZZKLPYGZCQQPLLKCCYLPQMZCZQCLJSLQZDJXLDDHPZQDLJJXZQDXYZQKZLJCYQDYJPPYPQYKJYRMPCBYMCXKLLZLLFQPYLLLMBSGLCYSSLRSYSQTMXYXZQZFDZUYSYZTFFMZZSMZQHZSSCCMLYXWTPZGXZJGZGSJSGKDDHTQGGZLLBJDZLCBCHYXYZHZFYWXYZYMSDBZZYJGTSMTFXQYXQSTDGSLNXDLRYZZLRYYLXQHTXSRTZNGZXBNQQZFMYKMZJBZYMKBPNLYZPBLMCNQYZZZSJZHJCTZKHYZZJRDYZHNPXGLFZTLKGJTCTSSYLLGZRZBBQZZKLPKLCZYSSUYXBJFPNJZZXCDWXZYJXZZDJJKGGRSRJKMSMZJLSJYWQSKYHQJSXPJZZZLSNSHRNYPZTWCHKLPSRZLZXYJQXQKYSJYCZTLQZYBBYBWZPQDWWYZCYTJCJXCKCWDKKZXSGKDZXWWYYJQYYTCYTDLLXWKCZKKLCCLZCQQDZLQLCSFQCHQHSFSMQZZLNBJJZBSJHTSZDYSJQJPDLZCDCWJKJZZLPYCGMZWDJJBSJQZSYZYHHXJPBJYDSSXDZNCGLQMBTSFSBPDZDLZNFGFJGFSMPXJQLMBLGQCYYXBQKDJJQYRFKZTJDHCZKLBSDZCFJTPLLJGXHYXZCSSZZXSTJYGKGCKGYOQXJPLZPBPGTGYJZGHZQZZLBJLSQFZGKQQJZGYCZBZQTLDXRJXBSXXPZXHYZYCLWDXJJHXMFDZPFZHQHQMQGKSLYHTYCGFRZGNQXCLPDLBZCSCZQLLJBLHBZCYPZZPPDYMZZSGYHCKCPZJGSLJLNSCDSLDLXBMSTLDDFJMKDJDHZLZXLSZQPQPGJLLYBDSZGQLBZLSLKYYHZTTNTJYQTZZPSZQZTLLJTYYLLQLLQYZQLBDZLSLYYZYMDFSZSNHLXZNCZQZPBWSKRFBSYZMTHBLGJPMCZZLSTLXSHTCSYZLZBLFEQHLXFLCJLYLJQCBZLZJHHSSTBRMHXZHJZCLXFNBGXGTQJCZTMSFZKJMSSNXLJKBHSJXNTNLZDNTLMSJXGZJYJCZXYJYJWRWWQNZTNFJSZPZSHZJFYRDJSFSZJZBJFZQZZHZLXFYSBZQLZSGYFTZDCSZXZJBQMSZKJRHYJZCKMJKHCHGTXKXQGLXPXFXTRTYLXJXHDTSJXHJZJXZWZLCQSBTXWXGXTXXHXFTSDKFJHZYJFJXRZSDLLLTQSQQZQWZXSYQTWGWBZCGZLLYZBCLMQQTZHZXZXLJFRMYZFLXYSQXXJKXRMQDZDMMYYBSQBHGZMWFWXGMXLZPYYTGZYCCDXYZXYWGSYJYZNBHPZJSQSYXSXRTFYZGRHZTXSZZTHCBFCLSYXZLZQMZLMPLMXZJXSFLBYZMYQHXJSXRXSQZZZSSLYFRCZJRCRXHHZXQYDYHXSJJHZCXZBTYNSYSXJBQLPXZQPYMLXZKYXLXCJLCYSXXZZLXDLLLJJYHZXGYJWKJRWYHCPSGNRZLFZWFZZNSXGXFLZSXZZZBFCSYJDBRJKRDHHGXJLJJTGXJXXSTJTJXLYXQFCSGSWMSBCTLQZZWLZZKXJMLTMJYHSDDBXGZHDLBMYJFRZFSGCLYJBPMLYSMSXLSZJQQHJZFXGFQFQBPXZGYYQXGZTCQWYLTLGWSGWHRLFSFGZJMGMGBGTJFSYZZGZYZAFLSSPMLPFLCWBJZCLJJMZLPJJLYMQDMYYYFBGYGYZMLYZDXQYXRQQQHSYYYQXYLJTYXFSFSLLGNQCYHYCWFHCCCFXPYLYPLLZYXXXXXKQHHXSHJZCFZSCZJXCPZWHHHHHAPYLQALPQAFYHXDYLUKMZQGGGDDESRNNZLTZGCHYPPYSQJJHCLLJTOLNJPZLJLHYMHEYDYDSQYCDDHGZUNDZCLZYZLLZNTNYZGSLHSLPJJBDGWXPCDUTJCKLKCLWKLLCASSTKZZDNQNTTLYYZSSYSSZZRYLJQKCQDHHCRXRZYDGRGCWCGZQFFFPPJFZYNAKRGYWYQPQXXFKJTSZZXSWZDDFBBXTBGTZKZNPZZPZXZPJSZBMQHKCYXYLDKLJNYPKYGHGDZJXXEAHPNZKZTZCMXCXMMJXNKSZQNMNLWBWWXJKYHCPSTMCSQTZJYXTPCTPDTNNPGLLLZSJLSPBLPLQHDTNJNLYYRSZFFJFQWDPHZDWMRZCCLODAXNSSNYZRESTYJWJYJDBCFXNMWTTBYLWSTSZGYBLJPXGLBOCLHPCBJLTMXZLJYLZXCLTPNCLCKXTPZJSWCYXSFYSZDKNTLBYJCYJLLSTGQCBXRYZXBXKLYLHZLQZLNZCXWJZLJZJNCJHXMNZZGJZZXTZJXYCYYCXXJYYXJJXSSSJSTSSTTPPGQTCSXWZDCSYFPTFBFHFBBLZJCLZZDBXGCXLQPXKFZFLSYLTUWBMQJHSZBMDDBCYSCCLDXYCDDQLYJJWMQLLCSGLJJSYFPYYCCYLTJANTJJPWYCMMGQYYSXDXQMZHSZXPFTWWZQSWQRFKJLZJQQYFBRXJHHFWJJZYQAZMYFRHCYYBYQWLPEXCCZSTYRLTTDMQLYKMBBGMYYJPRKZNPBSXYXBHYZDJDNGHPMFSGMWFZMFQMMBCMZZCJJLCNUXYQLMLRYGQZCYXZLWJGCJCGGMCJNFYZZJHYCPRRCMTZQZXHFQGTJXCCJEAQCRJYHPLQLSZDJRBCQHQDYRHYLYXJSYMHZYDWLDFRYHBPYDTSSCNWBXGLPZMLZZTQSSCPJMXXYCSJYTYCGHYCJWYRXXLFEMWJNMKLLSWTXHYYYNCMMCWJDQDJZGLLJWJRKHPZGGFLCCSCZMCBLTBHBQJXQDSPDJZZGKGLFQYWBZYZJLTSTDHQHCTCBCHFLQMPWDSHYYTQWCNZZJTLBYMBPDYYYXSQKXWYYFLXXNCWCXYPMAELYKKJMZZZBRXYYQJFLJPFHHHYTZZXSGQQMHSPGDZQWBWPJHZJDYSCQWZKTXXSQLZYYMYSDZGRXCKKUJLWPYSYSCSYZLRMLQSYLJXBCXTLWDQZPCYCYKPPPNSXFYZJJRCEMHSZMSXLXGLRWGCSTLRSXBZGBZGZTCPLUJLSLYLYMTXMTZPALZXPXJTJWTCYYZLBLXBZLQMYLXPGHDSLSSDMXMBDZZSXWHAMLCZCPJMCNHJYSNSYGCHSKQMZZQDLLKABLWJXSFMOCDXJRRLYQZKJMYBYQLYHETFJZFRFKSRYXFJTWDSXXSYSQJYSLYXWJHSNLXYYXHBHAWHHJZXWMYLJCSSLKYDZTXBZSYFDXGXZJKHSXXYBSSXDPYNZWRPTQZCZENYGCXQFJYKJBZMLJCMQQXUOXSLYXXLYLLJDZBTYMHPFSTTQQWLHOKYBLZZALZXQLHZWRRQHLSTMYPYXJJXMQSJFNBXYXYJXXYQYLTHYLQYFMLKLJTMLLHSZWKZHLJMLHLJKLJSTLQXYLMBHHLNLZXQJHXCFXXLHYHJJGBYZZKBXSCQDJQDSUJZYYHZHHMGSXCSYMXFEBCQWWRBPYYJQTYZCYQYQQZYHMWFFHGZFRJFCDPXNTQYZPDYKHJLFRZXPPXZDBBGZQSTLGDGYLCQMLCHHMFYWLZYXKJLYPQHSYWMQQGQZMLZJNSQXJQSYJYCBEHSXFSZPXZWFLLBCYYJDYTDTHWZSFJMQQYJLMQXXLLDTTKHHYBFPWTYYSQQWNQWLGWDEBZWCMYGCULKJXTMXMYJSXHYBRWFYMWFRXYQMXYSZTZZTFYKMLDHQDXWYYNLCRYJBLPSXCXYWLSPRRJWXHQYPHTYDNXHHMMYWYTZCSQMTSSCCDALWZTCPQPYJLLQZYJSWXMZZMMYLMXCLMXCZMXMZSQTZPPQQBLPGXQZHFLJJHYTJSRXWZXSCCDLXTYJDCQJXSLQYCLZXLZZXMXQRJMHRHZJBHMFLJLMLCLQNLDXZLLLPYPSYJYSXCQQDCMQJZZXHNPNXZMEKMXHYKYQLXSXTXJYYHWDCWDZHQYYBGYBCYSCFGPSJNZDYZZJZXRZRQJJYMCANYRJTLDPPYZBSTJKXXZYPFDWFGZZRPYMTNGXZQBYXNBUFNQKRJQZMJEGRZGYCLKXZDSKKNSXKCLJSPJYYZLQQJYBZSSQLLLKJXTBKTYLCCDDBLSPPFYLGYDTZJYQGGKQTTFZXBDKTYYHYBBFYTYYBCLPDYTGDHRYRNJSPTCSNYJQHKLLLZSLYDXXWBCJQSPXBPJZJCJDZFFXXBRMLAZHCSNDLBJDSZBLPRZTSWSBXBCLLXXLZDJZSJPYLYXXYFTFFFBHJJXGBYXJPMMMPSSJZJMTLYZJXSWXTYLEDQPJMYGQZJGDJLQJWJQLLSJGJGYGMSCLJJXDTYGJQJQJCJZCJGDZZSXQGSJGGCXHQXSNQLZZBXHSGZXCXYLJXYXYYDFQQJHJFXDHCTXJYRXYSQTJXYEFYYSSYYJXNCYZXFXMSYSZXYYSCHSHXZZZGZZZGFJDLTYLNPZGYJYZYYQZPBXQBDZTZCZYXXYHHSQXSHDHGQHJHGYWSZTMZMLHYXGEBTYLZKQWYTJZRCLEKYSTDBCYKQQSAYXCJXWWGSBHJYZYDHCSJKQCXSWXFLTYNYZPZCCZJQTZWJQDZZZQZLJJXLSBHPYXXPSXSHHEZTXFPTLQYZZXHYTXNCFZYYHXGNXMYWXTZSJPTHHGYMXMXQZXTSBCZYJYXXTYYZYPCQLMMSZMJZZLLZXGXZAAJZYXJMZXWDXZSXZDZXLEYJJZQBHZWZZZQTZPSXZTDSXJJJZNYAZPHXYYSRNQDTHZHYYKYJHDZXZLSWCLYBZYECWCYCRYLCXNHZYDZYDYJDFRJJHTRSQTXYXJRJHOJYNXELXSFSFJZGHPZSXZSZDZCQZBYYKLSGSJHCZSHDGQGXYZGXCHXZJWYQWGYHKSSEQZZNDZFKWYSSTCLZSTSYMCDHJXXYWEYXCZAYDMPXMDSXYBSQMJMZJMTZQLPJYQZCGQHXJHHLXXHLHDLDJQCLDWBSXFZZYYSCHTYTYYBHECXHYKGJPXHHYZJFXHWHBDZFYZBCAPNPGNYDMSXHMMMMAMYNBYJTMPXYYMCTHJBZYFCGTYHWPHFTWZZEZSBZEGPFMTSKFTYCMHFLLHGPZJXZJGZJYXZSBBQSCZZLZCCSTPGXMJSFTCCZJZDJXCYBZLFCJSYZFGSZLYBCWZZBYZDZYPSWYJZXZBDSYUXLZZBZFYGCZXBZHZFTPBGZGEJBSTGKDMFHYZZJHZLLZZGJQZLSFDJSSCBZGPDLFZFZSZYZYZSYGCXSNXXCHCZXTZZLJFZGQSQYXZJQDCCZTQCDXZJYQJQCHXZTDLGSCXZSYQJQTZWLQDQZTQCHQQJZYEZZZPBWKDJFCJPZTYPQYQTTYNLMBDKTJZPQZQZZFPZSBNJLGYJDXJDZZKZGQKXDLPZJTCJDQBXDJQJSTCKNXBXZMSLYJCQMTJQWWCJQNJNLLLHJCWQTBZQYDZCZPZZDZYDDCYZZZCCJTTJFZDPRRTZTJDCQTQZDTJNPLZBCLLCTZSXKJZQZPZLBZRBTJDCXFCZDBCCJJLTQQPLDCGZDBBZJCQDCJWYNLLZYZCCDWLLXWZLXRXNTQQCZXKQLSGDFQTDDGLRLAJJTKUYMKQLLTZYTDYYCZGJWYXDXFRSKSTQTENQMRKQZHHQKDLDAZFKYPBGGPZREBZZYKZZSPEGJXGYKQZZZSLYSYYYZWFQZYLZZLZHWCHKYPQGNPGBLPLRRJYXCCSYYHSFZFYBZYYTGZXYLXCZWXXZJZBLFFLGSKHYJZEYJHLPLLLLCZGXDRZELRHGKLZZYHZLYQSZZJZQLJZFLNBHGWLCZCFJYSPYXZLZLXGCCPZBLLCYBBBBUBBCBPCRNNZCZYRBFSRLDCGQYYQXYGMQZWTZYTYJXYFWTEHZZJYWLCCNTZYJJZDEDPZDZTSYQJHDYMBJNYJZLXTSSTPHNDJXXBYXQTZQDDTJTDYYTGWSCSZQFLSHLGLBCZPHDLYZJYCKWTYTYLBNYTSDSYCCTYSZYYEBHEXHQDTWNYGYCLXTSZYSTQMYGZAZCCSZZDSLZCLZRQXYYELJSBYMXSXZTEMBBLLYYLLYTDQYSHYMRQWKFKBFXNXSBYCHXBWJYHTQBPBSBWDZYLKGZSKYHXQZJXHXJXGNLJKZLYYCDXLFYFGHLJGJYBXQLYBXQPQGZTZPLNCYPXDJYQYDYMRBESJYYHKXXSTMXRCZZYWXYQYBMCLLYZHQYZWQXDBXBZWZMSLPDMYSKFMZKLZCYQYCZLQXFZZYDQZPZYGYJYZMZXDZFYFYTTQTZHGSPCZMLCCYTZXJCYTJMKSLPZHYSNZLLYTPZCTZZCKTXDHXXTQCYFKSMQCCYYAZHTJPCYLZLYJBJXTPNYLJYYNRXSYLMMNXJSMYBCSYSYLZYLXJJQYLDZLPQBFZZBLFNDXQKCZFYWHGQMRDSXYCYTXNQQJZYYPFZXDYZFPRXEJDGYQBXRCNFYYQPGHYJDYZXGRHTKYLNWDZNTSMPKLBTHBPYSZBZTJZSZZJTYYXZPHSSZZBZCZPTQFZMYFLYPYBBJQXZMXXDJMTSYSKKBJZXHJCKLPSMKYJZCXTMLJYXRZZQSLXXQPYZXMKYXXXJCLJPRMYYGADYSKQLSNDHYZKQXZYZTCGHZTLMLWZYBWSYCTBHJHJFCWZTXWYTKZLXQSHLYJZJXTMPLPYCGLTBZZTLZJCYJGDTCLKLPLLQPJMZPAPXYZLKKTKDZCZZBNZDYDYQZJYJGMCTXLTGXSZLMLHBGLKFWNWZHDXUHLFMKYSLGXDTWWFRJEJZTZHYDXYKSHWFZCQSHKTMQQHTZHYMJDJSKHXZJZBZZXYMPAGQMSTPXLSKLZYNWRTSQLSZBPSPSGZWYHTLKSSSWHZZLYYTNXJGMJSZSUFWNLSOZTXGXLSAMMLBWLDSZYLAKQCQCTMYCFJBSLXCLZZCLXXKSBZQCLHJPSQPLSXXCKSLNHPSFQQYTXYJZLQLDXZQJZDYYDJNZPTUZDSKJFSLJHYLZSQZLBTXYDGTQFDBYAZXDZHZJNHHQBYKNXJJQCZMLLJZKSPLDYCLBBLXKLELXJLBQYCXJXGCNLCQPLZLZYJTZLJGYZDZPLTQCSXFDMNYCXGBTJDCZNBGBQYQJWGKFHTNPYQZQGBKPBBYZMTJDYTBLSQMPSXTBNPDXKLEMYYCJYNZCTLDYKZZXDDXHQSHDGMZSJYCCTAYRZLPYLTLKXSLZCGGEXCLFXLKJRTLQJAQZNCMBYDKKCXGLCZJZXJHPTDJJMZQYKQSECQZDSHHADMLZFMMZBGNTJNNLGBYJBRBTMLBYJDZXLCJLPLDLPCQDHLXZLYCBLCXZZJADJLNZMMSSSMYBHBSQKBHRSXXJMXSDZNZPXLGBRHWGGFCXGMSKLLTSJYYCQLTSKYWYYHYWXBXQYWPYWYKQLSQPTNTKHQCWDQKTWPXXHCPTHTWUMSSYHBWCRWXHJMKMZNGWTMLKFGHKJYLSYYCXWHYECLQHKQHTTQKHFZLDXQWYZYYDESBPKYRZPJFYYZJCEQDZZDLATZBBFJLLCXDLMJSSXEGYGSJQXCWBXSSZPDYZCXDNYXPPZYDLYJCZPLTXLSXYZYRXCYYYDYLWWNZSAHJSYQYHGYWWAXTJZDAXYSRLTDPSSYYFNEJDXYZHLXLLLZQZSJNYQYQQXYJGHZGZCYJCHZLYCDSHWSHJZYJXCLLNXZJJYYXNFXMWFPYLCYLLABWDDHWDXJMCXZTZPMLQZHSFHZYNZTLLDYWLSLXHYMMYLMBWWKYXYADTXYLLDJPYBPWUXJMWMLLSAFDLLYFLBHHHBQQLTZJCQJLDJTFFKMMMBYTHYGDCQRDDWRQJXNBYSNWZDBYYTBJHPYBYTTJXAAHGQDQTMYSTQXKBTZPKJLZRBEQQSSMJJBDJOTGTBXPGBKTLHQXJJJCTHXQDWJLWRFWQGWSHCKRYSWGFTGYGBXSDWDWRFHWYTJJXXXJYZYSLPYYYPAYXHYDQKXSHXYXGSKQHYWFDDDPPLCJLQQEEWXKSYYKDYPLTJTHKJLTCYYHHJTTPLTZZCDLTHQKZXQYSTEEYWYYZYXXYYSTTJKLLPZMCYHQGXYHSRMBXPLLNQYDQHXSXXWGDQBSHYLLPJJJTHYJKYPPTHYYKTYEZYENMDSHLCRPQFDGFXZPSFTLJXXJBSWYYSKSFLXLPPLBBBLBSFXFYZBSJSSYLPBBFFFFSSCJDSTZSXZRYYSYFFSYZYZBJTBCTSBSDHRTJJBYTCXYJEYLXCBNEBJDSYXYKGSJZBXBYTFZWGENYHHTHZHHXFWGCSTBGXKLSXYWMTMBYXJSTZSCDYQRCYTWXZFHMYMCXLZNSDJTTTXRYCFYJSBSDYERXJLJXBBDEYNJGHXGCKGSCYMBLXJMSZNSKGXFBNBPTHFJAAFXYXFPXMYPQDTZCXZZPXRSYWZDLYBBKTYQPQJPZYPZJZNJPZJLZZFYSBTTSLMPTZRTDXQSJEHBZYLZDHLJSQMLHTXTJECXSLZZSPKTLZKQQYFSYGYWPCPQFHQHYTQXZKRSGTTSQCZLPTXCDYYZXSQZSLXLZMYCPCQBZYXHBSXLZDLTCDXTYLZJYYZPZYZLTXJSJXHLPMYTXCQRBLZSSFJZZTNJYTXMYJHLHPPLCYXQJQQKZZSCPZKSWALQSBLCCZJSXGWWWYGYKTJBBZTDKHXHKGTGPBKQYSLPXPJCKBMLLXDZSTBKLGGQKQLSBKKTFXRMDKBFTPZFRTBBRFERQGXYJPZSSTLBZTPSZQZSJDHLJQLZBPMSMMSXLQQNHKNBLRDDNXXDHDDJCYYGYLXGZLXSYGMQQGKHBPMXYXLYTQWLWGCPBMQXCYZYDRJBHTDJYHQSHTMJSBYPLWHLZFFNYPMHXXHPLTBQPFBJWQDBYGPNZTPFZJGSDDTQSHZEAWZZYLLTYYBWJKXXGHLFKXDJTMSZSQYNZGGSWQSPHTLSSKMCLZXYSZQZXNCJDQGZDLFNYKLJCJLLZLMZZNHYDSSHTHZZLZZBBHQZWWYCRZHLYQQJBEYFXXXWHSRXWQHWPSLMSSKZTTYGYQQWRSLALHMJTQJSMXQBJJZJXZYZKXBYQXBJXSHZTSFJLXMXZXFGHKZSZGGYLCLSARJYHSLLLMZXELGLXYDJYTLFBHBPNLYZFBBHPTGJKWETZHKJJXZXXGLLJLSTGSHJJYQLQZFKCGNNDJSSZFDBCTWWSEQFHQJBSAQTGYPQLBXBMMYWXGSLZHGLZGQYFLZBYFZJFRYSFMBYZHQGFWZSYFYJJPHZBYYZFFWODGRLMFTWLBZGYCQXCDJYGZYYYYTYTYDWEGAZYHXJLZYYHLRMGRXXZCLHNELJJTJTPWJYBJJBXJJTJTEEKHWSLJPLPSFYZPQQBDLQJJTYYQLYZKDKSQJYYQZLDQTGJQYZJSUCMRYQTHTEJMFCTYHYPKMHYZWJDQFHYYXWSHCTXRLJHQXHCCYYYJLTKTTYTMXGTCJTZAYYOCZLYLBSZYWJYTSJYHBYSHFJLYGJXXTMZYYLTXXYPZLXYJZYZYYPNHMYMDYYLBLHLSYYQQLLNJJYMSOYQBZGDLYXYLCQYXTSZEGXHZGLHWBLJHEYXTWQMAKBPQCGYSHHEGQCMWYYWLJYJHYYZLLJJYLHZYHMGSLJLJXCJJYCLYCJPCPZJZJMMYLCQLNQLJQJSXYJMLSZLJQLYCMMHCFMMFPQQMFYLQMCFFQMMMMHMZNFHHJGTTHHKHSLNCHHYQDXTMMQDCYZYXYQMYQYLTDCYYYZAZZCYMZYDLZFFFMMYCQZWZZMABTBYZTDMNZZGGDFTYPCGQYTTSSFFWFDTZQSSYSTWXJHXYTSXXYLBYQHWWKXHZXWZNNZZJZJJQJCCCHYYXBZXZCYZTLLCQXYNJYCYYCYNZZQYYYEWYCZDCJYCCHYJLBTZYYCQWMPWPYMLGKDLDLGKQQBGYCHJXY\”;
//此处收录了375个多音字,数据来自于http://www.51window.net/page/pinyin
var oMultiDiff = {\”19969\”:\”DZ\”, \”19975\”:\”WM\”, \”19988\”:\”QJ\”, \”20048\”:\”YL\”, \”20056\”:\”SC\”, \”20060\”:\”NM\”, \”20094\”:\”QG\”, \”20127\”:\”QJ\”, \”20167\”:\”QC\”, \”20193\”:\”YG\”, \”20250\”:\”KH\”, \”20256\”:\”ZC\”, \”20282\”:\”SC\”, \”20285\”:\”QJG\”, \”20291\”:\”TD\”, \”20314\”:\”YD\”, \”20340\”:\”NE\”, \”20375\”:\”TD\”, \”20389\”:\”YJ\”, \”20391\”:\”CZ\”, \”20415\”:\”PB\”, \”20446\”:\”YS\”, \”20447\”:\”SQ\”, \”20504\”:\”TC\”, \”20608\”:\”KG\”, \”20854\”:\”QJ\”, \”20857\”:\”ZC\”, \”20911\”:\”PF\”, \”20504\”:\”TC\”, \”20608\”:\”KG\”, \”20854\”:\”QJ\”, \”20857\”:\”ZC\”, \”20911\”:\”PF\”, \”20985\”:\”AW\”, \”21032\”:\”PB\”, \”21048\”:\”XQ\”, \”21049\”:\”SC\”, \”21089\”:\”YS\”, \”21119\”:\”JC\”, \”21242\”:\”SB\”, \”21273\”:\”SC\”, \”21305\”:\”YP\”, \”21306\”:\”QO\”, \”21330\”:\”ZC\”, \”21333\”:\”SDC\”, \”21345\”:\”QK\”, \”21378\”:\”CA\”, \”21397\”:\”SC\”, \”21414\”:\”XS\”, \”21442\”:\”SC\”, \”21477\”:\”JG\”, \”21480\”:\”TD\”, \”21484\”:\”ZS\”, \”21494\”:\”YX\”, \”21505\”:\”YX\”, \”21512\”:\”HG\”, \”21523\”:\”XH\”, \”21537\”:\”PB\”, \”21542\”:\”PF\”, \”21549\”:\”KH\”, \”21571\”:\”E\”, \”21574\”:\”DA\”, \”21588\”:\”TD\”, \”21589\”:\”O\”, \”21618\”:\”ZC\”, \”21621\”:\”KHA\”, \”21632\”:\”ZJ\”, \”21654\”:\”KG\”, \”21679\”:\”LKG\”, \”21683\”:\”KH\”, \”21710\”:\”A\”, \”21719\”:\”YH\”, \”21734\”:\”WOE\”, \”21769\”:\”A\”, \”21780\”:\”WN\”, \”21804\”:\”XH\”, \”21834\”:\”A\”, \”21899\”:\”ZD\”, \”21903\”:\”RN\”, \”21908\”:\”WO\”, \”21939\”:\”ZC\”, \”21956\”:\”SA\”, \”21964\”:\”YA\”, \”21970\”:\”TD\”, \”22003\”:\”A\”, \”22031\”:\”JG\”, \”22040\”:\”XS\”, \”22060\”:\”ZC\”, \”22066\”:\”ZC\”, \”22079\”:\”MH\”, \”22129\”:\”XJ\”, \”22179\”:\”XA\”, \”22237\”:\”NJ\”, \”22244\”:\”TD\”, \”22280\”:\”JQ\”, \”22300\”:\”YH\”, \”22313\”:\”XW\”, \”22331\”:\”YQ\”, \”22343\”:\”YJ\”, \”22351\”:\”PH\”, \”22395\”:\”DC\”, \”22412\”:\”TD\”, \”22484\”:\”PB\”, \”22500\”:\”PB\”, \”22534\”:\”ZD\”, \”22549\”:\”DH\”, \”22561\”:\”PB\”, \”22612\”:\”TD\”, \”22771\”:\”KQ\”, \”22831\”:\”HB\”, \”22841\”:\”JG\”, \”22855\”:\”QJ\”, \”22865\”:\”XQ\”, \”23013\”:\”ML\”, \”23081\”:\”WM\”, \”23487\”:\”SX\”, \”23558\”:\”QJ\”, \”23561\”:\”YW\”, \”23586\”:\”YW\”, \”23614\”:\”YW\”, \”23615\”:\”SN\”, \”23631\”:\”PB\”, \”23646\”:\”ZS\”, \”23663\”:\”ZT\”, \”23673\”:\”YG\”, \”23762\”:\”TD\”, \”23769\”:\”ZS\”, \”23780\”:\”QJ\”, \”23884\”:\”QK\”, \”24055\”:\”XH\”, \”24113\”:\”DC\”, \”24162\”:\”ZC\”, \”24191\”:\”GA\”, \”24273\”:\”QJ\”, \”24324\”:\”NL\”, \”24377\”:\”TD\”, \”24378\”:\”QJ\”, \”24439\”:\”PF\”, \”24554\”:\”ZS\”, \”24683\”:\”TD\”, \”24694\”:\”WE\”, \”24733\”:\”LK\”, \”24925\”:\”TN\”, \”25094\”:\”ZG\”, \”25100\”:\”XQ\”, \”25103\”:\”XH\”, \”25153\”:\”PB\”, \”25170\”:\”PB\”, \”25179\”:\”KG\”, \”25203\”:\”PB\”, \”25240\”:\”ZS\”, \”25282\”:\”FB\”, \”25303\”:\”NA\”, \”25324\”:\”KG\”, \”25341\”:\”ZY\”, \”25373\”:\”WZ\”, \”25375\”:\”XJ\”, \”25384\”:\”A\”, \”25457\”:\”A\”, \”25528\”:\”SD\”, \”25530\”:\”SC\”, \”25552\”:\”TD\”, \”25774\”:\”ZC\”, \”25874\”:\”ZC\”, \”26044\”:\”YW\”, \”26080\”:\”WM\”, \”26292\”:\”PB\”, \”26333\”:\”PB\”, \”26355\”:\”ZY\”, \”26366\”:\”CZ\”, \”26397\”:\”ZC\”, \”26399\”:\”QJ\”, \”26415\”:\”ZS\”, \”26451\”:\”SB\”, \”26526\”:\”ZC\”, \”26552\”:\”JG\”, \”26561\”:\”TD\”, \”26588\”:\”JG\”, \”26597\”:\”CZ\”, \”26629\”:\”ZS\”, \”26638\”:\”YL\”, \”26646\”:\”XQ\”, \”26653\”:\”KG\”, \”26657\”:\”XJ\”, \”26727\”:\”HG\”, \”26894\”:\”ZC\”, \”26937\”:\”ZS\”, \”26946\”:\”ZC\”, \”26999\”:\”KJ\”, \”27099\”:\”KJ\”, \”27449\”:\”YQ\”, \”27481\”:\”XS\”, \”27542\”:\”ZS\”, \”27663\”:\”ZS\”, \”27748\”:\”TS\”, \”27784\”:\”SC\”, \”27788\”:\”ZD\”, \”27795\”:\”TD\”, \”27812\”:\”O\”, \”27850\”:\”PB\”, \”27852\”:\”MB\”, \”27895\”:\”SL\”, \”27898\”:\”PL\”, \”27973\”:\”QJ\”, \”27981\”:\”KH\”, \”27986\”:\”HX\”, \”27994\”:\”XJ\”, \”28044\”:\”YC\”, \”28065\”:\”WG\”, \”28177\”:\”SM\”, \”28267\”:\”QJ\”, \”28291\”:\”KH\”, \”28337\”:\”ZQ\”, \”28463\”:\”TL\”, \”28548\”:\”DC\”, \”28601\”:\”TD\”, \”28689\”:\”PB\”, \”28805\”:\”JG\”, \”28820\”:\”QG\”, \”28846\”:\”PB\”, \”28952\”:\”TD\”, \”28975\”:\”ZC\”, \”29100\”:\”A\”, \”29325\”:\”QJ\”, \”29575\”:\”SL\”, \”29602\”:\”FB\”, \”30010\”:\”TD\”, \”30044\”:\”CX\”, \”30058\”:\”PF\”, \”30091\”:\”YSP\”, \”30111\”:\”YN\”, \”30229\”:\”XJ\”, \”30427\”:\”SC\”, \”30465\”:\”SX\”, \”30631\”:\”YQ\”, \”30655\”:\”QJ\”, \”30684\”:\”QJG\”, \”30707\”:\”SD\”, \”30729\”:\”XH\”, \”30796\”:\”LG\”, \”30917\”:\”PB\”, \”31074\”:\”NM\”, \”31085\”:\”JZ\”, \”31109\”:\”SC\”, \”31181\”:\”ZC\”, \”31192\”:\”MLB\”, \”31293\”:\”JQ\”, \”31400\”:\”YX\”, \”31584\”:\”YJ\”, \”31896\”:\”ZN\”, \”31909\”:\”ZY\”, \”31995\”:\”XJ\”, \”32321\”:\”PF\”, \”32327\”:\”ZY\”, \”32418\”:\”HG\”, \”32420\”:\”XQ\”, \”32421\”:\”HG\”, \”32438\”:\”LG\”, \”32473\”:\”GJ\”, \”32488\”:\”TD\”, \”32521\”:\”QJ\”, \”32527\”:\”PB\”, \”32562\”:\”ZSQ\”, \”32564\”:\”JZ\”, \”32735\”:\”ZD\”, \”32793\”:\”PB\”, \”33071\”:\”PF\”, \”33098\”:\”XL\”, \”33100\”:\”YA\”, \”33152\”:\”PB\”, \”33261\”:\”CX\”, \”33324\”:\”BP\”, \”33333\”:\”TD\”, \”33406\”:\”YA\”, \”33426\”:\”WM\”, \”33432\”:\”PB\”, \”33445\”:\”JG\”, \”33486\”:\”ZN\”, \”33493\”:\”TS\”, \”33507\”:\”QJ\”, \”33540\”:\”QJ\”, \”33544\”:\”ZC\”, \”33564\”:\”XQ\”, \”33617\”:\”YT\”, \”33632\”:\”QJ\”, \”33636\”:\”XH\”, \”33637\”:\”YX\”, \”33694\”:\”WG\”, \”33705\”:\”PF\”, \”33728\”:\”YW\”, \”33882\”:\”SR\”, \”34067\”:\”WM\”, \”34074\”:\”YW\”, \”34121\”:\”QJ\”, \”34255\”:\”ZC\”, \”34259\”:\”XL\”, \”34425\”:\”JH\”, \”34430\”:\”XH\”, \”34485\”:\”KH\”, \”34503\”:\”YS\”, \”34532\”:\”HG\”, \”34552\”:\”XS\”, \”34558\”:\”YE\”, \”34593\”:\”ZL\”, \”34660\”:\”YQ\”, \”34892\”:\”XH\”, \”34928\”:\”SC\”, \”34999\”:\”QJ\”, \”35048\”:\”PB\”, \”35059\”:\”SC\”, \”35098\”:\”ZC\”, \”35203\”:\”TQ\”, \”35265\”:\”JX\”, \”35299\”:\”JX\”, \”35782\”:\”SZ\”, \”35828\”:\”YS\”, \”35830\”:\”E\”, \”35843\”:\”TD\”, \”35895\”:\”YG\”, \”35977\”:\”MH\”, \”36158\”:\”JG\”, \”36228\”:\”QJ\”, \”36426\”:\”XQ\”, \”36466\”:\”DC\”, \”36710\”:\”JC\”, \”36711\”:\”ZYG\”, \”36767\”:\”PB\”, \”36866\”:\”SK\”, \”36951\”:\”YW\”, \”37034\”:\”YX\”, \”37063\”:\”XH\”, \”37218\”:\”ZC\”, \”37325\”:\”ZC\”, \”38063\”:\”PB\”, \”38079\”:\”TD\”, \”38085\”:\”QY\”, \”38107\”:\”DC\”, \”38116\”:\”TD\”, \”38123\”:\”YD\”, \”38224\”:\”HG\”, \”38241\”:\”XTC\”, \”38271\”:\”ZC\”, \”38415\”:\”YE\”, \”38426\”:\”KH\”, \”38461\”:\”YD\”, \”38463\”:\”AE\”, \”38466\”:\”PB\”, \”38477\”:\”XJ\”, \”38518\”:\”YT\”, \”38551\”:\”WK\”, \”38585\”:\”ZC\”, \”38704\”:\”XS\”, \”38739\”:\”LJ\”, \”38761\”:\”GJ\”, \”38808\”:\”SQ\”, \”39048\”:\”JG\”, \”39049\”:\”XJ\”, \”39052\”:\”HG\”, \”39076\”:\”CZ\”, \”39271\”:\”XT\”, \”39534\”:\”TD\”, \”39552\”:\”TD\”, \”39584\”:\”PB\”, \”39647\”:\”SB\”, \”39730\”:\”LG\”, \”39748\”:\”TPB\”, \”40109\”:\”ZQ\”, \”40479\”:\”ND\”, \”40516\”:\”HG\”, \”40536\”:\”HG\”, \”40583\”:\”QJ\”, \”40765\”:\”YQ\”, \”40784\”:\”QJ\”, \”40840\”:\”YK\”, \”40863\”:\”QJG\”};
//参数,中文字符串
//返回值:拼音首字母串数组
function makePy() {
var str = document.getElementById(\”text\”).value;
if (typeof (str) != \”string\”) {
throw new Error(-1, \”\\u51fd\\u6570makePy\\u9700\\u8981\\u5b57\\u7b26\\u4e32\\u7c7b\\u578b\\u53c2\\u6570!\”);
}
var arrResult = new Array(); //保存中间结果的数组
for (var i = 0, len = str.length; i < len; i++) {
//获得unicode码
var ch = str.charAt(i);
//检查该unicode码是否在处理范围之内,在则返回该码对映汉字的拼音首字母,不在则调用其它函数处理
arrResult.push(checkCh(ch));
}
//处理arrResult,返回所有可能的拼音首字母串数组
document.getElementById(\”text_value\”).innerHTML = mkRslt(arrResult)
return mkRslt(arrResult);
}
function checkCh(ch) {
var uni = ch.charCodeAt(0);
//如果不在汉字处理范围之内,返回原字符,也可以调用自己的处理函数
if (uni > 40869 || uni < 19968) {
return ch;
} //dealWithOthers(ch);
//检查是否是多音字,是按多音字处理,不是就直接在strChineseFirstPY字符串中找对应的首字母
return (oMultiDiff[uni] ? oMultiDiff[uni] : (strChineseFirstPY.charAt(uni – 19968)));
}
function mkRslt(arr) {
var arrRslt = [\”\”];
for (var i = 0, len = arr.length; i < len; i++) {
var str = arr[i];
var strlen = str.length;
if (strlen == 1) {
for (var k = 0; k < arrRslt.length; k++) {
arrRslt[k] += str;
console.log(str)
}
} else {
var tmpArr = arrRslt.slice(0);
arrRslt = [];
for (k = 0; k < strlen; k++) {
//复制一个相同的arrRslt
var tmp = tmpArr.slice(0);
//把当前字符str[k]添加到每个元素末尾
for (var j = 0; j < tmp.length; j++) {
tmp[j] += str.charAt(k);
}
//把复制并修改后的数组连接到arrRslt上
arrRslt = arrRslt.concat(tmp);
}
}
}
return arrRslt;
}
// //两端去空格函数
// String.prototype.trim = function () {
// return this.replace(/(^\\s*)|(\\s*$)/g, \”\”);
// };
</script>
</body>
</html>
原文链接:https://blog.csdn.net/ZXW_Future/article/details/89048811
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。