<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">%%
%% This is file `xeCJK.sty',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% xeCJK.dtx  (with options: `package')
%% 
%% $Id: xeCJK.dtx 358 2012-10-27 11:52:01Z sobenlee $
%% $URL: https://ctex-kit.googlecode.com/svn/trunk/xeCJK/xeCJK.dtx $
%% -----------------------------------------------------------------
%%    Author:
%%             Wenchang Sun    &lt;sunwch@nankai.edu.cn&gt;
%%    Current Maintainers:
%%             Leo Liu         &lt;leoliu.pku@gmail.com&gt;
%%             Qing Lee        &lt;sobenlee@gmail.com&gt;
%% 
%%    Copyright (C) 2007--2012 Wenchang Sun
%% 
%%    This file may be distributed and/or modified under the
%%    conditions of the LaTeX Project Public License, either version 1.3
%%    of this license or (at your option) any later version.
%%    The latest version of this license is in
%%       http://www.latex-project.org/lppl.txt
%%    and version 1.3 or later is part of all distributions of LaTeX
%%    version 2005/12/01 or later.
%% 
%%    This work has the LPPL maintenance status "maintained".
%%    The Current Maintainer of this work are Leo Liu and Qing Lee.
%% -----------------------------------------------------------------
%% 
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{expl3}
\GetIdInfo$Id: xeCJK.dtx 358 2012-10-27 11:52:01Z sobenlee $
          {package for typesetting CJK scripts with XeLaTeX}
\ProvidesExplPackage
  {\ExplFileName}
  {\ExplFileDate}{3.0.10}{\ExplFileDescription}
\msg_new:nnn { xeCJK } { Require-XeTeX }
  {
    The~xeCJK~package~requires~XeTeX~to~function.\\\\
    You~must~change~your~typesetting~engine~to~"xelatex" \\
    instead~of~plain~"latex"~or~"pdflatex"~or~"lualatex".\\
    Loading~xeCJK~will~abort!
  }
\xetex_if_engine:F { \msg_critical:nn { xeCJK } { Require-XeTeX } }
\msg_new:nnn { xeCJK } { l3-too-old }
  {
    Support~package~'expl3'~too~old. \\\\
    Please~update~an~up~to~date~version~of~the~bundles\\\\
    'l3kernel'~and~'l3packages'\\\\
    using~your~TeX~package~manager~or~from~CTAN.\\
    Loading~xeCJK~will~abort!
  }
\@ifpackagelater { expl3 } { 2012/09/10 } { }
  { \msg_critical:nn { xeCJK } { l3-too-old } }
\RequirePackage{xparse}
\RequirePackage{l3keys2e}
\msg_new:nnn { xeCJK } { XeTeX-too-old }
  {
    \token_to_str:N \XeTeXglyphbounds \ is~not~defined.\\\\
    You~have~to~update~XeTeX~to~the~version~0.9995.0~or~later.
  }
\cs_if_free:NT \XeTeXglyphbounds
  {
    \msg_error:nn { xeCJK } { XeTeX-too-old }
    \AtEndOfPackage { \__xeCJK_AfterPreamble:n { \punctstyle { plain } } }
  }
\int_new:N \l__xeCJK_tmpa_int
\int_new:N \l__xeCJK_tmpb_int
\int_new:N \l__xeCJK_tmpc_int
\dim_new:N \l__xeCJK_tmpa_dim
\dim_new:N \l__xeCJK_tmpb_dim
\dim_new:N \l__xeCJK_tmpc_dim
\tl_new:N \l__xeCJK_tmpa_tl
\tl_new:N \l__xeCJK_tmpb_tl
\clist_new:N \l__xeCJK_tmpa_clist
\clist_new:N \l__xeCJK_tmpb_clist
\clist_new:N \l__xeCJK_tmpc_clist
\cs_new_protected_nopar:Npn \xeCJK_no_break: { \tex_penalty:D \c_ten_thousand }
\tl_new:N \g__xeCJK_at_end_preamble_hook_tl
\tl_new:N \g__xeCJK_after_preamble_hook_tl
\tl_new:N \g__xeCJK_after_end_preamble_hook_tl
\cs_new_protected:Npn \__xeCJK_AtEndPreamble:n #1
  { \tl_gput_right:Nn \g__xeCJK_at_end_preamble_hook_tl {#1} }
\cs_new_protected:Npn \__xeCJK_AfterPreamble:n #1
  { \tl_gput_right:Nn \g__xeCJK_after_preamble_hook_tl {#1} }
\cs_new_protected:Npn \__xeCJK_AfterEndPreamble:n #1
  { \tl_gput_right:Nn \g__xeCJK_after_end_preamble_hook_tl {#1} }
\AtBeginDocument { \g__xeCJK_after_preamble_hook_tl }
\tl_put_left:Nn  \document { \group_end: \g__xeCJK_at_end_preamble_hook_tl \group_begin: }
\tl_put_right:Nn \document { \g__xeCJK_after_end_preamble_hook_tl \tex_ignorespaces:D }
\group_begin:
\char_set_lccode:nn { `\Z } { `\t }
\char_set_lccode:nn { `\Y } { `\c }
\char_set_lccode:nn { `\; } { `\: }
\char_set_lccode:nn { `\/ } { `\\ }
\tl_map_inline:nn { \T \F \C \J \K } { \char_set_lccode:nn { `#1 } { `#1 } }
\tl_map_function:nN { \O \U \Z \E \R \M \A \Y \R \; \/ } \char_set_catcode_other:N
\tl_to_lowercase:n
  {
    \group_end:
    \prg_new_conditional:Npnn \xeCJK_if_outer_macro:c #1 { p , T , F , TF }
      {
        \exp_last_unbraced:Nf \__xeCJK_if_outer_macro_aux:w
          { \cs_meaning:c {#1} } OUZER ~ MAYRO ; \q_stop
      }
    \cs_new_nopar:Npn \__xeCJK_if_outer_macro_aux:w #1 OUZER ~ MAYRO ; #2 \q_stop
      {
        \if_cs_exist:w c__xeCJK_prefix_#1_aux_tl \cs_end:
          \prg_return_true: \else: \prg_return_false: \fi:
      }
    \tl_new:c { c__xeCJK_prefix_/_aux_tl }
    \tl_new:c { c__xeCJK_prefix_/long/_aux_tl }
    \tl_new:c { c__xeCJK_prefix_/protected/_aux_tl }
    \tl_new:c { c__xeCJK_prefix_/protected/long/_aux_tl }
  }
\token_new:Nn \l__xeCJK_peek_search_token { ? }
\cs_new_protected:Npn \xeCJK_peek_catcode_ignore_spaces:NTF #1#2#3
  {
    \cs_set_eq:NN \l__xeCJK_peek_search_token #1 \prg_do_nothing:
    \tl_set:Nn \__xeCJK_peek_true:w  { \group_align_safe_end: #2 }
    \tl_set:Nn \__xeCJK_peek_false:w { \group_align_safe_end: #3 }
    \group_align_safe_begin:
    \peek_after:Nw \__xeCJK_peek_ignore_spaces_execute_branches:
  }
\cs_new_protected:Npn \xeCJK_peek_catcode_ignore_spaces:NT #1#2
  { \xeCJK_peek_catcode_ignore_spaces:NTF #1 {#2} { } }
\cs_new_protected:Npn \xeCJK_peek_catcode_ignore_spaces:NF #1#2
  { \xeCJK_peek_catcode_ignore_spaces:NTF #1 { } {#2} }
\cs_new_nopar:Npn \__xeCJK_peek_ignore_spaces_execute_branches:
  {
    \if_meaning:w \l_peek_token \c_space_token
      \tex_afterassignment:D \__xeCJK_peek_ignore_spaces_execute_branches_aux:
      \exp_after:wN \cs_set_eq:NN \exp_after:wN \__xeCJK_peek_tmp:w
    \else:
      \exp_after:wN \__xeCJK_peek_execute_branches_catcode:
    \fi:
  }
\cs_new_protected_nopar:Npn \__xeCJK_peek_ignore_spaces_execute_branches_aux:
  { \peek_after:Nw \__xeCJK_peek_ignore_spaces_execute_branches: }
\cs_new_nopar:Npn \__xeCJK_peek_execute_branches_catcode:
  {
    \if_catcode:w \exp_not:N \l_peek_token \exp_not:N \l__xeCJK_peek_search_token
      \exp_after:wN \__xeCJK_peek_true:w
    \else:
      \exp_after:wN \__xeCJK_peek_false:w
    \fi:
  }
\prg_new_conditional:Npnn \xeCJK_if_blank_x:n #1 { p , T , F , TF }
  {
    \if_int_compare:w \pdftex_strcmp:D { \c_empty_tl } {#1} = \c_zero
      \prg_return_true:
    \else:
      \if_int_compare:w \pdftex_strcmp:D { \c_space_tl } {#1} = \c_zero
        \prg_return_true: \else: \prg_return_false: \fi:
    \fi:
  }
\prg_new_conditional:Npnn \xeCJK_if_package_loaded:n #1 { p , T , F , TF }
  {
    \tl_if_exist:cTF { ver@ #1 . \c__xeCJK_pkg_extension_tl }
      { \prg_return_true: } { \prg_return_false: }
  }
\tl_const:Nx \c__xeCJK_pkg_extension_tl { \@pkgextension }
\cs_new_nopar:Npn \__xeCJK_msg_new:nn  { \msg_new:nnn      { xeCJK } }
\cs_new_nopar:Npn \__xeCJK_error:n     { \msg_error:nn     { xeCJK } }
\cs_new_nopar:Npn \__xeCJK_error:nx    { \msg_error:nnx    { xeCJK } }
\cs_new_nopar:Npn \__xeCJK_warning:n   { \msg_warning:nn   { xeCJK } }
\cs_new_nopar:Npn \__xeCJK_warning:nx  { \msg_warning:nnx  { xeCJK } }
\cs_new_nopar:Npn \__xeCJK_warning:nxx { \msg_warning:nnxx { xeCJK } }
\cs_new_nopar:Npn \__xeCJK_info:nx     { \msg_info:nnx     { xeCJK } }
\cs_new_nopar:Npn \__xeCJK_info:nxx    { \msg_info:nnxx    { xeCJK } }
\keys_define:nn { xeCJK / options }
  {
    xeCJKactive .choice:,
    xeCJKactive / true  .code:n = { \makexeCJKactive   } ,
    xeCJKactive / false .code:n = { \makexeCJKinactive } ,
    xeCJKactive      .default:n = { true },
  }
\NewDocumentCommand \makexeCJKactive   { } { \XeTeXinterchartokenstate = \c_one  }
\NewDocumentCommand \makexeCJKinactive { } { \XeTeXinterchartokenstate = \c_zero }
\char_set_catcode_ignore:n { "FEFF }
\int_const:Nn \c__xeCJK_Default_class_int   {   0 }
\int_const:Nn \c__xeCJK_CJK_class_int       {   1 }
\int_const:Nn \c__xeCJK_FullLeft_class_int  {   2 }
\int_const:Nn \c__xeCJK_FullRight_class_int {   3 }
\int_const:Nn \c__xeCJK_Boundary_class_int  { 255 }
\cs_new_protected_nopar:Npn \__xeCJK_new_class:n #1
  {
    \exp_args:Nc \newXeTeXintercharclass { c__xeCJK_#1_class_int }
    \clist_gclear_new:c { g__xeCJK_#1_range_clist }
    \seq_gput_right:Nv \g__xeCJK_class_seq { c__xeCJK_#1_class_int }
  }
\seq_new:N \g__xeCJK_class_seq
\__xeCJK_new_class:n { HalfLeft }
\__xeCJK_new_class:n { HalfRight }
\__xeCJK_new_class:n { NormalSpace }
\clist_set:Nn \g__xeCJK_base_class_clist
  {
    Default, CJK, FullLeft, FullRight, Boundary,
    HalfLeft, HalfRight, NormalSpace
  }
\clist_map_inline:Nn \g__xeCJK_base_class_clist
  { \clist_gclear_new:c { g__xeCJK_#1_range_clist } }
\clist_new:N \g__xeCJK_CJK_class_clist
\prop_new:N \g__xeCJK_CJK_class_prop
\cs_new_protected_nopar:Npn \__xeCJK_save_CJK_class:n #1
  {
    \clist_gput_right:Nx \g__xeCJK_CJK_class_clist {#1}
    \prop_gput:Nvx \g__xeCJK_CJK_class_prop { c__xeCJK_#1_class_int } {#1}
  }
\cs_generate_variant:Nn \prop_gput:Nnn { Nvx }
\clist_map_function:nN { CJK, FullLeft, FullRight } \__xeCJK_save_CJK_class:n
\cs_new_nopar:Npn \__xeCJK_class_num:n #1 { \tl_use:c { c__xeCJK_#1_class_int } }
\NewDocumentCommand \xeCJKDeclareCharClass { s &gt; { \TrimSpaces } m m }
  {
    \__xeCJK_declare_char_class:nn {#2} {#3}
    \IfBooleanT {#1} { \xeCJKResetPunctClass }
  }
\cs_new_protected_nopar:Npn \__xeCJK_declare_char_class:nn #1#2
  {
    \clist_gput_right:cx { g__xeCJK_#1_range_clist } {#2}
    \clist_map_inline:xn {#2}
      {
        \str_if_eq_x:nnF {##1} { -&gt; }
          {
            \__xeCJK_set_char_class_aux:Nn \__xeCJK_set_char_class:nnn {##1}
            { \__xeCJK_class_num:n {#1} }
          }
      }
  }
\NewDocumentCommand \__xeCJK_set_char_class_aux:Nn
  { m &gt; { \SplitArgument { 1 } { -&gt; } } m } { #1 #2 }
\cs_generate_variant:Nn \clist_map_inline:nn { x }
\NewDocumentCommand \xeCJKsetcharclass { s m m m }
  {
    \__xeCJK_set_char_class:nnn {#2} {#3} {#4}
    \IfBooleanF {#1} { \xeCJKResetPunctClass }
  }
\cs_new_protected_nopar:Npn \__xeCJK_set_char_class:nnn #1#2#3
  {
    \__xeCJK_check_num_range:nnNN {#1} {#2} \l__xeCJK_tmpa_int \l__xeCJK_tmpb_int
    \int_set:Nn \l__xeCJK_tmpc_int {#3}
    \prop_if_in:NVTF \g__xeCJK_CJK_class_prop \l__xeCJK_tmpc_int
      { \cs_set_eq:NN \__xeCJK_set_char_catcode:n \char_set_catcode_other:n }
      { \cs_set_eq:NN \__xeCJK_set_char_catcode:n \use_none:n }
    \xeCJK_int_until_do:nn { \l__xeCJK_tmpa_int &gt; \l__xeCJK_tmpb_int }
      {
        \__xeCJK_set_char_catcode:n { \l__xeCJK_tmpa_int }
        \XeTeXcharclass \l__xeCJK_tmpa_int = \l__xeCJK_tmpc_int
        \int_incr:N \l__xeCJK_tmpa_int
      }
  }
\cs_new_protected:Npn \xeCJK_int_until_do:nn #1#2
  {
    \__xeCJK_int_until_do_aux:wn \use_none:n
      { \reverse_if:N \if_int_compare:w #1#2 }
  }
\cs_new_protected:Npn \__xeCJK_int_until_do_aux:wn \use_none:n #1
  {
    #1 \exp_after:wN \__xeCJK_int_until_do_aux:wn \fi:
    \use_none:n {#1}
  }
\cs_new_protected_nopar:Npn \__xeCJK_check_num_range:nnNN #1#2#3#4
  {
    \bool_if:nTF { \xeCJK_if_blank_x_p:n {#1} || \xeCJK_if_blank_x_p:n {#2} }
      {
        \int_set:Nn #3 { \xeCJK_if_blank_x:nTF {#1} {#2} {#1} }
        \int_set_eq:NN #3 #4
      }
      {
        \int_set:Nn #3 { \int_min:nn {#1} { \IfNoValueTF {#2} {#1} {#2} } }
        \int_set:Nn #4 { \int_max:nn {#1} { \IfNoValueTF {#2} {#1} {#2} } }
      }
  }
\NewDocumentCommand \xeCJKResetPunctClass { }
  {
    \__xeCJK_declare_char_class:nn { HalfLeft }
      { "28 , "2D , "5B , "60 , "7B }
    \__xeCJK_declare_char_class:nn { HalfRight }
      { "21 , "22 , "25 , "27 , "29 , "2C , "2E , "3A , "3B , "3F , "5D , "7D , }
    \__xeCJK_declare_char_class:nn { FullLeft }
      {
        "2018 , "201C , "2116 , "3008 , "300A , "300C , "300E , "3010 , "3012 ,
        "3014 , "3016 , "3018 , "301A , "301D , "3036 , "E76C , "FE59 , "FE5B ,
        "FE5D , "FE5F , "FE60 , "FE69 , "FE6B , "FF03 , "FF04 , "FF08 , "FF20 ,
        "FF3B , "FF5B , "FFE0 , "FFE1 , "FFE5 , "FFE6 ,
      }
    \__xeCJK_declare_char_class:nn { FullRight }
      {
        "00B7 , "2019 , "201D , "2014 , "2015 , "2025 , "2026 , "2030 , "2500 ,
        "3001 , "3002 , "3005 , "3006 , "3009 , "300B , "300D , "300F , "3011 ,
        "3015 , "3017 , "3019 , "301B , "301E , "301F , "3041 , "3043 , "3045 ,
        "3047 , "3049 , "3063 , "3083 , "3085 , "3087 , "308E , "309B , "309C ,
        "309D , "309E , "30A1 , "30A3 , "30A5 , "30A7 , "30A9 , "30C3 , "30E3 ,
        "30E5 , "30E7 , "30EE , "30F5 , "30F6 , "30FB , "30FC , "30FD , "30FE ,
        "FE50 , "FE51 , "FE52 , "FE54 , "FE55 , "FE56 , "FE57 , "FE5A , "FE5C ,
        "FE5E , "FE6A , "FF01 , "FF05 , "FF09 , "FF0C , "FF0E , "FF1A , "FF1B ,
        "FF1F , "FF3D , "FF5D , "FF61 , "FF63 , "FF64 , "FF65 , "FF67 , "FF68 ,
        "FF69 , "FF6A , "FF6B , "FF6C , "FF6D , "FF6E , "FF6F , "FF70 , "FF9E ,
        "FF9F ,
      }
  }
\__xeCJK_declare_char_class:nn { CJK }
  {
    "1100 -&gt; "11FF ,
    "2E80 -&gt; "2EFF ,
    "2F00 -&gt; "2FDF ,
    "2FF0 -&gt; "2FFF ,
    "3000 -&gt; "303F ,
    "3040 -&gt; "309F ,
    "30A0 -&gt; "30FF ,
    "3100 -&gt; "312F ,
    "3130 -&gt; "318F ,
    "3190 -&gt; "319F ,
    "31A0 -&gt; "31BF ,
    "31C0 -&gt; "31EF ,
    "31F0 -&gt; "31FF ,
    "3200 -&gt; "32FF ,
    "3300 -&gt; "33FF ,
    "3400 -&gt; "4DBF ,
    "4DC0 -&gt; "4DFF ,
    "4E00 -&gt; "9FFF ,
    "A000 -&gt; "A48F ,
    "A490 -&gt; "A4CF ,
    "A960 -&gt; "A97F ,
    "AC00 -&gt; "D7AF ,
    "B000 -&gt; "B0FF ,
    "D7B0 -&gt; "D7FF ,
    "F900 -&gt; "FAFF ,
    "FE30 -&gt; "FE4F ,
    "FF00 -&gt; "FFEF ,
    "20000 -&gt; "2A6DF ,
    "2A700 -&gt; "2B73F ,
    "2B740 -&gt; "2B81F ,
    "2F800 -&gt; "2FA1F ,
  }
\xeCJKResetPunctClass
\NewDocumentCommand \normalspacedchars { m }
  {
    \tl_map_inline:nn {#1}
      { \XeTeXcharclass `##1 = \__xeCJK_class_num:n { NormalSpace } }
  }
\normalspacedchars{/}
\cs_new_protected_nopar:Npn \__xeCJK_inter_class_toks:nnn #1#2#3
  { \XeTeXinterchartoks \__xeCJK_class_num:n {#1} \__xeCJK_class_num:n {#2} = {#3} }
\cs_generate_variant:Nn \__xeCJK_inter_class_toks:nnn { nnc , nnx }
\cs_new_nopar:Npn \__xeCJK_get_inter_class_toks:nn #1#2
  { \tex_the:D \XeTeXinterchartoks \__xeCJK_class_num:n {#1} \__xeCJK_class_num:n {#2} }
\cs_new_protected_nopar:Npn \__xeCJK_clear_inter_class_toks:nn #1#2
  { \__xeCJK_inter_class_toks:nnn {#1} {#2} { \c_empty_tl } }
\cs_new_protected_nopar:Npn \__xeCJK_pre_inter_class_toks:nnn #1#2#3
  {
    \__xeCJK_inter_class_toks:nnx {#1} {#2}
      { \exp_not:n {#3} \__xeCJK_get_inter_class_toks:nn {#1} {#2} }
  }
\cs_new_protected_nopar:Npn \__xeCJK_app_inter_class_toks:nnn #1#2#3
  {
    \__xeCJK_inter_class_toks:nnx {#1} {#2}
      { \__xeCJK_get_inter_class_toks:nn {#1} {#2} \exp_not:n {#3} }
  }
\cs_generate_variant:Nn \__xeCJK_app_inter_class_toks:nnn { nnc }
\cs_new_protected_nopar:Npn \__xeCJK_copy_inter_class_toks:nnnn #1#2#3#4
  {
    \__xeCJK_inter_class_toks:nnx {#1} {#2}
      { \__xeCJK_get_inter_class_toks:nn {#3} {#4} }
  }
\cs_new_protected_nopar:Npn \__xeCJK_clear_CJK_toks:
  {
    \clist_map_inline:Nn \g__xeCJK_CJK_class_clist
      { \__xeCJK_clear_inter_class_toks:nn { Boundary } {##1} }
  }
\clist_map_inline:nn { Default, HalfLeft, HalfRight, NormalSpace }
  {
    \clist_map_inline:nn { CJK, FullLeft, FullRight }
      {
        \__xeCJK_inter_class_toks:nnn {#1} {##1}
          {
            \c_group_begin_token
            \xeCJK_select_font:
            \__xeCJK_clear_inter_class_toks:nn {#1} {##1}
            \__xeCJK_clear_CJK_toks:
          }
        \__xeCJK_inter_class_toks:nnn {##1} {#1} { \c_group_end_token }
      }
    \__xeCJK_app_inter_class_toks:nnn {#1} { CJK } { \CJKsymbol }
    \clist_map_inline:nn { FullLeft, FullRight }
      { \__xeCJK_app_inter_class_toks:nnc {#1} {##1} { xeCJK_CJK_and_##1:N } }
  }
\clist_map_inline:nn { Default, HalfLeft, NormalSpace }
  {
    \__xeCJK_inter_class_toks:nnn { Boundary } {#1}
      {
        \bool_if:nTF
          {
            \l__xeCJK_xecglue_bool &amp;&amp;
            \int_compare_p:nNn \etex_lastnodetype:D = \c_eleven &amp;&amp;
            \skip_if_eq_p:nn \tex_lastskip:D \l__xeCJK_space_glue_tl
          }
          {
            \tex_unskip:D
            \bool_if:nTF
              { \xeCJK_if_last_node_p:n { CJK } || \xeCJK_if_last_node_p:n { CJK_space } }
              { \CJKecglue } { \c_space_token }
          }
          {
            \xeCJK_if_last_node:nTF { CJK } { \CJKecglue }
              { \xeCJK_if_last_node:nT { CJK_space } { \__xeCJK_space_or_xecglue: } }
          }
      }
    \str_if_eq_x:nnF {#1} { NormalSpace }
      { \__xeCJK_app_inter_class_toks:nnn { CJK } {#1} { \CJKecglue } }
  }
\clist_map_inline:nn { Default, HalfRight, NormalSpace }
  {
    \__xeCJK_inter_class_toks:nnn {#1} { Boundary }
      {
        \peek_catcode:NTF \c_space_token
          { { \xeCJK_make_node:n { default_space } } }
          { { \xeCJK_make_node:n { default } } }
      }
    \str_if_eq_x:nnF {#1} { NormalSpace }
      { \__xeCJK_pre_inter_class_toks:nnn {#1} { CJK } { \CJKecglue } }
  }
\__xeCJK_inter_class_toks:nnn { Boundary } { CJK } { \xeCJK_Boundary_and_CJK: }
\cs_new_protected_nopar:Npn \xeCJK_Boundary_and_CJK:
  {
    { \__xeCJK_check_for_glue: }
    \c_group_begin_token
    \__xeCJK_clear_CJK_toks:
    \xeCJK_select_font:
    \CJKsymbol
  }
\cs_new_protected_nopar:Npn \__xeCJK_check_for_glue:
  {
    \bool_if:nTF
      { \xeCJK_if_last_node_p:n { CJK } || \xeCJK_if_last_node_p:n { CJK_space } }
      { \CJKglue }
      {
        \bool_if:nTF
          {
            \xeCJK_if_last_node_p:n { default }              ||
            \int_compare_p:nNn \etex_lastnodetype:D = \c_ten ||
            \xeCJK_if_last_node_p:n { default_itcorr }
          }
          { \CJKecglue }
          {
            \bool_if:nT
              {
                \l__xeCJK_xecglue_bool &amp;&amp;
                \int_compare_p:nNn \etex_lastnodetype:D = \c_eleven &amp;&amp;
                ( \skip_if_eq_p:nn \tex_lastskip:D \l__xeCJK_space_glue_tl ||
                  \dim_compare_p:nNn \tex_lastskip:D = \l__xeCJK_ecglue_dim )
              }
              {
                \tex_unskip:D
                \bool_if:nTF
                  {
                    \xeCJK_if_last_node_p:n { default_space }        ||
                    \int_compare_p:nNn \etex_lastnodetype:D = \c_ten ||
                    \xeCJK_if_last_node_p:n { default }              ||
                    \xeCJK_if_last_node_p:n { default_itcorr }
                  }
                  { \CJKecglue }
                  {
                    \bool_if:nTF
                      {
                        \xeCJK_if_last_node_p:n { CJK }       ||
                        \xeCJK_if_last_node_p:n { CJK_space }
                      }
                      { \bool_if:NTF \l__xeCJK_space_bool \c_space_token \CJKglue }
                      { \c_space_token }
                  }
              }
          }
      }
  }
\tl_set:Nn \l__xeCJK_space_glue_tl
  {
    \tex_fontdimen:D \c_two \tex_font:D
    \@plus  \tex_fontdimen:D \c_three \tex_font:D
    \@minus \tex_fontdimen:D \c_four  \tex_font:D
  }
\__xeCJK_inter_class_toks:nnn { CJK } { Boundary }
  {
    \c_group_end_token
    { \xeCJK_make_node:n { CJK } }
    \xeCJK_ignorespaces:
  }
\__xeCJK_inter_class_toks:nnn { CJK } { CJK } { \xeCJK_CJK_and_CJK:N }
\cs_new_protected_nopar:Npn \xeCJK_CJK_and_CJK:N #1 { \CJKglue \CJKsymbol {#1} }
\clist_map_inline:nn { FullLeft, FullRight }
  {
    \__xeCJK_inter_class_toks:nnn { Boundary } {#1}
      {
        \c_group_begin_token
        \__xeCJK_clear_CJK_toks:
        \xeCJK_select_font:
        \use:c { xeCJK_CJK_and_#1:N }
      }
    \__xeCJK_inter_class_toks:nnn {#1} { CJK } { \CJKsymbol }
    \__xeCJK_inter_class_toks:nnn {#1} { Boundary } { \c_group_end_token \tex_ignorespaces:D }
  }
\clist_map_inline:Nn \g__xeCJK_base_class_clist
  {
    \bool_if:nF
      { \str_if_eq_x_p:nn {#1} { FullLeft } || \str_if_eq_x_p:nn {#1} { FullRight } }
      {
        \__xeCJK_pre_inter_class_toks:nnn { FullLeft }  {#1} { \xeCJK_no_break: }
        \__xeCJK_pre_inter_class_toks:nnn { FullRight } {#1} { \xeCJK_after_FullRight: }
      }
  }
\clist_map_inline:nn { CJK, FullLeft, FullRight }
  {
    \clist_map_inline:nn { FullLeft, FullRight }
      { \__xeCJK_inter_class_toks:nnc {#1} {##1} { xeCJK_#1_and_##1:N } }
  }
\cs_new_protected_nopar:Npn \__xeCJK_punct_rule:n #1
  {
    \tex_vrule:D
      \@width  \dim_eval:c { \l__xeCJK_punct_coor_tl/rule/#1 }
      \@depth  \c_zero_dim
      \@height \c_zero_dim \scan_stop:
  }
\cs_new_protected_nopar:Npn \__xeCJK_punct_glue:n #1
  {
    \skip_horizontal:n
      {
        \dim_eval:c { \l__xeCJK_punct_coor_tl/glue/#1 }
        \@plus  \dim_eval:n { ( \tl_use:c { \l__xeCJK_punct_coor_tl/glue/#1 } ) /4 }
        \@minus \dim_eval:n { ( \tl_use:c { \l__xeCJK_punct_coor_tl/glue/#1 } ) /2 }
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_punct_kern:n #1
  { \tex_kern:D \dim_eval:c { \l__xeCJK_punct_coor_tl/kern/#1 } }
\cs_generate_variant:Nn \dim_eval:n { c }
\cs_new_protected_nopar:Npn \xeCJK_before_FullLeft:N #1
  {
    \tl_set:Nx \l__xeCJK_lastpunct_tl {#1}
    \__xeCJK_punct_rule:n { l/#1 }
    \CJKpunctsymbol {#1}
  }
\cs_new_protected_nopar:Npn \xeCJK_after_FullRight:
  {
    \xeCJK_get_punct_bounds:nV { r } \l__xeCJK_lastpunct_tl
    \__xeCJK_punct_rule:n { r/\l__xeCJK_lastpunct_tl }
    \__xeCJK_punct_glue:n { r/\l__xeCJK_lastpunct_tl }
  }
\cs_new_protected_nopar:Npn \xeCJK_CJK_and_FullLeft:N #1
  {
    \xeCJK_get_punct_bounds:nN { l } {#1}
    \int_compare:nNnF \etex_lastnodetype:D = \c_one
      { \__xeCJK_punct_glue:n { l/#1 } }
    \xeCJK_before_FullLeft:N {#1}
    \__xeCJK_punct_if_middle:NT {#1}
      {
        \__xeCJK_punct_rule:n { lr/#1 }
        \__xeCJK_punct_glue:n { l/#1 }
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_CJK_and_FullRight:N #1
  {
    \xeCJK_get_punct_bounds:nN { r } {#1}
    \__xeCJK_punct_if_long:NTF {#1} \CJKglue
      {
        \xeCJK_no_break:
        \__xeCJK_punct_if_middle:NT {#1}
          {
            \__xeCJK_punct_glue:n { r/#1 }
            \__xeCJK_punct_rule:n { lr/#1 }
          }
      }
    \tl_gset:Nx \l__xeCJK_lastpunct_tl {#1}
    \CJKpunctsymbol {#1}
  }
\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_FullLeft:N #1
  {
    \xeCJK_no_break:
    \xeCJK_get_punct_bounds:nN { l } {#1}
    \xeCJK_calc_kern:VN \l__xeCJK_lastpunct_tl {#1}
    \__xeCJK_punct_kern:n { \l__xeCJK_lastpunct_tl - #1 }
    \xeCJK_before_FullLeft:N {#1}
  }
\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_FullRight:N #1
  {
    \xeCJK_no_break:
    \xeCJK_get_punct_bounds:nN { r } {#1}
    \xeCJK_calc_kern:VN \l__xeCJK_lastpunct_tl {#1}
    \__xeCJK_punct_kern:n { \l__xeCJK_lastpunct_tl - #1 }
    \xeCJK_no_break:
    \tl_set:Nx \l__xeCJK_lastpunct_tl {#1}
    \CJKpunctsymbol {#1}
  }
\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_FullLeft:N #1
  {
    \__xeCJK_punct_rule:n { r/\l__xeCJK_lastpunct_tl }
    \xeCJK_get_punct_bounds:nN { l } {#1}
    \xeCJK_calc_kern:VN \l__xeCJK_lastpunct_tl {#1}
    \__xeCJK_punct_kern:n { \l__xeCJK_lastpunct_tl - #1 }
    \__xeCJK_punct_nobreak:
    \xeCJK_before_FullLeft:N {#1}
 }
\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_FullRight:N #1
  {
    \__xeCJK_punct_rule:n { r/\l__xeCJK_lastpunct_tl }
    \xeCJK_get_punct_bounds:nN { r } {#1}
    \xeCJK_calc_kern:VN \l__xeCJK_lastpunct_tl {#1}
    \__xeCJK_punct_kern:n { \l__xeCJK_lastpunct_tl - #1 }
    \xeCJK_no_break:
    \tl_set:Nx \l__xeCJK_lastpunct_tl {#1}
    \CJKpunctsymbol {#1}
  }
 \prg_new_conditional:Npnn \xeCJK_if_last_node:n #1 { p , T , F , TF }
  {
    \if_dim:w \dim_use:c { c__xeCJK_#1_node_dim } = \tex_lastkern:D
      \prg_return_true: \else: \prg_return_false: \fi:
  }
\cs_new_protected_nopar:Npn \xeCJK_def_node:nn #1#2
  {
    \dim_if_exist:cTF { c__xeCJK_#1_node_dim }
      { \dim_gset:cn } { \dim_const:cn }
    { c__xeCJK_#1_node_dim } {#2}
  }
\cs_new_protected_nopar:Npn \xeCJK_make_node:n #1
  {
    \tex_kern:D - \dim_use:c { c__xeCJK_#1_node_dim }
    \tex_kern:D   \dim_use:c { c__xeCJK_#1_node_dim }
  }
\xeCJK_def_node:nn { CJK }            { 11 sp }
\xeCJK_def_node:nn { CJK_space }      { 12 sp }
\xeCJK_def_node:nn { default }        { 13 sp }
\xeCJK_def_node:nn { default_space }  { 14 sp }
\xeCJK_def_node:nn { default_itcorr } { 15 sp }
\keys_define:nn { xeCJK / options }
  { CJKglue .code:n = { \cs_set_protected:Npn \CJKglue {#1} } }
\keys_define:nn { xeCJK / options }
  {
    CJKecglue .code:n =
      {
        \cs_set_protected:Npn \CJKecglue {#1}
        \settowidth \l__xeCJK_ecglue_dim \CJKecglue
      },
    xCJKecglue .choice:,
    xCJKecglue / true    .code:n =
      {
        \bool_set_true:N  \l__xeCJK_xecglue_bool
        \cs_set_eq:NN \__xeCJK_space_or_xecglue: \CJKecglue
      },
    xCJKecglue / false   .code:n =
      {
        \bool_set_false:N \l__xeCJK_xecglue_bool
        \cs_set_eq:NN \__xeCJK_space_or_xecglue: \c_space_token
      },
    xCJKecglue / unknown .code:n =
      {
        \bool_set_true:N  \l__xeCJK_xecglue_bool
        \cs_set_protected:Npn \CJKecglue {#1}
        \settowidth \l__xeCJK_ecglue_dim \CJKecglue
        \cs_set_eq:NN \__xeCJK_space_or_xecglue: \CJKecglue
      },
    xCJKecglue .default:n = { true } ,
  }
\dim_new:N \l__xeCJK_ecglue_dim
\bool_new:N \l__xeCJK_xecglue_bool
\keys_define:nn { xeCJK / options }
  {
    CJKspace .choice:,
    CJKspace / true  .code:n = { \CJKspace   },
    CJKspace / false .code:n = { \CJKnospace },
    CJKspace      .default:n = { true },
    space         .meta:n = { CJKspace = true  },
    nospace       .meta:n = { CJKspace = false },
  }
\NewDocumentCommand \CJKspace { }
  {
    \bool_set_true:N \l__xeCJK_space_bool
    \cs_set_eq:NN \xeCJK_ignorespaces: \__xeCJK_peek_math:
  }
\NewDocumentCommand \CJKnospace { }
  {
    \bool_set_false:N \l__xeCJK_space_bool
    \cs_set_eq:NN \xeCJK_ignorespaces: \__xeCJK_ignore_spaces:
  }
\cs_new_protected_nopar:Npn \__xeCJK_ignore_spaces:
  {
    \peek_catcode:NTF \c_space_token
      {
        \xeCJK_if_last_node:nT { CJK }
          { \tex_unkern:D \tex_unkern:D { \xeCJK_make_node:n { CJK_space } } }
        \xeCJK_peek_catcode_ignore_spaces:NTF \c_math_toggle_token
          { \__xeCJK_space_or_xecglue: }
          {
            \bool_if:nT
              {
                \xeCJK_if_outer_macro_p:c { l_peek_token } ||
                \token_if_cs_p:c { l_peek_token }
              }
              { \__xeCJK_space_or_xecglue: }
          }
      }
      {
        \xeCJK_if_outer_macro:cF { l_peek_token }
          {
            \token_if_math_toggle:cTF { l_peek_token } \CJKecglue
              { \cs_if_exist:cF { l_peek_token } \exp_not:N }
          }
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_peek_math:
  {
    \peek_catcode:NTF \c_space_token
      {
        \xeCJK_if_last_node:nT { CJK }
          { \tex_unkern:D \tex_unkern:D { \xeCJK_make_node:n { CJK_space } } }
        \xeCJK_peek_catcode_ignore_spaces:NF \c_space_token
          { \__xeCJK_space_or_xecglue: }
      }
      {
        \xeCJK_if_outer_macro:cF { l_peek_token }
          {
            \token_if_math_toggle:cTF { l_peek_token } \CJKecglue
              { \cs_if_exist:cF { l_peek_token } \exp_not:N }
          }
      }
  }
\keys_define:nn { xeCJK / options }
  {
    CheckSingle .choice:,
    CheckSingle / true  .code:n = { \xeCJKenablechecksingle  },
    CheckSingle / false .code:n = { \xeCJKdisablechecksingle },
    CheckSingle      .default:n = { true },
    CJKchecksingle      .meta:n = { CheckSingle = true } ,
  }
\bool_new:N \l__xeCJK_checksingle_bool
\NewDocumentCommand \xeCJKenablechecksingle { }
  {
    \bool_if:NF \l__xeCJK_checksingle_bool
      {
        \bool_set_true:N \l__xeCJK_checksingle_bool
        \cs_set_eq:NN \__xeCJK_checksingle_save_CJKsymbol:N \xeCJK_CJK_and_CJK:N
        \cs_set_eq:NN \xeCJK_CJK_and_CJK:N \xeCJK_checksingle:N
      }
  }
\NewDocumentCommand \xeCJKdisablechecksingle { }
  {
    \bool_if:NT \l__xeCJK_checksingle_bool
      {
        \bool_set_false:N \l__xeCJK_checksingle_bool
        \cs_set_eq:NN \xeCJK_CJK_and_CJK:N \__xeCJK_checksingle_save_CJKsymbol:N
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_checksingle:N #1
  {
    \peek_catcode:NTF \c_catcode_other_token
      { \xeCJK_checksingle:NN {#1} }
      {
        \bool_if:nTF
          {
            ! ( \xeCJK_if_outer_macro_p:c { l_peek_token } )                    &amp;&amp;
            \xeCJK_if_blank_x_p:n { \token_get_arg_spec:c { l_peek_token } }    &amp;&amp;
            \exp_args:NNc \exp_args:No \tl_if_single_token_p:n { l_peek_token } &amp;&amp;
            \exp_args:NNc \exp_after:wN \token_if_other_p:N { l_peek_token }
          }
          { \xeCJK_checksingle:NN {#1} }
          { \__xeCJK_checksingle_save_CJKsymbol:N {#1} }
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_checksingle:NN #1#2
  {
    \peek_catcode:NTF \c_catcode_other_token
      { \__xeCJK_checksingle_save_CJKsymbol:N {#1} #2 }
      {
        \bool_if:nTF
          {
            ! ( \xeCJK_if_outer_macro_p:c { l_peek_token } )  &amp;&amp;
              ( \token_if_space_p:c       { l_peek_token } ||
                \token_if_math_toggle_p:c { l_peek_token } ||
                \token_if_cs_p:c          { l_peek_token } )
          }
          {
            \bool_if:nTF { \token_if_space_p:c { l_peek_token } }
              {
                \xeCJK_peek_catcode_ignore_spaces:NTF \c_catcode_other_token
                  { \__xeCJK_checksingle_save_CJKsymbol:N {#1} #2 \c_space_token }
                  {
                    \bool_if:nTF
                      {
                        ! ( \xeCJK_if_outer_macro_p:c { l_peek_token } )  &amp;&amp;
                          ( \token_if_math_toggle_p:c { l_peek_token } ||
                            \token_if_cs_p:c          { l_peek_token } )
                      }
                      { \xeCJK_checksingle:NNN {#1} {#2} \c_space_token }
                      { \__xeCJK_checksingle_save_CJKsymbol:N {#1} #2 \c_space_token }
                  }
              }
              { \xeCJK_checksingle:NNN {#1} {#2} { } }
          }
          { \__xeCJK_checksingle_save_CJKsymbol:N {#1} #2 }
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_checksingle:NNN #1#2#3
  {
    \bool_if:nTF
      {
        \token_if_eq_meaning_p:NN \l_peek_token \par ||
        \token_if_eq_meaning_p:NN \l_peek_token \[ % \]
      }
      { \CJKsymbol {#1} \xeCJK_no_break: #2 }
      { \xeCJK_checksingle_env:NNN {#1} {#2} {#3} }
  }
\cs_new_protected_nopar:Npn \xeCJK_checksingle_env:NNN #1#2#3
  {
    \peek_catcode_remove:NTF \c_math_toggle_token
      {
        \peek_catcode:NTF \c_math_toggle_token
          { \CJKsymbol {#1} \xeCJK_no_break: #2 \c_math_toggle_token }
          { \__xeCJK_checksingle_save_CJKsymbol:N {#1} #2#3 \c_math_toggle_token }
      }
      {
        \peek_meaning_remove:NTF \begin
          { \xeCJK_checksingle_env:NNNNn {#1} {#2} {#3} \begin }
          {
            \peek_meaning_remove:NTF \end
              { \xeCJK_checksingle_env:NNNNn {#1} {#2} {#3} \end }
              { \__xeCJK_checksingle_save_CJKsymbol:N {#1} #2#3 }
          }
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_checksingle_env:NNNNn #1#2#3#4#5
  {
    \clist_if_in:NnTF \g__xeCJK_inline_env_clist {#5}
      { \__xeCJK_checksingle_save_CJKsymbol:N {#1} #2#3 }
      { \CJKsymbol {#1} \xeCJK_no_break: #2 }
    \scan_stop: #4 {#5}
  }
\keys_define:nn { xeCJK / options }
  {
    InlineEnv .clist_gset:N = \g__xeCJK_inline_env_clist ,
    InlineEnv+      .code:n =
      {
        \clist_gput_right:Nx \g__xeCJK_inline_env_clist {#1}
        \clist_gremove_duplicates:N \g__xeCJK_inline_env_clist
      },
    InlineEnv-      .code:n =
      {
        \clist_map_inline:xn {#1}
          { \clist_gremove_all:Nn \g__xeCJK_inline_env_clist {##1} }
      },
  }
\cs_generate_variant:Nn \token_if_cs_p:N          { c }
\cs_generate_variant:Nn \token_if_space_p:N       { c }
\cs_generate_variant:Nn \token_get_arg_spec:N     { c }
\cs_generate_variant:Nn \token_if_math_toggle_p:N { c }
\cs_generate_variant:Nn \token_if_math_toggle:NTF { c }
\tl_new:N \__xeCJK_UL_subclass_patch_tl
\clist_new:N \g__xeCJK_CJK_subclass_clist
\cs_new_protected_nopar:Npn \__xeCJK_erase_CJKsymbol:
  {
    \cs_gset_eq:NN \CJKsymbol_Block \CJKsymbol
    \cs_gset_eq:NN \CJKsymbol \prg_do_nothing:
  }
\cs_new_protected_nopar:Npn \__xeCJK_restore_CJKsymbol:
  {
    \cs_gset_eq:NN \CJKsymbol \CJKsymbol_Block
    \CJKsymbol
  }
\NewDocumentCommand \xeCJKDeclareSubCJKBlock { s m m }
  {
    \xeCJKDeclareSubCharClass { CJK } {#2} {#3}
    \IfBooleanT {#1} { \xeCJKResetPunctClass }
  }
\@onlypreamble \xeCJKDeclareSubCJKBlock
\bool_new:N \l__xeCJK_sub_cancel_bool
\NewDocumentCommand \xeCJKCancelSubCJKBlock { s m }
  {
    \bool_if:NF \l__xeCJK_sub_cancel_bool
      {
        \bool_set_true:N \l__xeCJK_sub_cancel_bool
        \__xeCJK_sub_restore_or_cancel:n {#2}
        \IfBooleanT {#1} { \xeCJKResetPunctClass }
      }
  }
\NewDocumentCommand \xeCJKRestoreSubCJKBlock { s m }
  {
    \bool_if:NT \l__xeCJK_sub_cancel_bool
      {
        \bool_set_false:N \l__xeCJK_sub_cancel_bool
        \__xeCJK_sub_restore_or_cancel:n {#2}
        \IfBooleanT {#1} { \xeCJKResetPunctClass }
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_sub_restore_or_cancel:n #1
  {
    \clist_map_inline:xn {#1}
      {
        \int_if_exist:cTF { c__xeCJK_ CJK/##1 _class_int }
          {
            \__xeCJK_declare_char_class:nn
              { CJK \bool_if:NF \l__xeCJK_sub_cancel_bool { /##1 } }
              { \tl_use:c { g__xeCJK_CJK/##1_range_clist } }
          }
          { \__xeCJK_error:nx { SubBlock-undefined } {##1} }
      }
  }
\__xeCJK_msg_new:nn { SubBlock-undefined }
  {
    The~CJK~sub~block~'#1'~is~undefined.\\\\
    Try~to~use~\token_to_str:N \xeCJKDeclareSubCJKBlock \
    to~declare~it.
  }
\NewDocumentCommand \xeCJKDeclareSubCharClass
  { &gt; { \TrimSpaces } m &gt; { \TrimSpaces } m m }
  {
    \int_if_exist:cF { c__xeCJK_ #1/#2 _class_int }
      {
        \__xeCJK_new_class:n { #1/#2 }
        \__xeCJK_set_sub_class_toks:nn {#1} {#2}
        \__xeCJK_new_sub_key:n {#2}
        \__xeCJK_UL_subclass_patch:nn {#1} {#2}
      }
    \__xeCJK_declare_char_class:nn { #1/#2 } {#3}
  }
\@onlypreamble \xeCJKDeclareSubCharClass
\cs_new_protected_nopar:Npn \__xeCJK_set_sub_class_toks:nn #1#2
  {
    \clist_map_inline:Nn \g__xeCJK_base_class_clist
      {
        \__xeCJK_copy_inter_class_toks:nnnn { #1/#2 } {##1} {#1}  {##1}
        \__xeCJK_copy_inter_class_toks:nnnn {##1} { #1/#2 } {##1} {#1}
        \str_if_eq_x:nnTF {##1} { CJK }
          {
            \__xeCJK_pre_inter_class_toks:nnn {##1} { #1/#2 }
              { \__xeCJK_switch_font:nn {#1} {#2} }
          }
          {
            \__xeCJK_pre_inter_class_toks:nnn {##1} { #1/#2 }
              { \__xeCJK_erase_CJKsymbol: }
            \__xeCJK_app_inter_class_toks:nnn {##1} { #1/#2 }
              { \__xeCJK_switch_font:nn {#1} {#2} \__xeCJK_restore_CJKsymbol: }
          }
      }
    \__xeCJK_copy_inter_class_toks:nnnn { #1/#2 } { #1/#2 } {#1} {#1}
    \clist_if_empty:NF \g__xeCJK_CJK_subclass_clist
      {
        \clist_map_inline:Nn \g__xeCJK_CJK_subclass_clist
          {
            \__xeCJK_copy_inter_class_toks:nnnn { #1/#2  } { #1/##1 } {#1} {#1}
            \__xeCJK_copy_inter_class_toks:nnnn { #1/##1 } { #1/#2  } {#1} {#1}
            \__xeCJK_pre_inter_class_toks:nnn { #1/#2 } { #1/##1 }
              { \__xeCJK_switch_font:nn {#2} {##1} }
            \__xeCJK_pre_inter_class_toks:nnn { #1/##1 } { #1/#2 }
              { \__xeCJK_switch_font:nn {##1} {#2} }
          }
      }
    \clist_gput_right:Nn \g__xeCJK_CJK_subclass_clist {#2}
    \__xeCJK_save_CJK_class:n { #1/#2 }
    \clist_map_inline:nn { CJK, FullLeft, FullRight }
      {
        \__xeCJK_pre_inter_class_toks:nnn { #1/#2 } {##1}
          { \__xeCJK_switch_font:nn {#2} {#1} }
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_UL_subclass_patch:nn #1#2
  {
    \tl_put_right:Nn \__xeCJK_UL_subclass_patch_tl
      {
        \clist_map_inline:nn { Default, HalfLeft, HalfRight }
          {
            \str_if_eq_x:nnTF {##1} { HalfLeft }
              { \__xeCJK_inter_class_toks:nnn {#1} { #1/#2 } { \CJKecglue \CJKsymbol } }
              { \__xeCJK_inter_class_toks:nnn {#1} { #1/#2 } { \CJKsymbol } }
            \__xeCJK_inter_class_toks:nnn { Boundary } { #1/#2 }
              {
                \__xeCJK_erase_CJKsymbol:
                \xeCJK_Boundary_and_CJK:
                \__xeCJK_switch_font:nn {#1} {#2}
                \__xeCJK_restore_CJKsymbol:
              }
          }
      }
  }
\clist_new:N \g__xeCJK_punctstyle_clist
\clist_set:Nn \g__xeCJK_punctstyle_clist
  { CCT , halfwidth , fullwidth , marginkerning , mixedwidth , plain }
\clist_map_inline:Nn \g__xeCJK_punctstyle_clist
  { \tl_const:cn { c__xeCJK_ps_#1_tl } {#1} }
\cs_generate_variant:Nn \keys_define:nn { nx }
\keys_define:nn { xeCJK / options }
  {
    PunctStyle .choice_code:n =
      {
        \tl_set:Nx \l_xeCJK_punctstyle_tl { \l_keys_choice_tl }
        \tl_if_eq:NNT \l_xeCJK_punctstyle_tl \c__xeCJK_ps_plain_tl
          { \xeCJKallowbreakbetweenpuncts }
      },
  }
\keys_define:nx { xeCJK / options }
  { PunctStyle .generate_choices:n = { \exp_not:V \g__xeCJK_punctstyle_clist } }
\keys_define:nn { xeCJK / options }
  {
    PunctStyle / banjiao       .meta:n = { PunctStyle = halfwidth },
    PunctStyle / quanjiao      .meta:n = { PunctStyle = fullwidth },
    PunctStyle / kaiming       .meta:n = { PunctStyle = mixedwidth },
    PunctStyle / hangmobanjiao .meta:n = { PunctStyle = marginkerning },
    PunctStyle / unknown .code:n =
      { \__xeCJK_error:nx { PunctStyle-undefined } \l_keys_value_tl },
  }
\__xeCJK_msg_new:nn { PunctStyle-undefined }
  {
    Punctstyle~"#1"~is~not~available. \\\\
    You~can~only~use~one~of\\\\
    "\g__xeCJK_punctstyle_clist".\\
  }
\keys_define:nn { xeCJK / options }
  {
    AllowBreakBetweenPuncts .choice:,
    AllowBreakBetweenPuncts / true  .code:n = { \xeCJKallowbreakbetweenpuncts },
    AllowBreakBetweenPuncts / false .code:n = { \xeCJKnobreakbetweenpuncts },
    AllowBreakBetweenPuncts      .default:n = { true },
    KaiMingPunct  .code:n = { \__xeCJK_set_special_punct:nn { mixedwidth } {#1} },
    KaiMingPunct+ .code:n = { \__xeCJK_add_special_punct:nn { mixedwidth } {#1} },
    KaiMingPunct- .code:n = { \__xeCJK_sub_special_punct:nn { mixedwidth } {#1} },
    LongPunct     .code:n = { \__xeCJK_set_special_punct:nn { long } {#1} },
    LongPunct+    .code:n = { \__xeCJK_add_special_punct:nn { long } {#1} },
    LongPunct-    .code:n = { \__xeCJK_sub_special_punct:nn { long } {#1} },
    MiddlePunct+  .code:n = { \__xeCJK_add_special_punct:nn { middle } {#1} },
    MiddlePunct   .code:n = { \__xeCJK_set_special_punct:nn { middle } {#1} },
    MiddlePunct-  .code:n = { \__xeCJK_sub_special_punct:nn { middle } {#1} },
    PunctWidth .tl_gset:N = \g__xeCJK_punct_width_tl ,
  }
\NewDocumentCommand \xeCJKallowbreakbetweenpuncts { }
  { \cs_set_eq:NN \__xeCJK_punct_nobreak: \__xeCJK_zero_glue: }
\NewDocumentCommand \xeCJKnobreakbetweenpuncts { }
  { \cs_set_eq:NN \__xeCJK_punct_nobreak: \xeCJK_no_break: }
\cs_new_protected_nopar:Npn \__xeCJK_zero_glue: { \skip_horizontal:N \c_zero_skip }
\clist_set:Nn \g__xeCJK_special_ps_clist { mixedwidth , long , middle }
\clist_map_inline:Nn \g__xeCJK_special_ps_clist
  {
    \tl_new:c    { l__xeCJK_#1_punct_tl   }
    \prop_new:c  { l__xeCJK_#1_punct_prop }
  }
\cs_new_protected_nopar:Npn \__xeCJK_set_special_punct:nn #1#2
  {
    \tl_set:cx { l__xeCJK_#1_punct_tl } {#2}
    \prop_clear:c { l__xeCJK_#1_punct_prop }
    \tl_map_inline:cn { l__xeCJK_#1_punct_tl }
      { \prop_put:cnn  { l__xeCJK_#1_punct_prop } {##1} { } }
  }
\cs_new_protected_nopar:Npn \__xeCJK_add_special_punct:nn #1#2
  {
    \tl_put_right:cx { l__xeCJK_#1_punct_tl } {#2}
    \tl_map_inline:cn { l__xeCJK_#1_punct_tl }
      { \prop_put:cnn  { l__xeCJK_#1_punct_prop } {##1} { } }
  }
\cs_new_protected_nopar:Npn \__xeCJK_sub_special_punct:nn #1#2
  {
    \tl_map_inline:xn {#2}
      {
        \tl_remove_all:cn { l__xeCJK_#1_punct_tl } {##1}
        \prop_remove:cn { l__xeCJK_#1_punct_prop } {##1}
      }
  }
\cs_generate_variant:Nn \tl_map_inline:nn { x }
\cs_generate_variant:Nn \dim_set:Nn { Nc }
\cs_generate_variant:Nn \dim_add:Nn { Nc }
\cs_generate_variant:Nn \dim_min:nn { cc }
\cs_new_protected_nopar:Npn \xeCJK_dim_set_max:Nn #1#2
  { \dim_set:Nn #1 { \dim_max:nn {#1} {#2} } }
\cs_new_protected_nopar:Npn \xeCJK_dim_set_min:Nn #1#2
  { \dim_set:Nn #1 { \dim_min:nn {#1} {#2} } }
\tl_set:Nn \l__xeCJK_punct_coor_tl { \l_xeCJK_font_coor_tl/\l_xeCJK_punctstyle_tl }
\cs_new_protected_nopar:Npn \xeCJK_get_punct_bounds:nN #1#2
  {
    \tl_if_exist:cF { \l__xeCJK_punct_coor_tl/rule/#1/#2 }
      {
        \tl_if_eq:NNTF \l_xeCJK_punctstyle_tl \c__xeCJK_ps_plain_tl
          {
            \tl_set:NV \l__xeCJK_tmpa_tl \c_zero_dim
            \tl_gset_eq:cN { \l__xeCJK_punct_coor_tl/glue/#1/#2  } \l__xeCJK_tmpa_tl
            \tl_gset_eq:cN { \l__xeCJK_punct_coor_tl/rule/#1/#2  } \l__xeCJK_tmpa_tl
            \tl_gset_eq:cN { \l__xeCJK_punct_coor_tl/rule/lr/#2  } \l__xeCJK_tmpa_tl
            \tl_gset_eq:cN { \l__xeCJK_punct_coor_tl/bound/#1/#2 } \l__xeCJK_tmpa_tl
            \tl_gset_eq:cN { \l__xeCJK_punct_coor_tl/bound/lr/#2 } \l__xeCJK_tmpa_tl
          }
          {
            \tl_if_exist:cF { \l__xeCJK_punct_coor_tl/bound/#1/#2 }
              { { \xeCJK_select_font: \xeCJK_calc_punct_dimen:N {#2} } }
            \__xeCJK_punct_if_long:NTF {#2}
              {
                \dim_zero:N \l__xeCJK_tmpa_dim
                \dim_zero:N \l__xeCJK_tmpb_dim
                \dim_zero:N \l__xeCJK_tmpc_dim
              }
              {
                \dim_set:Nc \l__xeCJK_tmpa_dim { \l__xeCJK_punct_coor_tl/bound/#1/#2 }
                \dim_set:Nc \l__xeCJK_tmpb_dim
                  { \l__xeCJK_punct_coor_tl/bound/\str_if_eq_x:nnTF {#1} lrl/#2 }
                \dim_set:Nn \l__xeCJK_tmpc_dim
                  {
                    \cs_if_exist_use:cF { g__xeCJK_punct_width/#2 }
                      {
                        \xeCJK_if_blank_x:nTF \g__xeCJK_punct_width_tl
                          { \c_zero_dim } { \g__xeCJK_punct_width_tl }
                      }
                  }
                \__xeCJK_punct_if_middle:NTF {#2}
                  {
                    \dim_set:Nn \l__xeCJK_tmpc_dim
                      {
                        \dim_compare:nNnTF \l__xeCJK_tmpc_dim &gt; \c_zero_dim
                          { \l__xeCJK_tmpc_dim }
                          {
                            \tl_case:Nnn \l_xeCJK_punctstyle_tl
                              {
                                \c__xeCJK_ps_halfwidth_tl  { .5 em }
                                \c__xeCJK_ps_mixedwidth_tl { .5 em }
                                \c__xeCJK_ps_CCT_tl        { .7 em }
                                \c__xeCJK_ps_fullwidth_tl  {  1 em }
                              }
                              { 1 em }
                          }
                        - ( \tl_use:c { \l__xeCJK_punct_coor_tl/dimen/#2 } )
                      }
                    \dim_compare:nNnTF \l__xeCJK_tmpc_dim &gt; \c_zero_dim
                      { \dim_set:Nn \l__xeCJK_tmpc_dim { .5 \l__xeCJK_tmpc_dim } }
                      {
                        \dim_set:Nn \l__xeCJK_tmpc_dim
                          { \dim_min:nn \l__xeCJK_tmpa_dim \l__xeCJK_tmpb_dim }
                      }
                  }
                  {
                    \dim_compare:nNnTF \l__xeCJK_tmpc_dim &gt; \c_zero_dim
                      {
                        \dim_set:Nn \l__xeCJK_tmpc_dim
                          {
                            \l__xeCJK_tmpc_dim - \l__xeCJK_tmpb_dim
                            - ( \tl_use:c { \l__xeCJK_punct_coor_tl/dimen/#2 } )
                          }
                      }
                      {
                        \dim_set:Nn \l__xeCJK_tmpc_dim
                          { \dim_min:nn \l__xeCJK_tmpa_dim \l__xeCJK_tmpb_dim }
                        \tl_case:Nnn \l_xeCJK_punctstyle_tl
                          {
                            \c__xeCJK_ps_halfwidth_tl { \prg_do_nothing: }
                            \c__xeCJK_ps_mixedwidth_tl
                              {
                                \__xeCJK_punct_if_mixedwidth:NT {#2}
                                  {
                                    \dim_add:Nn \l__xeCJK_tmpc_dim { .5 \l__xeCJK_tmpa_dim }
                                    \xeCJK_dim_set_min:Nn \l__xeCJK_tmpc_dim \l__xeCJK_tmpa_dim
                                  }
                              }
                            \c__xeCJK_ps_CCT_tl
                              {
                                \__xeCJK_punct_if_mixedwidth:NTF {#2}
                                  { \dim_add:Nn \l__xeCJK_tmpc_dim { .5 \l__xeCJK_tmpa_dim } }
                                  { \dim_add:Nn \l__xeCJK_tmpc_dim { .3 \l__xeCJK_tmpa_dim } }
                                \xeCJK_dim_set_min:Nn \l__xeCJK_tmpc_dim \l__xeCJK_tmpa_dim
                              }
                          }
                          { \dim_set_eq:NN \l__xeCJK_tmpc_dim \l__xeCJK_tmpa_dim }
                      }
                  }
                \xeCJK_dim_set_max:Nn \l__xeCJK_tmpc_dim \c_zero_dim
              }
            \tl_gset:cx { \l__xeCJK_punct_coor_tl/rule/#1/#2 }
                        { - \dim_use:N \l__xeCJK_tmpa_dim }
            \tl_gset:cx { \l__xeCJK_punct_coor_tl/rule/lr/#2 }
                        { - \dim_use:N \l__xeCJK_tmpb_dim }
            \tl_gset:cV { \l__xeCJK_punct_coor_tl/glue/#1/#2 } \l__xeCJK_tmpc_dim
          }
      }
  }
\cs_generate_variant:Nn \xeCJK_get_punct_bounds:nN { nV }
\NewDocumentCommand \xeCJKsetwidth { m m }
  { \tl_map_inline:xn {#1} { \tl_gset:cn { g__xeCJK_punct_width/##1 } {#2} } }
\prg_new_conditional:Npnn \__xeCJK_punct_if_right:N #1 { p , T , F , TF }
  {
    \tl_if_exist:cTF { \l__xeCJK_punct_coor_tl/glue/r/#1 }
      \prg_return_true: \prg_return_false:
  }
\prg_new_conditional:Npnn \__xeCJK_punct_if_both_left_right:NN #1#2 { p , T , F , TF }
  {
    \bool_if:nTF
      {
        ( \tl_if_exist_p:c { \l__xeCJK_punct_coor_tl/glue/r/#1 } &amp;&amp;
          \tl_if_exist_p:c { \l__xeCJK_punct_coor_tl/glue/r/#2 } )  ||
        ( \tl_if_exist_p:c { \l__xeCJK_punct_coor_tl/glue/l/#1 } &amp;&amp;
          \tl_if_exist_p:c { \l__xeCJK_punct_coor_tl/glue/l/#2 } )
      }
      \prg_return_true: \prg_return_false:
  }
\cs_generate_variant:Nn \prg_new_conditional:Npnn { c }
\clist_map_inline:Nn \g__xeCJK_special_ps_clist
  {
    \prg_new_conditional:cpnn { __xeCJK_punct_if_#1:N } ##1 { p , T , F , TF }
      {
        \prop_if_in:cnTF { l__xeCJK_#1_punct_prop } {##1}
          \prg_return_true: \prg_return_false:
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_calc_kern:NN #1#2
  {
    \tl_if_exist:cF { \l__xeCJK_punct_coor_tl/kern/#1-#2 }
      {
        \dim_zero:N \l__xeCJK_tmpa_dim
        \tl_if_eq:NNF \l_xeCJK_punctstyle_tl \c__xeCJK_ps_plain_tl
          {
            \tl_if_exist:cTF { g__xeCJK_punct/kern/#1-#2 }
              { \dim_set:Nc \l__xeCJK_tmpa_dim { g__xeCJK_punct/kern/#1-#2 } }
              { \__xeCJK_calc_kern:NNN \l__xeCJK_tmpa_dim {#1} {#2} }
          }
        \tl_gset:cV { \l__xeCJK_punct_coor_tl/kern/#1-#2 } \l__xeCJK_tmpa_dim
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_calc_kern:NNN #1#2#3
  {
    \tl_if_eq:NNTF \l_xeCJK_punctstyle_tl \c__xeCJK_ps_marginkerning_tl
      {
        \dim_zero:N #1
        \__xeCJK_punct_if_right:NT {#2}
          { \dim_add:Nc #1 { \l__xeCJK_punct_coor_tl/bound/r/#2 } }
        \__xeCJK_punct_if_right:NF {#3}
          { \dim_add:Nc #1 { \l__xeCJK_punct_coor_tl/bound/l/#3 } }
      }
      {
        \tl_if_eq:NNTF \l_xeCJK_punctstyle_tl \c__xeCJK_ps_fullwidth_tl
          { \dim_set:Nn #1 { \xeCJK_calc_kern:nNN { 1.5 em } {#2} {#3} } }
          {
            \__xeCJK_punct_if_both_left_right:NNTF {#2} {#3}
              {
                \__xeCJK_punct_if_mixedwidth:NT {#2}
                  {
                    \dim_set:Nn #1 { \xeCJK_calc_kern:nNN { 1 em } {#2} {#3} }
                    \dim_compare:nNnT #1 &lt; { .1 em }
                      { \dim_set:Nc #1 { \l__xeCJK_punct_coor_tl/bound/l/#2 } }
                  }
              }
              {
                \bool_if:nTF
                  {
                    \__xeCJK_punct_if_mixedwidth_p:N {#2} &amp;&amp;
                    ! ( \tl_if_eq_p:NN \l_xeCJK_punctstyle_tl \c__xeCJK_ps_halfwidth_tl )
                  }
                  {
                    \dim_set:Nn #1 { \tl_use:c { \l__xeCJK_punct_coor_tl/glue/r/#2 } }
                    \dim_set:Nn #1 { .7 #1 }
                  }
                  {
                    \dim_set:Nn #1 { \xeCJK_calc_kern:nNN { 1 em } {#2} {#3} }
                    \dim_compare:nNnT #1 &lt; { .1 em }
                      {
                        \dim_set:Nn #1
                          {
                            \dim_max:nn
                              {
                                \dim_min:cc
                                  { \l__xeCJK_punct_coor_tl/bound/l/#2 }
                                  { \l__xeCJK_punct_coor_tl/bound/r/#2 }
                              }
                              {
                                \dim_min:cc
                                  { \l__xeCJK_punct_coor_tl/bound/l/#3 }
                                  { \l__xeCJK_punct_coor_tl/bound/r/#3 }
                              }
                          }
                      }
                  }
              }
          }
        \bool_if:nT
          { \__xeCJK_punct_if_long_p:N {#2} || \__xeCJK_punct_if_long_p:N {#3} }
          { \xeCJK_dim_set_max:Nn #1 { .1 em } }
      }
    \xeCJK_dim_set_max:Nn #1 \c_zero_dim
  }
\cs_generate_variant:Nn \xeCJK_calc_kern:NN { V }
\cs_new_protected_nopar:Npn \xeCJK_calc_kern:nNN #1#2#3
  {
    \dim_eval:n
      {
        #1
        - \tl_use:c { \l__xeCJK_punct_coor_tl/
                      \__xeCJK_punct_if_right:NTF {#2} { bound } { glue } /l/#2 }
        - \tl_use:c { \l__xeCJK_punct_coor_tl/
                      \__xeCJK_punct_if_right:NTF {#3} { glue } { bound } /r/#3 }
        - \tl_use:c { \l__xeCJK_punct_coor_tl/dimen/#2 }
        - \tl_use:c { \l__xeCJK_punct_coor_tl/dimen/#3 }
        \__xeCJK_punct_if_both_left_right:NNT {#2} {#3}
          { + \tl_use:c { \l__xeCJK_punct_coor_tl/rule/lr/#3 } }
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_calc_punct_dimen:N #1
  {
    \tl_gset:cx { \l__xeCJK_punct_coor_tl/bound/l/#1 }
                { \xeCJK_glyph_bounds:nN { left  } {#1} }
    \tl_gset:cx { \l__xeCJK_punct_coor_tl/bound/r/#1 }
                { \xeCJK_glyph_bounds:nN { right } {#1} }
    \tl_gset:cx { \l__xeCJK_punct_coor_tl/bound/lr/#1 }
      {
        \dim_eval:n
          {
            ( \tl_use:c { \l__xeCJK_punct_coor_tl/bound/l/#1 } ) +
            ( \tl_use:c { \l__xeCJK_punct_coor_tl/bound/r/#1 } )
          }
      }
    \tl_gset:cx { \l__xeCJK_punct_coor_tl/dimen/#1 }
      {
        \dim_eval:n
          {
            ( \etex_fontcharwd:D \tex_font:D `#1 ) -
            ( \tl_use:c { \l__xeCJK_punct_coor_tl/bound/lr/#1 } )
          }
      }
    \bool_if:nT
      {
        \__xeCJK_punct_if_long_p:N {#1} &amp;&amp;
        ! ( \str_if_eq_x_p:nn {#1} { ^^^^2025 } || \str_if_eq_x_p:nn {#1} { ^^^^2026 } )
      }
      {
        \clist_map_inline:Nn \g__xeCJK_punctstyle_clist
          {
            \str_if_eq_x:nnF \c__xeCJK_ps_plain_tl {##1}
              {
                \tl_gset:cx { \l_xeCJK_font_coor_tl/##1/kern/#1-#1 }
                  { - \tl_use:c { \l__xeCJK_punct_coor_tl/bound/lr/#1 } }
              }
          }
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_glyph_bounds:nN #1#2
  {
    \dim_eval:n
      {
        \XeTeXglyphbounds
          \str_case_x:nnn {#1}
            {
              { left   } { \c_one   }     { top    } { \c_two  }
              { right  } { \c_three }     { bottom } { \c_four }
            }
            { \c_three }
          \int_eval:n { \XeTeXcharglyph `#2 }
      }
  }
\NewDocumentCommand \xeCJKsetkern { m m m }
  { \tl_gset:cn { g__xeCJK_punct/kern/#1-#2 } {#3} }
\keys_define:nn { xeCJK / options }
  {
    AutoFallBack .choice:,
    AutoFallBack / true  .code:n = { \xeCJKenablefallback },
    AutoFallBack / false .code:n = { \xeCJKdisablefallback },
    AutoFallBack      .default:n = { true },
    fallback             .meta:n = { AutoFallBack = true },
  }
\bool_new:N \l__xeCJK_fallback_bool
\NewDocumentCommand \xeCJKenablefallback { }
  {
    \bool_if:NF \l__xeCJK_fallback_bool
      {
        \bool_set_true:N \l__xeCJK_fallback_bool
        \cs_set_eq:NN \__xeCJK_fallback_save_CJKsymbol:N \CJKsymbol
        \cs_set_eq:NN \CJKsymbol \xeCJK_fallback_testsymbol:N
      }
  }
\NewDocumentCommand \xeCJKdisablefallback { }
  {
    \bool_if:NT \l__xeCJK_fallback_bool
      {
        \bool_set_false:N \l__xeCJK_fallback_bool
        \cs_set_eq:NN \CJKsymbol \__xeCJK_fallback_save_CJKsymbol:N
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_fallback_testsymbol:N #1
  {
    \font_glyph_if_exist:NnTF \tex_font:D {`#1}
      { \__xeCJK_fallback_save_CJKsymbol:N {#1} }
      {
        \xeCJK_family_if_exist:xTF { \l_xeCJK_family_tl/FallBack }
          { {
              \tl_put_right:Nn \l_xeCJK_family_tl { /FallBack }
              \xeCJK_select_font:
              \xeCJK_fallback_testsymbol:N {#1}
          } }
          {
            \__xeCJK_warning:nx { fallback } {#1}
            \__xeCJK_fallback_save_CJKsymbol:N {#1}
          }
      }
  }
\__xeCJK_msg_new:nn { fallback }
  {
    CJKfamily~'\l_xeCJK_family_tl'~
    ( \prop_get:NV \g__xeCJK_family_prop \l_xeCJK_family_tl )~
    does~not~contain~glyph~'#1'~(U+\int_to_hexadecimal:n {`#1}).\\
  }
\NewDocumentCommand \setCJKfallbackfamilyfont { m O{} m }
  {
    \exp_args:Nx \tl_if_in:nnTF {#3} { , }
      { \xeCJK_set_family_fallback:xnn {#1} {#2} {#3} }
      { \xeCJK_set_family:xnn { #1/FallBack } {#2} {#3} }
  }
\cs_new_protected_nopar:Npn \xeCJK_set_family_fallback:xnn #1#2#3
  {
    \group_begin:
    \tl_set:Nx \l__xeCJK_family_fb_tl {#1}
    \prop_get:NVNF \g__xeCJK_family_prop \l__xeCJK_family_fb_tl \l__xeCJK_fontname_tl
      { \tl_clear:N \l__xeCJK_fontname_tl }
    \clist_map_inline:xn {#3}
      {
        \tl_put_right:Nn \l__xeCJK_family_fb_tl { /FallBack }
        \__xeCJK_get_sub_features:nn \l__xeCJK_family_fb_tl {##1}
        \clist_put_left:cx { l__xeCJK_ \l__xeCJK_family_fb_tl _fontfeat_clist } {#2}
        \xeCJK_set_family:xcc \l__xeCJK_family_fb_tl
          { l__xeCJK_ \l__xeCJK_family_fb_tl _fontfeat_clist }
          { l__xeCJK_ \l__xeCJK_family_fb_tl _fontname_tl }
      }
    \group_end:
  }
\bool_new:N \g__xeCJK_AutoFakeBold_bool
\bool_new:N \g__xeCJK_AutoFakeSlant_bool
\fp_new:N \g__xeCJK_EmboldenFactor_fp
\fp_new:N \g__xeCJK_SlantFactor_fp
\keys_define:nn { xeCJK / options }
  {
    AutoFakeBold .choice:,
    AutoFakeBold / true    .code:n =
      { \bool_set_true:N  \g__xeCJK_AutoFakeBold_bool },
    AutoFakeBold / false   .code:n =
      { \bool_set_false:N \g__xeCJK_AutoFakeBold_bool },
    AutoFakeBold / unknown .code:n =
      {
        \bool_set_true:N  \g__xeCJK_AutoFakeBold_bool
        \fp_set:Nn \g__xeCJK_EmboldenFactor_fp { \l_keys_value_tl }
      },
    AutoFakeBold .default:n  = { true },
    AutoFakeSlant .choice:,
    AutoFakeSlant / true     .code:n =
      { \bool_set_true:N  \g__xeCJK_AutoFakeSlant_bool },
    AutoFakeSlant / false    .code:n =
      { \bool_set_false:N \g__xeCJK_AutoFakeSlant_bool },
    AutoFakeSlant / unknown  .code:n =
      {
        \bool_set_true:N  \g__xeCJK_AutoFakeSlant_bool
        \fp_set:Nn \g__xeCJK_SlantFactor_fp { \l_keys_value_tl }
      },
    AutoFakeSlant .default:n = { true },
    EmboldenFactor .fp_set:N = \g__xeCJK_EmboldenFactor_fp,
    SlantFactor    .fp_set:N = \g__xeCJK_SlantFactor_fp,
    BoldFont  .meta:n = { AutoFakeBold  = true },
    boldfont  .meta:n = { AutoFakeBold  = true },
    SlantFont .meta:n = { AutoFakeSlant = true },
    slantfont .meta:n = { AutoFakeSlant = true },
  }
\cs_generate_variant:Nn \keys_set_known:nnN { nx }
\clist_new:N \g__xeCJK_sub_key_clist
\cs_new_protected_nopar:Npn \__xeCJK_new_sub_key:n #1
  {
    \clist_gput_right:Nx \g__xeCJK_sub_key_clist {#1}
    \keys_define:nn { xeCJK / features }
      {
        #1 .code:n =
          {
            \xeCJK_if_blank_x:nTF {##1}
              {
                \bool_set_false:c { l__xeCJK_copy_#1_bool }
                \bool_set_false:c { l__xeCJK_add_#1_bool }
                \tl_put_right:Nx \l__xeCJK_family_aux_tl { /#1 }
              }
              {
                \clist_put_right:Nx \l__xeCJK_sub_key_clist {#1}
                \str_if_eq_x:nnTF {##1} *
                  {
                    \bool_set_true:c  { l__xeCJK_copy_#1_bool }
                    \bool_set_false:c { l__xeCJK_add_#1_bool }
                  }
                  {
                    \bool_set_false:c { l__xeCJK_copy_#1_bool }
                    \bool_set_true:c  { l__xeCJK_add_#1_bool }
                    \__xeCJK_get_sub_features:nn {#1} {##1}
                  }
              }
          },
        #1 .default:n = \c_empty_tl,
      }
  }
\cs_generate_variant:Nn \__xeCJK_new_sub_key:n { x }
\cs_new_protected_nopar:Npn \__xeCJK_get_sub_features:nn #1#2
  {
    \tl_set:Nx \l__xeCJK_tmpa_tl {#2}
    \clist_clear:N \l__xeCJK_sub_fontfeat_clist
    \__xeCJK_gobble_brace:N \l__xeCJK_tmpa_tl
    \exp_args:No \tl_if_head_eq_charcode:nNTF \l__xeCJK_tmpa_tl [ % ]
      {
        \exp_after:wN \__xeCJK_get_sub_features_aux:n \l__xeCJK_tmpa_tl \c_empty_tl
        \xeCJK_if_blank_x:nT \l__xeCJK_sub_fontname_tl
          {
            \tl_set:Nx \l__xeCJK_sub_fontname_tl \l__xeCJK_tmpa_tl
            \clist_clear:N \l__xeCJK_sub_fontfeat_clist
          }
      }
      { \tl_set:Nx \l__xeCJK_sub_fontname_tl \l__xeCJK_tmpa_tl }
    \xeCJK_if_blank_x:nTF \l__xeCJK_sub_fontname_tl
      { \tl_set:Nx \l__xeCJK_sub_fontname_tl \l__xeCJK_fontname_tl }
      { \tl_replace_all:Nnx \l__xeCJK_sub_fontname_tl * \l__xeCJK_fontname_tl }
    \clist_set:cx { l__xeCJK_#1_fontfeat_clist } \l__xeCJK_sub_fontfeat_clist
    \tl_set:cx { l__xeCJK_#1_fontname_tl } \l__xeCJK_sub_fontname_tl
  }
\cs_new_protected_nopar:Npn \__xeCJK_gobble_brace:N #1
  {
    \exp_args:No \tl_if_head_is_group:nT #1
      {
        \exp_last_unbraced:NNo \tl_set:Nn #1 #1
        \__xeCJK_gobble_brace:N #1
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_get_sub_features_aux:n [#1] #2
  {
    \clist_set:Nx \l__xeCJK_sub_fontfeat_clist {#1}
    \tl_set:Nx \l__xeCJK_sub_fontname_tl {#2}
  }
\__xeCJK_new_sub_key:n { FallBack }
\cs_new_nopar:Npn \__xeCJK_map_features_id:n #1
  { \prop_get:Nn \g__xeCJK_features_id_prop {#1} }
\prop_new:N \g__xeCJK_features_id_prop
\prop_put:Nnn \g__xeCJK_features_id_prop { bf   } { Bold        }
\prop_put:Nnn \g__xeCJK_features_id_prop { it   } { Italic      }
\prop_put:Nnn \g__xeCJK_features_id_prop { bfit } { BoldItalic  }
\prop_put:Nnn \g__xeCJK_features_id_prop { sl   } { Slanted     }
\prop_put:Nnn \g__xeCJK_features_id_prop { bfsl } { BoldSlanted }
\prop_map_inline:Nn \g__xeCJK_features_id_prop
  {
    \keys_define:nn { xeCJK / features }
      {
        #2Font     .tl_set_x:c = { l__xeCJK_fontname_#1_tl },
        #2Features .tl_set_x:c = { l__xeCJK_fontfeat_#1_clist } ,
      }
  }
\keys_define:nn { xeCJK / features }
  {
    AutoFakeBold  .choice:,
    AutoFakeBold / false   .code:n =
      { \bool_set_false:N \l__xeCJK_AutoFakeBold_bool },
    AutoFakeBold / unknown .code:n =
      {
        \bool_set_true:N \l__xeCJK_AutoFakeBold_bool
        \fp_set:Nn \l__xeCJK_EmboldenFactor_fp { \l_keys_value_tl }
      },
    AutoFakeBold .default:n  = { \g__xeCJK_EmboldenFactor_fp },
    AutoFakeSlant  .choice:,
    AutoFakeSlant / false   .code:n =
      { \bool_set_false:N \l__xeCJK_AutoFakeSlant_bool },
    AutoFakeSlant / unknown .code:n =
      {
        \bool_set_true:N \l__xeCJK_AutoFakeSlant_bool
        \fp_set:Nn \l__xeCJK_SlantFactor_fp { \l_keys_value_tl }
      },
    AutoFakeSlant .default:n  = { \g__xeCJK_SlantFactor_fp },
    Mono .choice:,
    Mono / Exspace .code:n =
      {
        \xeCJK_set_monoexspace:
        \tl_clear:N \l__xeCJK_monoscale_tl
      },
    Mono / Scale   .code:n =
      {
        \xeCJK_set_monoscale:
        \tl_set:Nx \l__xeCJK_monoscale_tl { Scale = { \fp_use:N \g__xeCJK_monoscale_fp } }
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_set_init:
  {
    \cs_set_eq:NN \CJKfamily \use_none:n
    \tl_clear:N \l__xeCJK_monoscale_tl
    \int_gincr:N \g__xeCJK_fontspec_int
    \prop_clear:N \l__xeCJK_add_font_prop
    \prop_map_inline:Nn \g__xeCJK_features_id_prop
      {
        \tl_clear:c    { l__xeCJK_fontname_##1_tl    }
        \clist_clear:c { l__xeCJK_fontfeat_##1_clist }
      }
    \clist_clear:N \l__xeCJK_pass_features_clist
    \clist_clear:N \l__xeCJK_sub_key_clist
    \clist_map_inline:Nn \g__xeCJK_sub_key_clist
      {
        \bool_set_false:c { l__xeCJK_copy_##1_bool }
        \bool_set_false:c { l__xeCJK_add_##1_bool  }
      }
    \bool_set_eq:NN \l__xeCJK_AutoFakeBold_bool   \g__xeCJK_AutoFakeBold_bool
    \bool_set_eq:NN \l__xeCJK_AutoFakeSlant_bool  \g__xeCJK_AutoFakeSlant_bool
    \fp_set_eq:NN \l__xeCJK_EmboldenFactor_fp \g__xeCJK_EmboldenFactor_fp
    \fp_set_eq:NN \l__xeCJK_SlantFactor_fp    \g__xeCJK_SlantFactor_fp
  }
\cs_new_protected_nopar:Npn \xeCJK_set_family:xnn #1#2#3
  {
    \group_begin:
    \__xeCJK_set_init:
    \tl_set:Nx \l__xeCJK_family_aux_tl {#1}
    \clist_set:Nx \l__xeCJK_fontoptions_clist {#2}
    \tl_set:Nx \l__xeCJK_fontname_tl {#3}
    \keys_set_known:nxN { xeCJK / features }
      { \g__xeCJK_default_features_clist, #2 } \l__xeCJK_pass_features_clist
    \__xeCJK_parse_features:
    \__xeCJK_pass_features:
    \__xeCJK_check_family:V \l__xeCJK_family_aux_tl
    \cs_gset_protected_nopar:cpx { __xeCJK/family/\l__xeCJK_family_aux_tl }
      {
        \group_begin:
        \exp_not:n { \cs_set_eq:NN \CJKfamily \use_none:n }
        \exp_not:n { \fontspec_set_family:Nnn \l__xeCJK_fontspec_family_tl }
          { \l__xeCJK_pass_features_clist } { \l__xeCJK_fontname_tl }
        \prop_gput:NnV \exp_not:N \g__xeCJK_family_name_prop
          { \l__xeCJK_family_aux_tl } \exp_not:N \l__xeCJK_fontspec_family_tl
        \cs_gset_protected_nopar:cpx { __xeCJK/family/\l__xeCJK_family_aux_tl }
        \exp_not:n
          { {
            \exp_not:N \fontencoding { \c__xeCJK_encoding_tl }
            \exp_not:N \fontfamily   { \l__xeCJK_fontspec_family_tl }
            \exp_not:N \selectfont
          } }
        \group_end:
      }
    \__xeCJK_save_family_info:
    \__xeCJK_add_sub_block:
    \group_end:
  }
\cs_generate_variant:Nn \xeCJK_set_family:xnn { xcc }
\cs_new_protected_nopar:Npn \__xeCJK_check_family:n #1
  {
    \prop_get:NnNT \g__xeCJK_family_prop {#1} \l__xeCJK_tmpa_tl
      {
        \prop_gpop:NnNT \g__xeCJK_family_name_prop {#1} \l__xeCJK_tmpa_tl { }
        \__xeCJK_warning:nxx { CJKfamily-redef } {#1} \l__xeCJK_tmpa_tl
      }
  }
\cs_generate_variant:Nn \__xeCJK_check_family:n { V }
\__xeCJK_msg_new:nn { CJKfamily-redef } { Redefining~CJKfamily~`#1'~(#2). }
\cs_new_protected_nopar:Npn \__xeCJK_add_font:nn #1#2
  {
    \prop_put:Nxx \l__xeCJK_add_font_prop
      { \__xeCJK_map_features_id:n {#1} Font } {#2}
  }
\cs_new_protected_nopar:Npn \__xeCJK_add_font_if_new:nn #1#2
  {
    \prop_put_if_new:Nxx \l__xeCJK_add_font_prop
      { \__xeCJK_map_features_id:n {#1} Font } {#2}
  }
\cs_generate_variant:Nn \__xeCJK_add_font:nn        { nx, nc, nV, nv }
\cs_generate_variant:Nn \__xeCJK_add_font_if_new:nn { nx, nc, nV, nv }
\cs_generate_variant:Nn \prop_put:Nnn        { Nxx }
\cs_generate_variant:Nn \prop_get:Nn         { NV  }
\cs_generate_variant:Nn \prop_get:NnNF       { Nx  }
\cs_generate_variant:Nn \prop_if_in:NnF      { Nx  }
\cs_generate_variant:Nn \prop_put_if_new:Nnn { Nxx }
\cs_new_protected_nopar:Npn \__xeCJK_add_fake_bold:n #1
  {
    \clist_put_left:cx { l__xeCJK_fontfeat_#1_clist }
      { FakeBold = { \fp_use:N \l__xeCJK_EmboldenFactor_fp } }
  }
\cs_new_protected_nopar:Npn \__xeCJK_add_fake_slant:n #1
  {
    \clist_put_left:cx { l__xeCJK_fontfeat_#1_clist }
      { FakeSlant = { \fp_use:N \l__xeCJK_SlantFactor_fp } }
  }
\cs_new_protected_nopar:Npn \__xeCJK_parse_features:
  { \prop_map_inline:Nn \g__xeCJK_features_id_prop { \__xeCJK_parse_features:n {##1} } }
\cs_new_protected_nopar:Npn \__xeCJK_parse_features:n #1
  {
    \__xeCJK_if_font_select:nTF {#1}
      {
        \__xeCJK_add_font:nv {#1} { l__xeCJK_fontname_#1_tl }
        \__xeCJK_if_it_or_sl:nTF {#1}
          {
            \__xeCJK_if_font_select:nF {bf#1}
              { \__xeCJK_add_font_if_new:nv {bf#1} { l__xeCJK_fontname_#1_tl }  }
          }
          {
            \str_if_eq_x:nnT {#1} {bf}
              {
                \clist_map_inline:nn { it , sl }
                  {
                    \__xeCJK_if_font_select:nF {bf##1}
                      { \__xeCJK_add_font:nV {bf##1} \l__xeCJK_fontname_bf_tl }
                  }
              }
          }
      }
      { \__xeCJK_set_fake:n {#1} }
  }
\prg_new_conditional:Npnn \__xeCJK_if_font_select:n #1 { p, T, F, TF }
  {
    \exp_args:Nc \xeCJK_if_blank_x:nTF { l__xeCJK_fontname_#1_tl }
      \prg_return_false: \prg_return_true:
  }
\prg_new_conditional:Npnn \__xeCJK_if_it_or_sl:n #1 { p, T, F, TF }
  {
    \bool_if:nTF { \str_if_eq_x_p:nn { it } {#1} || \str_if_eq_x_p:nn { sl } {#1} }
      \prg_return_true: \prg_return_false:
  }
\cs_new_protected_nopar:Npn \__xeCJK_set_fake:n #1
  {
    \str_if_eq_x:nnTF {#1} { bf }
      { \bool_if:NT \l__xeCJK_AutoFakeBold_bool { \__xeCJK_add_fake_bold:n {#1} } }
      {
        \bool_if:NTF \l__xeCJK_AutoFakeSlant_bool
          {
            \bool_if:nT
              {   \__xeCJK_if_it_or_sl_p:n {#1} ||
                ( \str_if_eq_x_p:nn {#1} {bfit} &amp;&amp; ! ( \__xeCJK_if_font_select_p:n {it} ) ) ||
                ( \str_if_eq_x_p:nn {#1} {bfsl} &amp;&amp; ! ( \__xeCJK_if_font_select_p:n {sl} ) )
              }
              { \__xeCJK_add_fake_slant:n {#1} }
          }
          { \__xeCJK_if_it_or_sl:nT {#1} { \__xeCJK_map_it_sl:n {#1} } }
        \bool_if:nT
          {      \l__xeCJK_AutoFakeBold_bool
            &amp;&amp; ! ( \__xeCJK_if_it_or_sl_p:n {#1} )
            &amp;&amp; ! ( \__xeCJK_if_font_select_p:n {bf} )
          }
          { \__xeCJK_add_fake_bold:n {#1} }
      }
    \__xeCJK_add_font_if_new:nn {#1} *
  }
\cs_new_protected_nopar:Npn \__xeCJK_map_it_sl:n #1
  {
    \__xeCJK_if_map_font_select:nT {#1}
      {
        \__xeCJK_add_font:nx {#1} { \__xeCJK_get_map_font:n {#1} }
        \__xeCJK_if_font_select:nF {bf#1}
          { \__xeCJK_add_font_if_new:nx {bf#1} { \__xeCJK_get_map_font:n {#1} } }
      }
  }
\cs_new_nopar:Npn \__xeCJK_get_map_font:n #1
  { \tl_use:c { l__xeCJK_fontname_\str_if_eq_x:nnTF {#1} {it} {sl} {it} _tl } }
\prg_new_conditional:Npnn \__xeCJK_if_map_font_select:n #1 { p, T, F, TF }
  {
    \xeCJK_if_blank_x:nTF { \__xeCJK_get_map_font:n {#1} }
      \prg_return_false: \prg_return_true:
  }
\cs_new_protected_nopar:Npn \__xeCJK_pass_features:
  {
    \prop_map_inline:Nn \g__xeCJK_features_id_prop
      {
        \clist_if_empty:cF { l__xeCJK_fontfeat_##1_clist }
          {
            \clist_put_right:Nx \l__xeCJK_pass_features_clist
              { ##2Features = { \tl_use:c { l__xeCJK_fontfeat_##1_clist } } }
          }
      }
    \prop_map_inline:Nn \l__xeCJK_add_font_prop
      { \clist_put_right:Nx \l__xeCJK_pass_features_clist { ##1 = { ##2 } } }
    \xeCJK_if_blank_x:nF \l__xeCJK_monoscale_tl
      { \clist_put_left:Nx \l__xeCJK_pass_features_clist \l__xeCJK_monoscale_tl }
  }
\prop_new:N \g__xeCJK_family_prop
\prop_new:N \g__xeCJK_family_name_prop
\prop_new:N \g__xeCJK_family_options_prop
\cs_new_protected_nopar:Npn \__xeCJK_save_family_info:
  {
    \group_begin:
    \clist_map_inline:Nn \g__xeCJK_CJK_subclass_clist
      {
        \clist_remove_all:Nn \l__xeCJK_fontoptions_clist {##1}
        \clist_remove_all:Nn \l__xeCJK_fontoptions_clist { ##1 = }
      }
    \prop_gput:NVV \g__xeCJK_family_prop \l__xeCJK_family_aux_tl \l__xeCJK_fontname_tl
    \prop_gput:NVV \g__xeCJK_family_options_prop \l__xeCJK_family_aux_tl \l__xeCJK_fontoptions_clist
    \group_end:
  }
\cs_new_protected_nopar:Npn \__xeCJK_add_sub_block:
  {
    \clist_remove_duplicates:N \l__xeCJK_sub_key_clist
    \clist_map_inline:Nn \l__xeCJK_sub_key_clist
      {
        \tl_set:Nx \l__xeCJK_sub_family_tl { \l__xeCJK_family_aux_tl/##1 }
        \bool_if:cT { l__xeCJK_copy_##1_bool }
          {
            \__xeCJK_check_family:V \l__xeCJK_sub_family_tl
            \prop_get:NVNT \g__xeCJK_family_prop \l__xeCJK_family_aux_tl \l__xeCJK_tmpa_tl
              { \prop_gput:NVV \g__xeCJK_family_prop \l__xeCJK_sub_family_tl \l__xeCJK_tmpa_tl }
            \prop_get:NVNT \g__xeCJK_family_options_prop \l__xeCJK_family_aux_tl \l__xeCJK_tmpa_clist
              {
                \clist_remove_all:Nn \l__xeCJK_tmpa_clist { ##1 = * }
                \prop_gput:NVV \g__xeCJK_family_options_prop \l__xeCJK_sub_family_tl \l__xeCJK_tmpa_clist
              }
            \cs_gset_protected_nopar:cpx { __xeCJK/family/\l__xeCJK_sub_family_tl }
              {
                \xeCJK_family_if_exist:xT { \l__xeCJK_family_aux_tl }
                  {
                    \prop_get:NnNT \exp_not:N \g__xeCJK_family_name_prop
                      { \l__xeCJK_family_aux_tl } \exp_not:N \l__xeCJK_tmpa_tl
                      {
                        \prop_gput:NnV \exp_not:N \g__xeCJK_family_name_prop
                          { \l__xeCJK_sub_family_tl } \exp_not:N \l__xeCJK_tmpa_tl
                        \cs_gset_protected_nopar:cpx { __xeCJK/family/\l__xeCJK_sub_family_tl }
                        \exp_not:n
                          { {
                              \exp_not:N \fontencoding { \c__xeCJK_encoding_tl }
                              \exp_not:N \fontfamily   { \l__xeCJK_tmpa_tl }
                              \exp_not:N \selectfont
                          } }
                      }
                  }
              }
          }
        \bool_if:cT { l__xeCJK_add_##1_bool }
          {
            \xeCJK_set_family:xcc \l__xeCJK_sub_family_tl
              { l__xeCJK_##1_fontfeat_clist } { l__xeCJK_##1_fontname_tl }
          }
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_copy_family:nn #1#2
  {
    \xeCJK_family_if_exist:xT {#2}
      {
        \tl_map_inline:nn
          { \g__xeCJK_family_prop \g__xeCJK_family_options_prop \g__xeCJK_family_name_prop }
          { \prop_get:NnNT ##1 {#2} \l__xeCJK_tmpa_tl { \prop_gput:NnV ##1 {#1} \l__xeCJK_tmpa_tl } }
        \cs_gset_eq:cc { __xeCJK/family/#1 } { __xeCJK/family/#2 }
      }
  }
\cs_generate_variant:Nn \__xeCJK_copy_family:nn { xx }
\tl_set:Nn \l_xeCJK_font_coor_tl { __xeCJK/\l_xeCJK_family_tl/\f@series/\f@shape/\f@size }
\cs_new_protected_nopar:Npn \xeCJK_select_font:
  {
    \cs_if_exist_use:cF { \l_xeCJK_font_coor_tl }
      {
        \tl_set:Nx \l__xeCJK_current_coor_tl \l_xeCJK_font_coor_tl
        \cs_if_exist_use:cT { __xeCJK/family/\l_xeCJK_family_tl }
          { \exp_last_unbraced:NNV \cs_gset_eq:cN \l__xeCJK_current_coor_tl \tex_font:D }
      }
  }
\cs_new_eq:NN \xeCJK@setfont \xeCJK_select_font:
\cs_new_protected_nopar:Npn \__xeCJK_switch_font:nn #1#2
  {
    \str_if_eq_x:nnF {#1} {#2}
      {
        \__xeCJK_info:nxx { CJK-block } {#1} {#2}
        \tl_remove_all:Nn \l_xeCJK_family_tl { /#1 }
        \str_if_eq_x:nnF {#2} { CJK }
          {
            \tl_set:Nx \l__xeCJK_tmpa_tl \l_xeCJK_family_tl
            \tl_put_right:Nx \l_xeCJK_family_tl { /#2 }
            \xeCJK_family_if_exist:xF \l_xeCJK_family_tl
              {
                \xeCJK_family_if_exist:xTF { \CJKfamilydefault/#2 }
                  { \__xeCJK_copy_family:xx \l_xeCJK_family_tl { \CJKfamilydefault/#2 } }
                  { \__xeCJK_copy_family:xx \l_xeCJK_family_tl \l__xeCJK_tmpa_tl }
              }
          }
      }
    \xeCJK_select_font:
  }
\__xeCJK_msg_new:nn { CJK-block } { Switch~from~block~'#1'~to~'#2'. }
\prg_new_protected_conditional:Npnn \xeCJK_family_if_exist:x #1 { T, F, TF }
  {
    \cs_if_free:cTF { __xeCJK/family/#1 }
      { \prg_return_false: }
      {
        \prop_get:NxNF \g__xeCJK_family_name_prop {#1} \l__xeCJK_family_name_tl
          { \use:c { __xeCJK/family/#1 } }
        \prg_return_true:
      }
  }
\cs_generate_variant:Nn \prop_get:NnNTF { Nx }
\NewDocumentCommand \CJKfamily { t+ t- m }
  {
    \xeCJK_if_blank_x:nTF {#3}
      {
        \IfBooleanF {#1} { \IfBooleanF {#2} { \use_none:nn } }
        \xeCJK_family_if_exist_use:x { \l_xeCJK_family_tl }
      }
      {
        \IfBooleanTF {#2} { \xeCJK_family_if_exist_use:x {#3} }
          {
            \xeCJK_family_if_exist:xTF {#3}
              {
                \tl_set:Nx \l_xeCJK_family_tl {#3}
                \tl_set_eq:NN \xeCJK@family \l_xeCJK_family_tl
                \IfBooleanT {#1} { \use:c { __xeCJK/family/#3 } }
              }
              { \__xeCJK_family_unknown_warning:x {#3} }
          }
      }
    \tex_ignorespaces:D
  }
\cs_new_protected_nopar:Npn \xeCJK_family_if_exist_use:x #1
  {
    \xeCJK_family_if_exist:xTF {#1}
      { \use:c { __xeCJK/family/#1 } }
      { \__xeCJK_family_unknown_warning:x {#1} }
  }
\cs_new_protected_nopar:Npn \__xeCJK_family_unknown_warning:x #1
  {
    \seq_if_in:NxF \g__xeCJK_unknown_family_seq {#1}
      {
        \seq_gput_right:Nx \g__xeCJK_unknown_family_seq {#1}
        \__xeCJK_warning:nx { CJKfamily-Unknown } {#1}
      }
  }
\seq_new:N \g__xeCJK_unknown_family_seq
\__xeCJK_msg_new:nn { CJKfamily-Unknown }
  {
    Unknown~CJK~family~'
    \str_case_x:nnn {#1}
      {
        \CJKrmdefault { \token_to_str:N \CJKrmdefault }
        \CJKsfdefault { \token_to_str:N \CJKsfdefault }
        \CJKttdefault { \token_to_str:N \CJKttdefault }
      }
      {#1}
    '~is~ignored.\\\\
    Try~to~use~
    \str_case_x:nnn {#1}
      {
        \CJKrmdefault { \token_to_str:N \setCJKmainfont }
        \CJKsfdefault { \token_to_str:N \setCJKsansfont }
        \CJKttdefault { \token_to_str:N \setCJKmonofont }
      }
      { \token_to_str:N \setCJKfamilyfont {#1} }
    [...]{...}~to~define~it.
  }
\NewDocumentCommand \setCJKfamilyfont { m O{} m }
  { \xeCJK_set_family:xnn {#1} {#2} {#3} }
\NewDocumentCommand \newCJKfontfamily { o m O{} m }
  {
    \tl_set:Nx \l__xeCJK_family_aux_tl { \IfNoValueTF {#1} { \cs_to_str:N #2 } {#1} }
    \xeCJK_set_family:xnn \l__xeCJK_family_aux_tl {#3} {#4}
    \cs_new_protected_nopar:Npx #2 { \exp_not:N \CJKfamily { \l__xeCJK_family_aux_tl } }
  }
\int_new:N   \g__xeCJK_fontspec_int
\int_gdecr:N \g__xeCJK_fontspec_int
\NewDocumentCommand \CJKfontspec { O{} m }
  {
    \tl_set:Nx \l__xeCJK_CJKfontspec_id_tl { CJKfontspec/#1/#2/id }
    \cs_if_free:cT \l__xeCJK_CJKfontspec_id_tl
      {
        \int_gincr:N \g__xeCJK_fontspec_int
        \tl_gset:Nx \g__xeCJK_family_spec_tl
          { CJKfontspec ( \int_use:N \g__xeCJK_fontspec_int ) }
        \xeCJK_set_family:xnn \g__xeCJK_family_spec_tl {#1} {#2}
        \tl_gset:cx \l__xeCJK_CJKfontspec_id_tl \g__xeCJK_family_spec_tl
      }
    \exp_args:Nv \CJKfamily \l__xeCJK_CJKfontspec_id_tl
    \tex_ignorespaces:D
  }
\clist_new:N \g__xeCJK_default_features_clist
\NewDocumentCommand \defaultCJKfontfeatures { m }
  { \clist_gset:Nn \g__xeCJK_default_features_clist {#1} }
\defaultCJKfontfeatures { Script = CJK }
\@onlypreamble \defaultCJKfontfeatures
\NewDocumentCommand \addCJKfontfeatures { m }
  {
    \prop_if_in:NVTF \g__xeCJK_family_prop \l_xeCJK_family_tl
      {
        \group_begin:
        \clist_set:Nx \l__xeCJK_tmpa_clist {#1}
        \prop_get:NVN \g__xeCJK_family_prop \l_xeCJK_family_tl \l__xeCJK_tmpa_tl
        \clist_map_inline:Nn \g__xeCJK_CJK_subclass_clist
          {
            \clist_if_in:NnT \l__xeCJK_tmpa_clist {##1}
              {
                \clist_remove_all:Nn \l__xeCJK_tmpa_clist {##1}
                \prop_get:NxNF \g__xeCJK_family_prop { \l_xeCJK_family_tl/##1 } \l__xeCJK_tmpb_tl
                  {
                    \prop_get:NxNF \g__xeCJK_family_prop
                      { \CJKfamilydefault/##1 } \l__xeCJK_tmpb_tl
                      { \tl_set:Nx \l__xeCJK_tmpb_tl \l__xeCJK_tmpa_tl }
                  }
                \clist_set:Nx \l__xeCJK_tmpa_clist
                  { ##1 = { [ \l__xeCJK_tmpa_clist ] { \l__xeCJK_tmpb_tl } } }
                \clist_map_break:
              }
          }
        \prop_get:NVNF \g__xeCJK_family_options_prop \l_xeCJK_family_tl \l__xeCJK_tmpb_clist
          { \clist_clear:N \l__xeCJK_tmpb_clist }
        \clist_clear:N \l__xeCJK_tmpc_clist
        \clist_map_inline:Nn \l__xeCJK_tmpb_clist
          {
            \clist_if_in:NnF \l__xeCJK_tmpa_clist {##1}
              { \clist_put_right:Nn \l__xeCJK_tmpc_clist {##1} }
          }
        \clist_put_left:NV \l__xeCJK_tmpa_clist \l__xeCJK_tmpc_clist
        \use:x
          { \group_end: \CJKfontspec [ \l__xeCJK_tmpa_clist ] { \l__xeCJK_tmpa_tl } }
      }
      { \__xeCJK_warning:n { addCJKfontfeature-ignored } }
    \tex_ignorespaces:D
  }
\cs_new_eq:NN \addCJKfontfeature \addCJKfontfeatures
\__xeCJK_msg_new:nn { addCJKfontfeature-ignored }
  {
    \token_to_str:N \addCJKfontfeature (s)~ignored.\\\\
    It~cannot~be~used~with~a~font~that~wasn't~selected~by~xeCJK.
  }
\NewDocumentCommand \setCJKmainfont { O{} m }
  { \xeCJK_set_family:xnn \CJKrmdefault {#1} {#2} }
\cs_new_eq:NN \setCJKromanfont \setCJKmainfont
\NewDocumentCommand \setCJKsansfont { O{} m }
  { \xeCJK_set_family:xnn \CJKsfdefault {#1} {#2} }
\tl_if_exist:NF \CJKrmdefault     { \tl_set:Nn \CJKrmdefault { rm } }
\tl_if_exist:NF \CJKsfdefault     { \tl_set:Nn \CJKsfdefault { sf } }
\tl_if_exist:NF \CJKttdefault     { \tl_set:Nn \CJKttdefault { tt } }
\tl_if_exist:NF \CJKfamilydefault { \tl_set:Nn \CJKfamilydefault { \CJKrmdefault } }
\tl_new:c { __xeCJK/family/\CJKfamilydefault }
\AtEndOfPackage
  {
    \etex_protected:D \tl_put_right:Nn \normalfont { \CJKfamily \CJKfamilydefault }
    \etex_protected:D \tl_put_right:Nn \rmfamily   { \CJKfamily \CJKrmdefault }
    \etex_protected:D \tl_put_right:Nn \sffamily   { \CJKfamily \CJKsfdefault }
    \etex_protected:D \tl_put_right:Nn \ttfamily   { \CJKfamily \CJKttdefault }
    \cs_set_eq:NN \reset@font \normalfont
  }
\@onlypreamble \setCJKmainfont
\@onlypreamble \setCJKmathfont
\@onlypreamble \setCJKsansfont
\@onlypreamble \setCJKmonofont
\@onlypreamble \setCJKromanfont
\NewDocumentCommand \setCJKmathfont { O{} m }
  { \xeCJK_set_family:xnn \c__xeCJK_math_tl {#1} {#2} }
\tl_const:Nn \c__xeCJK_math_tl { CJKmath }
\keys_define:nn { xeCJK / options } { CJKmath .bool_gset:N = \g__xeCJK_math_bool }
\NewDocumentCommand \xeCJKsetmathcode { m m m m }
  {
    \__xeCJK_check_num_range:nnNN {#1} {#2} \l__xeCJK_tmpa_int \l__xeCJK_tmpb_int
    \int_set:Nn \l__xeCJK_tmpc_int { \__xeCJK_math_type:n {#3} }
    \int_set:Nn \l_tmpa_int { \use:c { sym #4 } }
    \xeCJK_int_until_do:nn { \l__xeCJK_tmpa_int &gt; \l__xeCJK_tmpb_int }
      {
        \XeTeXmathcode \l__xeCJK_tmpa_int = \l__xeCJK_tmpc_int \l_tmpa_int \l__xeCJK_tmpa_int
        \int_incr:N \l__xeCJK_tmpa_int
      }
  }
\cs_new_eq:NN \__xeCJK_math_type:n \mathchar@type
\cs_new_protected_nopar:Npn \xeCJK_set_mathfont:
  {
    \xeCJK_family_if_exist:xTF \c__xeCJK_math_tl
      { \tl_set:Nx \l__xeCJK_tmpa_tl \c__xeCJK_math_tl }
      {
        \xeCJK_family_if_exist:xTF \CJKfamilydefault
          { \tl_set:Nx \l__xeCJK_tmpa_tl \CJKfamilydefault }
          { \tl_set_eq:NN \l__xeCJK_tmpa_tl \q_no_value }
      }
    \prop_get:NVNT \g__xeCJK_family_name_prop \l__xeCJK_tmpa_tl \l__xeCJK_math_family_tl
      {
        \DeclareSymbolFont \c__xeCJK_math_tl       \c__xeCJK_encoding_tl
          \l__xeCJK_math_family_tl \mddefault \shapedefault
        \SetSymbolFont  \c__xeCJK_math_tl { bold } \c__xeCJK_encoding_tl
          \l__xeCJK_math_family_tl \bfdefault \shapedefault
        \clist_map_inline:nn { CJK, FullLeft, FullRight  }
          {
            \clist_map_inline:cn { g__xeCJK_##1_range_clist }
              {
                \__xeCJK_set_char_class_aux:Nn \xeCJKsetmathcode {####1}
                  \mathalpha \c__xeCJK_math_tl
              }
          }
      }
  }
\__xeCJK_AtEndPreamble:n
  {
    \normalfont
    \prop_if_empty:NTF \g__xeCJK_family_prop
      { \__xeCJK_warning:n { no-CJKfamily } }
      { \bool_if:NT \g__xeCJK_math_bool { \xeCJK_set_mathfont: } }
  }
\__xeCJK_msg_new:nn { no-CJKfamily }
  {
    It~seems~that~you~have~not~declare~a~CJKfamily.\\
    If~you~want~to~use~xeCJK~in~the~right~way,~you~should~use\\\\
    \token_to_str:N \xeCJKmainfont[...]{...}\\\\
    in~the~preamble~to~declare~the~main~CJKfamily.\\
  }
\fp_new:N \g__xeCJK_monoscale_fp
\fp_set_eq:NN \g__xeCJK_monoscale_fp \c_one_fp
\dim_new:N \g__xeCJK_exspace_dim
\NewDocumentCommand \setCJKmonoscale { }
  {
    \CJKflexiblespacing
    \xeCJK_set_monoscale:
    \addCJKfontfeatures { Scale = \fp_use:N \g__xeCJK_monoscale_fp }
  }
\cs_new_protected_nopar:Npn \xeCJK_set_monoscale:
  {
    \group_begin:
      \fontfamily \ttdefault \selectfont
      \fp_gset:Nn \g__xeCJK_monoscale_fp
        { \dim_to_fp:n { \c_two \tex_fontdimen:D \c_two \tex_font:D } / ( \f@size ) }
    \group_end:
  }
\NewDocumentCommand \setCJKmonoexspace { } { \xeCJK_set_monoexspace: }
\cs_new_protected_nopar:Npn \xeCJK_set_monoexspace:
  {
    \group_begin:
      \fontfamily \ttdefault \selectfont
      \dim_gset:Nn \g__xeCJK_exspace_dim
        {
          \c_two \tex_fontdimen:D \c_two \tex_font:D
          - \fp_to_dim:n { \g__xeCJK_monoscale_fp * ( \f@size ) }
        }
    \group_end:
  }
\NewDocumentCommand \CJKfixedspacing { }
  {
    \bool_if:NF \l__xeCJK_fixed_spacing_bool
      {
        \bool_set_true:N \l__xeCJK_fixed_spacing_bool
        \tl_set_eq:NN \l__xeCJK_flexible_punctstyle_tl \l_xeCJK_punctstyle_tl
        \bool_set_eq:NN \l__xeCJK_fixed_xecglue_bool \l__xeCJK_xecglue_bool
        \cs_set_eq:NN \__xeCJK_flexible_ecglue:  \CJKecglue
        \cs_set_eq:NN \__xeCJK_flexible_cjkglue: \CJKglue
        \xeCJK_set_monoexspace:
        \xeCJKsetup
          {
            PunctStyle = plain ,
            CJKglue    = { \skip_horizontal:N \g__xeCJK_exspace_dim } ,
            CJKecglue  = { \skip_horizontal:n { .5\g__xeCJK_exspace_dim } } ,
            xCJKecglue = false ,
          }
      }
  }
\NewDocumentCommand \CJKflexiblespacing { }
  {
    \bool_if:NT \l__xeCJK_fixed_spacing_bool
      {
        \bool_set_false:N \l__xeCJK_fixed_spacing_bool
        \exp_args:Nx \xeCJKsetup
          {
            PunctStyle = { \l__xeCJK_flexible_punctstyle_tl } ,
            CJKglue    = { \exp_not:o { \__xeCJK_flexible_cjkglue: } } ,
            CJKecglue  = { \exp_not:o { \__xeCJK_flexible_ecglue: } } ,
            xCJKecglue = { \bool_if:NTF \l__xeCJK_fixed_xecglue_bool { true } { false } } ,
          }
      }
  }
\bool_new:N \l__xeCJK_fixed_spacing_bool
\__xeCJK_AfterPreamble:n { \tl_put_right:Nn \verbatim@font \CJKfixedspacing }
\NewDocumentCommand \setCJKmonofont { s t+ O{} m }
  {
    \IfBooleanTF {#1}
      { \xeCJK_set_family:xnn \CJKttdefault { Mono = Scale, #3 } {#4} }
      {
        \IfBooleanTF {#2}
          { \xeCJK_set_family:xnn \CJKttdefault { Mono = Exspace, #3 } {#4} }
          { \xeCJK_set_family:xnn \CJKttdefault {#3} {#4} }
      }
  }
\bool_new:N \g__xeCJK_indent_bool
\keys_define:nn { xeCJK / options }
  {
    CJKnumber     .bool_set:N = \g__xeCJK_number_bool ,
    indentfirst   .bool_set:N = \g__xeCJK_indent_bool ,
    normalindentfirst .meta:n = { indentfirst = false } ,
    quiet .code:n =
      {
        \msg_redirect_module:nnn { xeCJK } { warning } { info }
        \msg_redirect_module:nnn { xeCJK } { info }    { none }
        \xeCJK_if_package_loaded:nF { fontspec }
          { \PassOptionsToPackage { quiet } { fontspec } }
      },
    silent .code:n =
      {
        \msg_redirect_module:nnn { xeCJK } { warning } { none }
        \msg_redirect_module:nnn { xeCJK } { info }    { none }
        \xeCJK_if_package_loaded:nF { fontspec }
          { \PassOptionsToPackage { silent } { fontspec } }
      },
    unknown .code:n =
      {
        \xeCJK_if_package_loaded:nTF { fontspec }
          { \__xeCJK_error:nx { key-unknown } { \l_keys_key_tl } }
          { \PassOptionsToPackage { \l_keys_key_tl } { fontspec } }
      },
  }
\__xeCJK_msg_new:nn { key-unknown }
  {
    Sorry,~but~\l__keys_module_tl \ does~not~have~a~key~called~'#1'.\\\\
    The~key~'#1'~is~being~ignored.
  }
\keys_set:nn { xeCJK / options }
  {
    CJKglue = { \skip_horizontal:n { \c_zero_skip \@plus .08\baselineskip } } ,
    CJKecglue       = \c_space_token ,
    xCJKecglue      = false ,
    CheckSingle     = false ,
    CJKspace        = false ,
    CJKmath         = false ,
    xeCJKactive     = true  ,
    indentfirst     = true  ,
    EmboldenFactor  = 4 ,
    SlantFactor     = .167 ,
    PunctStyle      = quanjiao ,
    KaiMingPunct    = { ^^^^3002 ^^^^ff0e ^^^^ff1f ^^^^ff01 } ,
    LongPunct       = { ^^^^2014 ^^^^2015 ^^^^2500 ^^^^2025 ^^^^2026 } ,
    MiddlePunct     = { ^^^^2014 ^^^^2015 ^^^^2500 ^^^^00b7 ^^^^30fb ^^^^ff65 } ,
    AllowBreakBetweenPuncts = false ,
  }
\cs_new_nopar:Npn \CJKsymbol      #1 {#1}
\cs_new_nopar:Npn \CJKpunctsymbol #1 {#1}
\ProcessKeysOptions { xeCJK / options }
\RequirePackage { fontspec } [ 2011/09/13 ]
\tl_const:Nx \c__xeCJK_encoding_tl { \g_fontspec_encoding_tl }
\bool_if:NT \g__xeCJK_indent_bool
  {
    \cs_set_eq:NN \@afterindentfalse \@afterindenttrue
    \@afterindenttrue
  }
\NewDocumentCommand \xeCJKsetup { m }
  {
    \keys_set:nn { xeCJK / options } {#1}
    \tex_ignorespaces:D
  }
\NewDocumentCommand \xeCJKsetemboldenfactor { m }
  { \xeCJKsetup { EmboldenFactor = {#1} } }
\NewDocumentCommand \xeCJKsetslantfactor { m }
  { \xeCJKsetup { SlantFactor = {#1} } }
\NewDocumentCommand \punctstyle { m } { \xeCJKsetup { PunctStyle = {#1} } }
\NewDocumentCommand \xeCJKplainchr { } { \punctstyle { plain } }
\NewDocumentCommand \CJKsetecglue { m } { \xeCJKsetup { CJKecglue = {#1} } }
\cs_new_eq:NN \xeCJKsetecglue \CJKsetecglue
\cs_new_protected_nopar:Npn \__xeCJK_fix_itcorr:
  {
    \scan_stop:
    \xeCJK_if_last_node:nTF { default }
      {
        \tex_unkern:D \tex_unkern:D
        \__xeCJK_itcorr_aux
        { \xeCJK_make_node:n { default_itcorr } }
      }
      { \__xeCJK_itcorr_aux }
  }
\cs_new_eq:NN \__xeCJK_itcorr_aux \/
\cs_set_protected_nopar:Npn \/
  {
    \int_compare:nNnTF \XeTeXinterchartokenstate &gt; \c_zero
      { \__xeCJK_fix_itcorr: } { \__xeCJK_itcorr_aux }
  }
\cs_set_eq:NN \@@italiccorr \/
\__xeCJK_AfterEndPreamble:n
  {
    \int_compare:nNnF
      { \c_three + ( \seq_count:N \g__xeCJK_class_seq ) } = \xe@alloc@intercharclass
      {
        \int_step_inline:nnnn \c_four \c_one \xe@alloc@intercharclass
          {
            \seq_if_in:NnF \g__xeCJK_class_seq {#1}
              { \__xeCJK_set_others_toks:n {#1} }
          }
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_set_others_toks:n #1
  {
    \int_set:Nn \c__xeCJK_Others_class_int {#1}
    \clist_map_inline:Nn \g__xeCJK_CJK_class_clist
      {
        \__xeCJK_copy_inter_class_toks:nnnn {##1} { Others } {##1} { NormalSpace }
        \__xeCJK_copy_inter_class_toks:nnnn { Others } {##1} { NormalSpace } {##1}
        \exp_args:Nnnx \__xeCJK_app_inter_class_toks:nnn {##1} { Others }
          { \__xeCJK_get_inter_class_toks:nn { Default } { Others } }
        \exp_args:Nnnx \__xeCJK_pre_inter_class_toks:nnn { Others } {##1}
          { \__xeCJK_get_inter_class_toks:nn { Others } { Default } }
        \xeCJK_if_blank_x:nT
          { \__xeCJK_get_inter_class_toks:nn { Others } { Boundary } }
          {
            \__xeCJK_copy_inter_class_toks:nnnn
              { Others } { Boundary } { Default } { Boundary }
          }
        \xeCJK_if_blank_x:nT
          { \__xeCJK_get_inter_class_toks:nn { Boundary } { Others } }
          {
            \__xeCJK_copy_inter_class_toks:nnnn
              { Boundary } { Others } { Boundary } { Default }
          }
      }
  }
\int_new:N \c__xeCJK_Others_class_int
\cs_new_protected_nopar:Npn \__xeCJK_patch:Nnn #1#2#3
  { \tl_put_left:Nn  #1 {#2} \tl_put_right:Nn #1 {#3} }
\__xeCJK_AfterPreamble:n
  {
    \tl_map_inline:nn
      {
        \textellipsis  \textemdash     \textperiodcentered \textcentereddot
        \textquoteleft \textquoteright \textquotedblleft   \textquotedblright
      }
      {
        \__xeCJK_patch:Nnn #1
          { \__xeCJK_group_begin: \makexeCJKinactive }
          { \__xeCJK_group_end: }
      }
    \__xeCJK_patch:Nnn \tipaencoding { \makexeCJKinactive } { }
    \cs_set_eq:NN \__xeCJK_aux_r \r
    \cs_set_protected_nopar:Npn \r #1 { { \makexeCJKinactive \__xeCJK_aux_r {#1} } }
    \xeCJK_if_package_loaded:nT { pifont }
      {
        \RenewDocumentCommand \Pifont { m }
          { \makexeCJKinactive \usefont {U} {#1} {m} {n} }
      }
  }
\cs_new_eq:NN \__xeCJK_group_begin: \group_begin:
\cs_new_eq:NN \__xeCJK_group_end: \group_end:
\__xeCJK_AfterEndPreamble:n
  {
    \bool_if:nT
      {
        \xeCJK_if_package_loaded_p:n { hyperref } &amp;&amp;
        \tl_if_exist_p:N \pdfstringdefPreHook
      }
      {
        \tl_gput_right:Nn \pdfstringdefPreHook
          {
            \cs_set_eq:NN \makexeCJKinactive \prg_do_nothing:
            \cs_set_eq:NN \__xeCJK_group_begin: \prg_do_nothing:
            \cs_set_eq:NN \__xeCJK_group_end: \prg_do_nothing:
            \cs_set_eq:NN \CJKfamily \use_none:n
          }
      }
  }
\tl_set:cn { ver@CJK.sty } { 2100/01/01 }
\cs_if_free:NT \CJK@ifundefined
  { \cs_set_eq:NN \CJK@ifundefined \cs_if_free:NTF }
\NewDocumentCommand \xeCJKcaption { o m }
  {
    \IfNoValueF {#1} { \XeTeXdefaultencoding "#1" }
    \cs_set_nopar:Npx \__xeCJK_reset_at_catcode:
      {
        \exp_not:n { \char_set_catcode:nn  { `\@ } }
                   { \char_value_catcode:n { `\@ } }
      }
    \char_set_catcode_letter:N \@
    \file_input:n { #2.cpx }
    \__xeCJK_reset_at_catcode:
    \XeTeXdefaultencoding "UTF-8"
  }
\cs_new_protected_nopar:Npn \xeCJK_ULprepunctchar:n #1
  {
    { \makexeCJKinactive \CJKpunctsymbol {#1} \xeCJK_no_break: }
    \tex_ignorespaces:D
  }
\cs_new_protected_nopar:Npn \xeCJK_ULpostpunctchar:n #1
  {
    { \makexeCJKinactive \CJKpunctsymbol {#1} }
    \xeCJK_ignorespaces:
  }
\cs_new_protected_nopar:Npn \xeCJK_ULroutines:
  {
    \__xeCJK_inter_class_toks:nnn { Default   } { CJK } { \CJKecglue \CJKsymbol }
    \__xeCJK_inter_class_toks:nnn { HalfLeft  } { CJK } { \CJKsymbol }
    \__xeCJK_inter_class_toks:nnn { HalfRight } { CJK } { \CJKecglue \CJKsymbol }
    \__xeCJK_inter_class_toks:nnn { Boundary  } { CJK } { \xeCJK_Boundary_and_CJK: }
    \clist_map_inline:nn { Default, HalfLeft, HalfRight, Boundary }
      {
        \__xeCJK_inter_class_toks:nnn {##1} { FullLeft }  { \xeCJK_ULprepunctchar:n }
        \__xeCJK_inter_class_toks:nnn {##1} { FullRight } { \xeCJK_ULpostpunctchar:n }
      }
    \__xeCJK_UL_subclass_patch_tl
  }
\__xeCJK_AfterPreamble:n
  {
    \cs_if_exist:NT \UL@hook
      {
        \addto@hook \UL@hook
          {
            \cs_set_eq:NN \__xeCJK_UL_CJKsymbol \CJKsymbol
            \cs_set_eq:NN \__xeCJK_UL_CJKpunctsymbol \CJKpunctsymbol
            \cs_set_protected_nopar:Npn \CJKsymbol #1
              {
                { \xeCJK_select_font: \__xeCJK_UL_CJKsymbol {#1} }
                { \xeCJK_make_node:n { CJK } } \xeCJK_ignorespaces:
              }
            \cs_set_protected_nopar:Npn \CJKpunctsymbol #1
              { { \xeCJK_select_font: \__xeCJK_UL_CJKpunctsymbol {#1} } }
            \xeCJK_ULroutines:
          }
      }
    \cs_if_exist:NT \XeTeX@CJKfntef@hook
      {
        \cs_set_nopar:Npn \XeTeX@CJKfntef@hook
          { \xeCJK_select_font: \makexeCJKinactive }
      }
  }
\bool_if:NT \g__xeCJK_number_bool
  {
    \tl_set:Nn \CJK@UnicodeEnc { UTF8 }
    \cs_set_protected_nopar:Npn \CJKaddEncHook #1#2
      { \cs_set_nopar:cpn { __xeCJK_enc_#1 } {#2} }
    \cs_set_protected_nopar:Npn \Unicode #1#2
      { \tex_char:D \int_eval:n { (#1) * \c_two_hundred_fifty_six + (#2) } }
    \RequirePackage { CJKnumb }
    \cs_if_exist_use:cT { __xeCJK_enc_\CJK@UnicodeEnc } { }
    \tl_set:Nx \CJK@tenthousand    { ^^^^4e07 }
    \tl_set:Nx \CJK@hundredmillion { ^^^^4ebf }
  }
%% 
%%    This package consists of the file  xeCJK.dtx
%%                 and the derived files xeCJK.pdf,
%%                                       xeCJK.sty,
%%                                       xeCJK.ins,
%%                                       xeCJK-example-autofake.tex,
%%                                       xeCJK-example-fallback.tex,
%%                                       xeCJK-example-subCJKblock.tex,
%%                                       xeCJK-example-CJKecglue.tex,
%%                                       xeCJK-example-checksingle.tex and
%%                                       README.txt.
%%
%% End of file `xeCJK.sty'.
</pre></body></html>