%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /data/old/usr/share/texlive/texmf-dist/tex/xelatex/xecjk/
Upload File :
Create Path :
Current File : //data/old/usr/share/texlive/texmf-dist/tex/xelatex/xecjk/xeCJK.sty

%%
%% This is file `xeCJK.sty',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% xeCJK.dtx  (with options: `package')
%% 
%% $Id: xeCJK.dtx 399 2013-01-11 14:57:50Z sobenlee $
%% $URL: https://ctex-kit.googlecode.com/svn/trunk/xeCJK/xeCJK.dtx $
%% -----------------------------------------------------------------
%%    Author:
%%             Wenchang Sun    <sunwch@nankai.edu.cn>
%%    Current Maintainers:
%%             Leo Liu         <leoliu.pku@gmail.com>
%%             Qing Lee        <sobenlee@gmail.com>
%% 
%%    Copyright (C) 2007--2013 Wenchang Sun
%%              (C) 2009--2013 Leo Liu
%%              (C) 2012--2013 Qing Lee
%% 
%%    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 399 2013-01-11 14:57:50Z sobenlee $
  {Typesetting CJK scripts with XeLaTeX}
\ProvidesExplPackage
  {\ExplFileName}
  {\ExplFileDate}{3.1.2}{\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~`#1'~too~old. \\\\
    Please~update~an~up~to~date~version~of~the~bundles\\\\
    `l3kernel'~and~`l3packages'\\\\
    using~your~TeX~package~manager~or~from~CTAN.\\
    \str_if_eq:nnT {#1} { expl3 } { Loading~xeCJK~will~abort! }
  }
\@ifpackagelater { expl3 } { 2012/11/10 } { }
  { \msg_critical:nnn { xeCJK } { l3-too-old } { expl3 } }
\RequirePackage { xtemplate }
\@ifpackagelater { xtemplate } { 2012/11/10 } { }
  { \msg_error:nnn { xeCJK } { l3-too-old } { xtemplate } }
\RequirePackage { xparse , l3keys2e }
\tl_new:N \l__xeCJK_tmpa_tl
\tl_new:N \l__xeCJK_tmpb_tl
\int_new:N \l__xeCJK_tmpa_int
\int_new:N \l__xeCJK_tmpb_int
\int_new:N \l__xeCJK_tmpc_int
\box_new:N \l__xeCJK_tmp_box
\dim_new:N \l__xeCJK_tmp_dim
\skip_new:N \l__xeCJK_tmp_skip
\prop_new:N \l__xeCJK_tmp_prop
\clist_new:N \l__xeCJK_tmpa_clist
\clist_new:N \l__xeCJK_tmpb_clist
\cs_new_protected_nopar:Npn \__xeCJK_msg_new:nn  { \msg_new:nnn      { xeCJK } }
\cs_new_protected_nopar:Npn \__xeCJK_error:n     { \msg_error:nn     { xeCJK } }
\cs_new_protected_nopar:Npn \__xeCJK_error:nx    { \msg_error:nnx    { xeCJK } }
\cs_new_protected_nopar:Npn \__xeCJK_warning:n   { \msg_warning:nn   { xeCJK } }
\cs_new_protected_nopar:Npn \__xeCJK_warning:nx  { \msg_warning:nnx  { xeCJK } }
\cs_new_protected_nopar:Npn \__xeCJK_warning:nxx { \msg_warning:nnxx { xeCJK } }
\cs_new_protected_nopar:Npn \__xeCJK_info:nx     { \msg_info:nnx     { xeCJK } }
\cs_new_protected_nopar:Npn \__xeCJK_info:nxx    { \msg_info:nnxx    { xeCJK } }
\cs_new_protected_nopar:Npn \xeCJK_allow_break: { \tex_penalty:D \c_zero }
\cs_new_protected_nopar:Npn \xeCJK_no_break: { \tex_penalty:D \c_ten_thousand }
\prg_new_conditional:Npnn \xeCJK_if_package_loaded:n #1 { p , T , F , TF }
  {
    \tl_if_exist:cTF { ver@ #1 . \c__xeCJK_package_ext_tl }
      { \prg_return_true: } { \prg_return_false: }
  }
\tl_const:Nx \c__xeCJK_package_ext_tl { \@pkgextension }
\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_at_end_preamble:n #1
  { \tl_gput_right:Nn \g__xeCJK_at_end_preamble_hook_tl {#1} }
\cs_new_protected:Npn \__xeCJK_after_preamble:n #1
  { \tl_gput_right:Nn \g__xeCJK_after_preamble_hook_tl {#1} }
\cs_new_protected:Npn \__xeCJK_after_end_preamble:n #1
  { \tl_gput_right:Nn \g__xeCJK_after_end_preamble_hook_tl {#1} }
\xeCJK_if_package_loaded:nTF { etoolbox }
  {
    \AtEndPreamble { \g__xeCJK_at_end_preamble_hook_tl }
    \AfterPreamble { \g__xeCJK_after_preamble_hook_tl }
    \AfterEndPreamble { \g__xeCJK_after_end_preamble_hook_tl }
  }
  {
    \AtBeginDocument { \g__xeCJK_after_preamble_hook_tl }
    \cs_new_protected_nopar:Npn \__xeCJK_document_left_hook:
      { \group_end: \g__xeCJK_at_end_preamble_hook_tl \group_begin: }
    \cs_new_protected_nopar:Npn \__xeCJK_document_right_hook:
      { \scan_stop: \g__xeCJK_after_end_preamble_hook_tl \tex_ignorespaces:D }
    \cs_gset_nopar:Npx \document
      {
        \__xeCJK_document_left_hook:
        \exp_not:o { \document }
        \__xeCJK_document_right_hook:
      }
  }
\cs_new_nopar:Npn \xeCJK_reverse:nnn #1#2#3
  { \str_if_eq_x:nnTF {#1} {#2} {#3} {#2} }
\cs_new_protected_nopar:Npn \xeCJK_tl_remove_outer_braces:N #1
  { \tl_set:Nx #1 { \exp_args:NV \xeCJK_tl_remove_outer_braces:n #1 } }
\cs_new:Npn \xeCJK_tl_remove_outer_braces:n #1
  { \__xeCJK_tl_remove_outer_braces:w #1 \q_stop }
\cs_new:Npn \__xeCJK_tl_remove_outer_braces:w #1 \q_stop
  {
    \bool_if:nTF { \tl_if_single_p:n {#1} && \tl_if_head_is_group_p:n {#1} }
      { \__xeCJK_tl_remove_outer_braces:w #1 \q_stop }
      { \tl_trim_spaces:n {#1} }
  }
\cs_new_eq:NN \xeCJK_cs_clear:N \tl_clear:N
\cs_new_eq:NN \xeCJK_cs_gclear:N \tl_gclear:N
\cs_new_protected:Npn \xeCJK_swap_cs:NN #1#2
  {
    \cs_set_eq:NN \__xeCJK_swap_cs_aux:w #1
    \cs_set_eq:NN #1 #2
    \cs_set_eq:NN #2 \__xeCJK_swap_cs_aux:w
    \cs_undefine:N \__xeCJK_swap_cs_aux:w
  }
\cs_new_protected_nopar:Npn \xeCJK_font_gset_to_current:c #1
  {
    \exp_after:wN \cs_gset_eq:NN
    \cs:w #1 \exp_after:wN \cs_end: \tex_the:D \tex_font:D
  }
\prg_new_conditional:Npnn \xeCJK_glyph_if_exist:N #1 { p , T , F , TF }
  {
    \etex_iffontchar:D \tex_font:D `#1 \exp_stop_f:
      \prg_return_true: \else: \prg_return_false: \fi:
  }
\tl_const:Nn \c_xeCJK_space_skip_tl
  {
    \skip_if_eq:nnTF \tex_spaceskip:D \c_zero_skip
      {
        \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
      }
      { \tex_spaceskip:D }
  }
\cs_new_protected_nopar:Npn \xeCJK_glue_to_skip:nN #1#2
  {
    \hbox_set:Nn \l__xeCJK_tmp_box { #1 \scan_stop: \exp_after:wN } \exp_after:wN
    \skip_set:Nn \exp_after:wN #2 \exp_after:wN { \skip_use:N \tex_lastskip:D }
  }
\prg_new_conditional:Npnn \xeCJK_if_blank_x:n #1 { p , T , F , TF }
  {
    \if_case:w \pdftex_strcmp:D { } {#1} \exp_stop_f:
      \prg_return_true:
    \else:
      \if_case:w \pdftex_strcmp:D { ~ } {#1} \exp_stop_f:
        \prg_return_true: \else: \prg_return_false: \fi:
    \fi:
  }
\cs_new_protected:Npn \xeCJK_int_until_do:nn #1#2
  { \__xeCJK_int_until_do:wn \use_none:n { \reverse_if:N \if_int_compare:w #1#2 } }
\cs_new_protected:Npn \__xeCJK_int_until_do:wn \use_none:n #1
  { #1 \exp_after:wN \__xeCJK_int_until_do:wn \fi: \use_none:n {#1} }
\cs_new_protected:Npn \xeCJK_peek_catcode_ignore_spaces:NTF #1#2#3
  {
    \cs_set_eq:NN \l__peek_search_token #1 \scan_stop:
    \tl_set:Nn \__xeCJK_peek_catcode_true:w  { \group_align_safe_end: #2 }
    \tl_set:Nn \__xeCJK_peek_catcode_false:w { \group_align_safe_end: #3 }
    \bool_set_false:N \l__xeCJK_peek_ignore_spaces_bool
    \group_align_safe_begin:
    \peek_after:Nw \__xeCJK_peek_catcode_ignore_spaces_branches:w
  }
\cs_new_protected_nopar:Npn \__xeCJK_peek_catcode_ignore_spaces_branches:w
  {
    \if_meaning:w \l_peek_token \c_space_token
      \bool_set_true:N \l__xeCJK_peek_ignore_spaces_bool
      \exp_after:wN \peek_after:Nw
      \exp_after:wN \__xeCJK_peek_catcode_ignore_spaces_branches:w
      \tex_romannumeral:D 0
    \else:
      \if_catcode:w
        \exp_not:N \l_peek_token \exp_not:N \l__peek_search_token
        \exp_after:wN \exp_after:wN
        \exp_after:wN \__xeCJK_peek_catcode_true:w
      \else:
        \exp_after:wN \exp_after:wN
        \exp_after:wN \__xeCJK_peek_catcode_false:w
      \fi:
    \fi:
  }
\bool_new:N \l__xeCJK_peek_ignore_spaces_bool
\cs_new_protected:Npn \xeCJK_peek_after_ignore_spaces:nw #1
  {
    \tl_set:Nn \__xeCJK_peek_after_do:w { \group_align_safe_end: #1 }
    \group_align_safe_begin:
    \peek_after:Nw \__xeCJK_peek_ignore_spaces_branches:w
  }
\cs_new_protected_nopar:Npn \__xeCJK_peek_ignore_spaces_branches:w
  {
    \if_meaning:w \l_peek_token \c_space_token
      \exp_after:wN \peek_after:Nw
      \exp_after:wN \__xeCJK_peek_ignore_spaces_branches:w
      \tex_romannumeral:D 0
    \else:
      \exp_after:wN \__xeCJK_peek_after_do:w
    \fi:
  }
\cs_new_nopar:Npn \xeCJK_token_value_class:N #1
  { \XeTeXcharclass \xeCJK_token_value_charcode:N #1 }
\cs_new_nopar:Npn \xeCJK_token_value_charcode:N #1
  { \exp_after:wN \__xeCJK_token_value_charcode:w \token_to_meaning:N #1 \q_stop }
\fp_compare:nNnTF { \int_use:N \xetex_XeTeXversion:D \XeTeXrevision } > { 0.9998 }
  {
    \cs_new_nopar:Npn \__xeCJK_token_value_charcode:w #1 ~ #2 ~ #3 \q_stop
      { `#3 }
  }
  {
    \cs_new_nopar:Npn \__xeCJK_token_value_charcode:w #1 ~ #2 ~ #3#4 \q_stop
      { \tl_if_empty:nTF {#4} { `#3 } { "20000 } }
  }
\prg_new_conditional:Npnn \xeCJK_if_CJK_class:N #1 { p , T , F , TF }
  {
    \if_cs_exist:w \__xeCJK_CJK_class_tl:n { \xeCJK_token_value_class:N #1 } \cs_end:
      \prg_return_true: \else: \prg_return_false: \fi:
  }
\cs_new_nopar:Npn \__xeCJK_CJK_class_tl:n #1
  { c__xeCJK_CJK_class_ \int_eval:n {#1} _tl }
\cs_generate_variant:Nn \__xeCJK_CJK_class_tl:n { c }
\prg_new_conditional:Npnn \xeCJK_if_same_class:NN #1#2 { p , T , F , TF }
  {
    \if_int_compare:w
      \xeCJK_token_value_class:N #1 = \xeCJK_token_value_class:N #2 \exp_stop_f:
      \prg_return_true: \else: \prg_return_false: \fi:
  }
\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 }
\seq_new:N \g__xeCJK_class_seq
\seq_new:N \g__xeCJK_new_class_seq
\cs_new_protected_nopar:Npn \xeCJK_new_class:n #1
  {
    \int_if_exist:cTF { \__xeCJK_class_csname:n {#1} }
      { \__xeCJK_error:nx { class-already-defined } {#1} }
      {
        \exp_args:Nc \newXeTeXintercharclass { \__xeCJK_class_csname:n {#1} }
        \clist_new:c { g__xeCJK_#1_range_clist }
        \seq_gput_right:Nn \g__xeCJK_class_seq {#1}
        \seq_gput_right:Nv \g__xeCJK_new_class_seq { \__xeCJK_class_csname:n {#1} }
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_save_class:nn #1#2
  {
    \int_if_exist:cTF { \__xeCJK_class_csname:n {#1} }
      { \__xeCJK_error:nx { class-already-defined } {#1} }
      {
        \int_const:cn { \__xeCJK_class_csname:n {#1} } {#2}
        \clist_new:c { g__xeCJK_#1_range_clist }
        \seq_gput_right:Nn \g__xeCJK_class_seq {#1}
      }
  }
\cs_new_nopar:Npn \__xeCJK_class_csname:n #1 { c__xeCJK_#1_class_int }
\cs_new_eq:cN { \__xeCJK_class_csname:n { Others } } \l__xeCJK_tmpa_int
\__xeCJK_msg_new:nn { class-already-defined }
  {
    XeTeX~character~class~`#1'~has~been~already~defined.\\\\
    Please~take~another~name. \\
  }
\xeCJK_save_class:nn { Default }   { \c_zero  }
\xeCJK_save_class:nn { CJK }       { \c_one   }
\xeCJK_save_class:nn { FullLeft }  { \c_two   }
\xeCJK_save_class:nn { FullRight } { \c_three }
\xeCJK_save_class:nn { Boundary }  { \c_two_hundred_fifty_five }
\xeCJK_new_class:n { HalfLeft }
\xeCJK_new_class:n { HalfRight }
\xeCJK_new_class:n { NormalSpace }
\clist_const:Nn \c__xeCJK_HalfLeft_chars_clist
  { "28 , "2D , "5B , "60 , "7B }
\clist_const:Nn \c__xeCJK_HalfRight_chars_clist
  { "21 , "22 , "25 , "27 , "29 , "2C , "2E , "3A , "3B , "3F , "5D , "7D }
\clist_const:Nn \c__xeCJK_NormalSpace_chars_clist { "2F }
\clist_const:Nn \c__xeCJK_FullLeft_chars_clist
  {
     "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
  }
\clist_const:Nn \c__xeCJK_FullRight_chars_clist
  {
     "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
  }
\clist_const:Nn \c__xeCJK_CJK_chars_clist
  {
     "1100 -> "11FF ,
     "2E80 -> "2EFF ,
     "2F00 -> "2FDF ,
     "2FF0 -> "2FFF ,
     "3000 -> "303F ,
     "3040 -> "309F ,
     "30A0 -> "30FF ,
     "3100 -> "312F ,
     "3130 -> "318F ,
     "3190 -> "319F ,
     "31A0 -> "31BF ,
     "31C0 -> "31EF ,
     "31F0 -> "31FF ,
     "3200 -> "32FF ,
     "3300 -> "33FF ,
     "3400 -> "4DBF ,
     "4DC0 -> "4DFF ,
     "4E00 -> "9FFF ,
     "A000 -> "A48F ,
     "A490 -> "A4CF ,
     "A960 -> "A97F ,
     "AC00 -> "D7AF ,
     "B000 -> "B0FF ,
     "D7B0 -> "D7FF ,
     "F900 -> "FAFF ,
     "FE30 -> "FE4F ,
     "FF00 -> "FFEF ,
     "20000 -> "2A6DF ,
     "2A700 -> "2B73F ,
     "2B740 -> "2B81F ,
     "2F800 -> "2FA1F
  }
\seq_new:N \g__xeCJK_base_class_seq
\seq_gset_eq:NN \g__xeCJK_base_class_seq \g__xeCJK_class_seq
\seq_new:N \g__xeCJK_non_CJK_class_seq
\seq_gset_from_clist:Nn \g__xeCJK_non_CJK_class_seq
  { Default , HalfLeft , HalfRight , NormalSpace , Boundary }
\seq_new:N \g__xeCJK_CJK_class_seq
\cs_new_protected_nopar:Npn \__xeCJK_save_CJK_class:n #1
  {
    \seq_gput_right:Nn \g__xeCJK_CJK_class_seq {#1}
    \tl_const:cn { \__xeCJK_CJK_class_tl:c { \__xeCJK_class_csname:n {#1} } } {#1}
  }
\clist_map_function:nN { CJK , FullLeft , FullRight } \__xeCJK_save_CJK_class:n
\cs_new_nopar:Npn \xeCJK_class_num:n #1 { \use:c { \__xeCJK_class_csname:n {#1} } }
\NewDocumentCommand \xeCJKDeclareCharClass { s > { \TrimSpaces } m m }
  {
    \xeCJK_declare_char_class:nx {#2} {#3}
    \IfBooleanT {#1} { \xeCJKResetPunctClass }
  }
\cs_new_protected_nopar:Npn \xeCJK_declare_char_class:nn #1#2
  {
    \clist_set:Nn \l__xeCJK_tmpa_clist {#2}
    \clist_gconcat:ccN
      { g__xeCJK_#1_range_clist } { g__xeCJK_#1_range_clist } \l__xeCJK_tmpa_clist
    \clist_map_inline:Nn \l__xeCJK_tmpa_clist
      {
        \str_if_eq:nnF {##1} { -> }
          {
            \__xeCJK_set_char_class_aux:Nnw \xeCJK_set_char_class:nnn {##1}
              { \xeCJK_class_num:n {#1} }
          }
      }
  }
\NewDocumentCommand \__xeCJK_set_char_class_aux:Nnw
  { m > { \SplitArgument { 1 } { -> } } m } { #1 #2 }
\cs_generate_variant:Nn \clist_gconcat:NNN { cc }
\cs_generate_variant:Nn \xeCJK_declare_char_class:nn { nx , nV }
\cs_new_protected_nopar:Npn \__xeCJK_set_char_class_catcode: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}
    \int_compare:nNnTF
      { \use:c { \__xeCJK_class_csname:n { CJK } } } = \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 > \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_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}
    \xeCJK_int_until_do:nn { \l__xeCJK_tmpa_int > \l__xeCJK_tmpb_int }
      {
        \XeTeXcharclass \l__xeCJK_tmpa_int = \l__xeCJK_tmpc_int
        \int_incr:N \l__xeCJK_tmpa_int
      }
  }
\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} } }
      }
  }
\cs_new_eq:NN \xeCJK_set_char_class:nnn \__xeCJK_set_char_class_catcode:nnn
\AtEndOfPackage
  { \cs_set_eq:NN \xeCJK_set_char_class:nnn \__xeCJK_set_char_class:nnn }
\cs_new_protected_nopar:Npn \__xeCJK_set_char_class_eq:nn #1#2
  {
    \int_set:Nn \l__xeCJK_tmpa_int { \xeCJK_class_num:n {#2} }
    \clist_map_inline:cn { c__xeCJK_#1_chars_clist }
      { \XeTeXcharclass ##1 = \l__xeCJK_tmpa_int }
  }
\NewDocumentCommand \normalspacedchars { m }
  {
    \tl_map_inline:nn {#1}
      { \XeTeXcharclass `##1 = \xeCJK_class_num:n { NormalSpace } }
  }
\NewDocumentCommand \xeCJKResetPunctClass { }
  {
    \xeCJK_declare_char_class:nV { HalfLeft  } \c__xeCJK_HalfLeft_chars_clist
    \xeCJK_declare_char_class:nV { HalfRight } \c__xeCJK_HalfRight_chars_clist
    \xeCJK_declare_char_class:nV { FullLeft  } \c__xeCJK_FullLeft_chars_clist
    \xeCJK_declare_char_class:nV { FullRight } \c__xeCJK_FullRight_chars_clist
  }
\NewDocumentCommand \xeCJKResetCharClass { }
  {
    \xeCJK_declare_char_class:nV { CJK } \c__xeCJK_CJK_chars_clist
    \xeCJK_declare_char_class:nV { NormalSpace } \c__xeCJK_NormalSpace_chars_clist
    \xeCJKResetPunctClass
  }
\xeCJKResetCharClass
\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 , nnv , 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} { \prg_do_nothing: } }
\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_generate_variant:Nn \xeCJK_pre_inter_class_toks:nnn { nnx }
\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 , nnx }
\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_replace_inter_class_toks:nnnn #1#2#3#4
  {
    \tl_set:Nx \l__xeCJK_tmpa_tl { \xeCJK_get_inter_class_toks:nn {#1} {#2} }
    \tl_replace_all:Nnn \l__xeCJK_tmpa_tl {#3} {#4}
    \xeCJK_inter_class_toks:nnx {#1} {#2} { \exp_not:V \l__xeCJK_tmpa_tl }
  }
\cs_new_protected_nopar:Npn \xeCJK_clear_Boundary_and_CJK_toks:
  { \seq_map_function:NN \g__xeCJK_CJK_class_seq \__xeCJK_clear_Boundary_and_CJK_toks:n }
\cs_new_protected_nopar:Npn \__xeCJK_clear_Boundary_and_CJK_toks:n #1
  { \xeCJK_clear_inter_class_toks:nn { Boundary } {#1} }
\cs_new_eq:NN \xeCJK_class_group_begin: \c_group_begin_token
\cs_new_eq:NN \xeCJK_class_group_end: \c_group_end_token
\clist_map_inline:nn { Default , HalfLeft , HalfRight , NormalSpace }
  {
    \xeCJK_inter_class_toks:nnn {#1} { CJK }
      {
        \xeCJK_class_group_begin:
        \xeCJK_select_font:
        \xeCJK_clear_inter_class_toks:nn {#1} { CJK }
        \xeCJK_clear_Boundary_and_CJK_toks:
        \CJKsymbol
      }
    \xeCJK_inter_class_toks:nnn { CJK } {#1} { \xeCJK_class_group_end: }
  }
\clist_map_inline:nn { Default , HalfLeft , NormalSpace }
  {
    \xeCJK_inter_class_toks:nnn { Boundary } {#1}
      {
        \bool_if:nTF
          {
            \l__xeCJK_xecglue_bool &&
            \skip_if_eq_p:nn \tex_lastskip:D \c_xeCJK_space_skip_tl
          }
          {
            \tex_unskip:D
            \bool_if:nTF
              {
                \xeCJK_if_last_node_p:n { CJK }       ||
                \xeCJK_if_last_node_p:n { CJK-space }
              }
              { \CJKecglue } { ~ }
          }
          {
            \xeCJK_if_last_node:nTF { CJK } { \CJKecglue }
              { \xeCJK_if_last_node:nT { CJK-space } { \__xeCJK_space_or_xecglue: } }
          }
      }
    \str_if_eq: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_meaning_remove:NTF \tex_italiccorrection:D
          { \tex_italiccorrection:D { \xeCJK_make_node:n { default } } }
          {
            \token_if_space:NTF \l_peek_token
              { { \xeCJK_make_node:n { default-space } } }
              { { \xeCJK_make_node:n { default } } }
          }
      }
    \str_if_eq:nnF {#1} { NormalSpace }
      { \xeCJK_pre_inter_class_toks:nnn {#1} { CJK } { \CJKecglue } }
  }
\xeCJK_inter_class_toks:nnn { Boundary } { CJK }
  {
    \xeCJK_check_for_glue:
    \xeCJK_class_group_begin:
    \xeCJK_clear_Boundary_and_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
          }
          { \CJKecglue }
          {
            \bool_if:nT
              {
                \l__xeCJK_xecglue_bool &&
                ( \skip_if_eq_p:nn \tex_lastskip:D \c_xeCJK_space_skip_tl ||
                  \skip_if_eq_p:nn \tex_lastskip:D \l__xeCJK_ecglue_skip )
              }
              {
                \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 }
                  }
                  { \CJKecglue }
                  {
                    \bool_if:nTF
                      {
                        \xeCJK_if_last_node_p:n { CJK }       ||
                        \xeCJK_if_last_node_p:n { CJK-space }
                      }
                      { \bool_if:NTF \l__xeCJK_reserve_space_bool { ~ } { \CJKglue } }
                      { ~ }
                  }
              }
          }
      }
  }
 \prg_new_conditional:Npnn \xeCJK_if_last_node:n #1 { p , T , F , TF }
  {
    \if_dim:w \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 - \use:c { c__xeCJK_#1_node_dim }
    \tex_kern:D   \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 }
\keys_define:nn { xeCJK / options }
  {
    CJKglue .code:n =
      {
        \cs_set_protected_nopar:Npn \CJKglue {#1}
        \xeCJK_glue_to_skip:nN {#1} \l__xeCJK_ccglue_skip
      }
  }
\skip_new:N \l__xeCJK_ccglue_skip
\keys_define:nn { xeCJK / options }
  {
    CJKecglue            .code:n =
      {
        \cs_set_protected_nopar:Npn \CJKecglue {#1}
        \xeCJK_glue_to_skip:nN {#1} \l__xeCJK_ecglue_skip
      } ,
    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_tl
      } ,
    xCJKecglue / unknown .code:n =
      {
        \bool_set_true:N  \l__xeCJK_xecglue_bool
        \cs_set_protected_nopar:Npn \CJKecglue {#1}
        \xeCJK_glue_to_skip:nN {#1} \l__xeCJK_ecglue_skip
        \cs_set_eq:NN \__xeCJK_space_or_xecglue: \CJKecglue
      } ,
    xCJKecglue        .default:n = { true }
  }
\skip_new:N \l__xeCJK_ecglue_skip
\bool_new:N \l__xeCJK_xecglue_bool
\keys_define:nn { xeCJK / options }
  {
    CJKspace .bool_set:N = \l__xeCJK_reserve_space_bool ,
    space        .meta:n = { CJKspace = true  } ,
    nospace      .meta:n = { CJKspace = false }
  }
\xeCJK_inter_class_toks:nnn { CJK } { Boundary }
  {
    \xeCJK_class_group_end:
    { \xeCJK_make_node:n { CJK } }
    \xeCJK_ignore_spaces:w
  }
\cs_new_protected_nopar:Npn \xeCJK_ignore_spaces:w
  {
    \xeCJK_peek_catcode_ignore_spaces:NTF \c_math_toggle_token
      {
        \bool_if:NTF \l__xeCJK_peek_ignore_spaces_bool
          { \__xeCJK_space_or_xecglue: } { \CJKecglue }
      }
      {
        \bool_if:NTF \l__xeCJK_peek_ignore_spaces_bool
          {
            \tex_unkern:D \tex_unkern:D
            { \xeCJK_make_node:n { CJK-space } }
            \bool_if:nT
              {
                \token_if_macro_p:N \l_peek_token ||
                ( \l__xeCJK_reserve_space_bool &&
                  \token_if_other_p:N \l_peek_token )
              }
              { \__xeCJK_space_or_xecglue: }
          }
          { \cs_if_exist:NF \l_peek_token \exp_not:N }
      }
  }
\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} }
\xeCJK_inter_class_toks:nnn { FullLeft }  { CJK }
  { \xeCJK_FullLeft_and_CJK: \CJKsymbol }
\xeCJK_inter_class_toks:nnn { FullRight } { CJK }
  { \xeCJK_FullRight_and_CJK: \CJKsymbol }
\seq_map_inline:Nn \g__xeCJK_non_CJK_class_seq
  {
    \clist_map_inline:nn { FullLeft , FullRight }
      {
        \xeCJK_inter_class_toks:nnx {#1} {##1}
          { \exp_not:c { xeCJK_Default_and_##1:nN } {#1} }
        \xeCJK_inter_class_toks:nnc {##1} {#1} { xeCJK_##1_and_Default: }
      }
  }
\xeCJK_inter_class_toks:nnn { Boundary } { FullLeft }
  { \xeCJK_Boundary_and_FullLeft:N  }
\xeCJK_inter_class_toks:nnn { Boundary } { FullRight }
  { \xeCJK_Boundary_and_FullRight:N  }
\xeCJK_app_inter_class_toks:nnn { FullLeft } { Boundary } { \tex_ignorespaces:D }
\xeCJK_inter_class_toks:nnn { FullRight } { Boundary }
  { \xeCJK_FullRight_and_Boundary: }
\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_Boundary:
  { \xeCJK_FullRight_and_Default: \tex_ignorespaces:D }
\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:NN #1#2
  {
    \tex_vrule:D
      width  - \__xeCJK_use_punct_dim:nnn { bound } {#1} {#2}
      depth  \c_zero_dim
      height \c_zero_dim \scan_stop:
  }
\cs_new_protected_nopar:Npn \__xeCJK_punct_glue:NN #1#2
  {
    \__xeCJK_punct_hskip:n
      {
        \__xeCJK_use_punct_dim:nnn { glue } {#1} {#2}
        minus \dim_eval:n { ( \__xeCJK_use_punct_dim:nnn { glue } {#1} {#2} ) / \c_two }
      }
  }
\cs_new_eq:NN \__xeCJK_punct_hskip:n \skip_horizontal:n
\cs_new_protected_nopar:Npn \__xeCJK_punct_kern:NN #1#2
  { \tex_kern:D \__xeCJK_use_punct_dim:nnn { kern } {#1} {#2} }
\tl_new:N \g__xeCJK_last_punct_tl
\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_CJK:
  {
    \__xeCJK_punct_if_middle:NTF \g__xeCJK_last_punct_tl
      {
        \__xeCJK_punct_rule:NN \c__xeCJK_right_tl \g__xeCJK_last_punct_tl
        \xeCJK_no_break:
        \__xeCJK_punct_glue:NN \c__xeCJK_left_tl  \g__xeCJK_last_punct_tl
      }
      { \xeCJK_no_break: }
  }
\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_Default:
  {
    \__xeCJK_punct_if_middle:NTF \g__xeCJK_last_punct_tl
      {
        \__xeCJK_punct_rule:NN \c__xeCJK_right_tl \g__xeCJK_last_punct_tl
        \xeCJK_class_group_end: \xeCJK_no_break:
        \__xeCJK_punct_glue:NN \c__xeCJK_left_tl  \g__xeCJK_last_punct_tl
      }
      { \xeCJK_class_group_end: \xeCJK_no_break: }
  }
\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_CJK:
  {
    \__xeCJK_punct_rule:NN \c__xeCJK_right_tl \g__xeCJK_last_punct_tl
    \__xeCJK_punct_glue:NN \c__xeCJK_right_tl \g__xeCJK_last_punct_tl
    \CJKglue
  }
\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_Default:
  {
    \__xeCJK_punct_rule:NN \c__xeCJK_right_tl \g__xeCJK_last_punct_tl
    \xeCJK_class_group_end:
    \__xeCJK_punct_glue:NN \c__xeCJK_right_tl \g__xeCJK_last_punct_tl
  }
\cs_new_protected_nopar:Npn \xeCJK_Default_and_FullLeft:nN #1#2
  {
    \xeCJK_get_punct_bounds:NN \c__xeCJK_left_tl {#2}
    \__xeCJK_Default_and_FullLeft_glue:N {#2}
    \xeCJK_class_group_begin:
    \xeCJK_select_font:
    \xeCJK_clear_inter_class_toks:nn {#1} { FullLeft }
    \xeCJK_clear_Boundary_and_CJK_toks:
    \tl_gset:Nx \g__xeCJK_last_punct_tl {#2}
    \__xeCJK_punct_rule:NN \c__xeCJK_left_tl {#2}
    \CJKpunctsymbol {#2}
  }
\cs_new_protected_nopar:Npn \__xeCJK_Default_and_FullLeft_glue:N #1
  { \__xeCJK_punct_glue:NN \c__xeCJK_left_tl {#1} }
\cs_new_protected_nopar:Npn \xeCJK_CJK_and_FullLeft:N #1
  {
    \xeCJK_get_punct_bounds:NN \c__xeCJK_left_tl {#1}
    \__xeCJK_CJK_and_FullLeft_glue:N {#1}
    \tl_gset:Nx \g__xeCJK_last_punct_tl {#1}
    \__xeCJK_punct_rule:NN \c__xeCJK_left_tl {#1}
    \CJKpunctsymbol {#1}
  }
\cs_new_protected_nopar:Npn \__xeCJK_CJK_and_FullLeft_glue:N #1
  { \CJKglue \__xeCJK_punct_glue:NN \c__xeCJK_left_tl {#1} }
\cs_new_protected_nopar:Npn \xeCJK_Boundary_and_FullLeft:N #1
  {
    \xeCJK_get_punct_bounds:NN \c__xeCJK_left_tl {#1}
    \__xeCJK_Boundary_and_FullLeft_glue:N {#1}
    \xeCJK_class_group_begin:
    \xeCJK_select_font:
    \xeCJK_clear_Boundary_and_CJK_toks:
    \tl_gset:Nx \g__xeCJK_last_punct_tl {#1}
    \__xeCJK_punct_rule:NN \c__xeCJK_left_tl {#1}
    \CJKpunctsymbol {#1}
  }
\cs_new_protected_nopar:Npn \__xeCJK_Boundary_and_FullLeft_glue:N #1
  {
    \int_compare:nNnF \etex_lastnodetype:D = \c_one
      { \__xeCJK_punct_glue:NN \c__xeCJK_left_tl {#1} }
  }
\cs_new_protected_nopar:Npn \xeCJK_Default_and_FullRight:nN #1#2
  {
    \xeCJK_get_punct_bounds:NN \c__xeCJK_right_tl {#2}
    \__xeCJK_Default_and_FullRight_glue:N {#2}
    \xeCJK_class_group_begin:
    \xeCJK_select_font:
    \xeCJK_clear_inter_class_toks:nn {#1} { FullRight }
    \xeCJK_clear_Boundary_and_CJK_toks:
    \tl_gset:Nx \g__xeCJK_last_punct_tl {#2}
    \__xeCJK_punct_if_middle:NT {#2}
      { \__xeCJK_punct_rule:NN \c__xeCJK_left_tl {#2} }
    \xeCJK_FullRight_symbol:N {#2}
  }
\cs_new_protected_nopar:Npn \xeCJK_Boundary_and_FullRight:N #1
  {
    \xeCJK_get_punct_bounds:NN \c__xeCJK_right_tl {#1}
    \__xeCJK_Default_and_FullRight_glue:N {#1}
    \xeCJK_class_group_begin:
    \xeCJK_select_font:
    \xeCJK_clear_Boundary_and_CJK_toks:
    \tl_gset:Nx \g__xeCJK_last_punct_tl {#1}
    \__xeCJK_punct_if_middle:NT {#1}
      { \__xeCJK_punct_rule:NN \c__xeCJK_left_tl {#1} }
    \xeCJK_FullRight_symbol:N {#1}
  }
\cs_new_protected_nopar:Npn \xeCJK_CJK_and_FullRight:N #1
  {
    \xeCJK_get_punct_bounds:NN \c__xeCJK_right_tl {#1}
    \__xeCJK_CJK_and_FullRight_glue:N {#1}
    \tl_gset:Nx \g__xeCJK_last_punct_tl {#1}
    \__xeCJK_punct_if_middle:NT {#1}
      { \__xeCJK_punct_rule:NN \c__xeCJK_left_tl {#1} }
    \xeCJK_FullRight_symbol:N {#1}
  }
\cs_new_protected_nopar:Npn \__xeCJK_CJK_and_FullRight_glue:N #1
  {
    \__xeCJK_punct_if_long:NTF {#1}
      { \CJKglue }
      {
        \__xeCJK_punct_if_middle:NTF {#1}
          { \xeCJK_no_break: \__xeCJK_punct_glue:NN \c__xeCJK_right_tl {#1} }
          { \xeCJK_no_break: }
      }
  }
\cs_new_eq:NN \__xeCJK_Default_and_FullRight_glue:N \__xeCJK_CJK_and_FullRight_glue:N
\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_FullLeft:N #1
  {
    \xeCJK_no_break:
    \xeCJK_get_punct_bounds:NN \c__xeCJK_left_tl {#1}
    \xeCJK_get_punct_kerning:oN \g__xeCJK_last_punct_tl {#1}
    \__xeCJK_punct_kern:NN \g__xeCJK_last_punct_tl {#1}
    \tl_gset:Nx \g__xeCJK_last_punct_tl {#1}
    \CJKpunctsymbol {#1}
  }
\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_FullRight:N #1
  {
    \xeCJK_no_break:
    \xeCJK_get_punct_bounds:NN \c__xeCJK_right_tl {#1}
    \xeCJK_get_punct_kerning:oN \g__xeCJK_last_punct_tl {#1}
    \__xeCJK_punct_kern:NN \g__xeCJK_last_punct_tl {#1}
    \tl_gset:Nx \g__xeCJK_last_punct_tl {#1}
    \xeCJK_no_break:
    \xeCJK_FullRight_symbol:N {#1}
  }
\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_FullLeft:N #1
  {
    \xeCJK_get_punct_bounds:NN \c__xeCJK_left_tl {#1}
    \xeCJK_get_punct_kerning:oN \g__xeCJK_last_punct_tl {#1}
    \__xeCJK_punct_kern:NN \g__xeCJK_last_punct_tl {#1}
    \tl_gset:Nx \g__xeCJK_last_punct_tl {#1}
    \__xeCJK_punct_break:
    \CJKpunctsymbol {#1}
  }
\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_FullRight:N #1
  {
    \xeCJK_get_punct_bounds:NN \c__xeCJK_right_tl {#1}
    \xeCJK_get_punct_kerning:oN \g__xeCJK_last_punct_tl {#1}
    \__xeCJK_punct_kern:NN \g__xeCJK_last_punct_tl {#1}
    \tl_gset:Nx \g__xeCJK_last_punct_tl {#1}
    \xeCJK_no_break:
    \xeCJK_FullRight_symbol:N {#1}
  }
\keys_define:nn { xeCJK / options }
  {
    CheckFullRight .choice: ,
    CheckFullRight / true  .code:n =
      {
        \cs_if_eq:NNF \xeCJK_FullRight_and_Boundary: \xeCJK_check_FullRight:
          {
            \cs_set_eq:NN \__xeCJK_save_FullRight_check: \xeCJK_FullRight_and_Boundary:
            \cs_set_eq:NN \__xeCJK_save_FullRight_symbol:N \xeCJK_FullRight_symbol:N
            \cs_set_eq:NN \xeCJK_FullRight_and_Boundary: \xeCJK_check_FullRight:
            \cs_set_eq:NN \xeCJK_FullRight_symbol:N \xeCJK_check_FullRight_symbol:Nw
          }
      } ,
    CheckFullRight / false .code:n =
      {
        \cs_if_eq:NNT \xeCJK_FullRight_and_Boundary: \xeCJK_check_FullRight:
          {
            \cs_set_eq:NN \xeCJK_FullRight_and_Boundary: \__xeCJK_save_FullRight_check:
            \cs_set_eq:NN \xeCJK_FullRight_symbol:N \__xeCJK_save_FullRight_symbol:N
          }
      } ,
    CheckFullRight      .default:n = { true }
  }
\cs_new_nopar:Npn \xeCJK_FullRight_symbol:N { \CJKpunctsymbol }
\cs_new_protected_nopar:Npn \xeCJK_check_FullRight:
  {
    \xeCJK_get_punct_bounds:NN \c__xeCJK_right_tl \g__xeCJK_last_punct_tl
    \__xeCJK_punct_rule:NN \c__xeCJK_right_tl \g__xeCJK_last_punct_tl
    \tl_case:Non \l_peek_token { \l__xeCJK_no_break_cs_case_tl } {  }
    \__xeCJK_punct_glue:NN \c__xeCJK_right_tl \g__xeCJK_last_punct_tl
    \xeCJK_class_group_end:
  }
\cs_generate_variant:Nn \tl_case:Nnn { No }
\cs_new_protected_nopar:Npn \xeCJK_check_FullRight_symbol:Nw #1
  { \xeCJK_peek_after_ignore_spaces:nw { \__xeCJK_save_FullRight_symbol:N {#1} } }
\cs_new_protected:Npn \xeCJK_cs_case_keys_define:nNNnn #1#2#3#4#5
  {
    \tl_new:N #2
    \seq_new:N #3
    \keys_define:nn { xeCJK / options }
      {
        #1  .code:n =
          {
            \seq_set_split:Nnn #3 { } {##1}
            \__xeCJK_update_cs_case_tl:NNnn #2#3 {#4} {#5}
          } ,
        #1+ .code:n =
          {
            \tl_map_inline:nn {##1}
              { \seq_if_in:NnF #2 {####1} { \seq_put_right:Nn #3 {####1} } }
            \__xeCJK_update_cs_case_tl:NNnn #2#3 {#4} {#5}
          } ,
        #1- .code:n =
          {
            \tl_map_inline:nn {##1} { \seq_remove_all:Nn #3 {####1} }
            \__xeCJK_update_cs_case_tl:NNnn #2#3 {#4} {#5}
          }
      }
  }
\cs_new_protected:Npn \__xeCJK_update_cs_case_tl:NNnn #1#2#3#4
  {
    \tl_clear:N #1
    \seq_map_inline:Nn #2 { \tl_put_right:Nn #1 { {##1} {#3} } }
    #4
  }
\xeCJK_cs_case_keys_define:nNNnn { NoBreakCS }
  \l__xeCJK_no_break_cs_case_tl \l__xeCJK_no_break_cs_seq { \xeCJK_no_break: } { }
\NewDocumentCommand \xeCJKnobreak { }
  {
    \int_zero:N \l__xeCJK_tmpa_int
    \int_while_do:nNnn \etex_lastnodetype:D = \c_eleven
      {
        \int_if_even:nTF \l__xeCJK_tmpa_int
          {
            \int_incr:N \l__xeCJK_tmpa_int
            \skip_set_eq:NN \l__xeCJK_tmp_skip \tex_lastskip:D
          }
          { \skip_add:Nn \l__xeCJK_tmp_skip \tex_lastskip:D }
        \tex_unskip:D
      }
    \xeCJK_no_break:
    \int_if_even:nF \l__xeCJK_tmpa_int
      { \skip_horizontal:N \l__xeCJK_tmp_skip }
  }
\keys_define:nn { xeCJK / options }
  {
    CheckSingle .choice: ,
    CheckSingle / true  .code:n =
      {
        \cs_if_eq:NNF \xeCJK_CJK_and_CJK:N \xeCJK_check_single:Nw
          {
            \cs_set_eq:NN \__xeCJK_check_single_save:N \xeCJK_CJK_and_CJK:N
            \cs_set_eq:NN \xeCJK_CJK_and_CJK:N \xeCJK_check_single:Nw
          }
      } ,
    CheckSingle / false .code:n =
      {
        \cs_if_eq:NNT \xeCJK_CJK_and_CJK:N \xeCJK_check_single:Nw
          { \cs_set_eq:NN  \xeCJK_CJK_and_CJK:N \__xeCJK_check_single_save:N }
      } ,
    CheckSingle      .default:n = { true } ,
    CJKchecksingle      .meta:n = { CheckSingle = true }
  }
\cs_new_protected_nopar:Npn \xeCJK_check_single:Nw #1
  {
    \peek_catcode:NTF \c_catcode_other_token
      { \xeCJK_check_single:NNw #1 }
      {
        \bool_if:nTF
          {
            \xeCJK_if_blank_x_p:n { \token_get_arg_spec:N \l_peek_token } &&
            \exp_args:No \tl_if_single_token_p:n \l_peek_token            &&
            \exp_after:wN \token_if_other_p:N \l_peek_token
          }
          { \exp_after:wN \xeCJK_check_single:NNw \exp_after:wN #1 }
          { \__xeCJK_check_single_save:N #1 }
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_check_single:NNw #1#2
  {
    \xeCJK_peek_catcode_ignore_spaces:NTF \c_catcode_other_token
      {
        \bool_if:NTF \l__xeCJK_peek_ignore_spaces_bool
          { \__xeCJK_check_single_space:NN #1#2 }
          { \__xeCJK_check_single_save:N #1 #2 }
      }
      {
        \group_align_safe_begin:
        \token_if_cs:NTF \l_peek_token
          {
            \group_align_safe_end:
            \bool_if:NTF \l__xeCJK_peek_ignore_spaces_bool
              { \xeCJK_check_single_cs:NNn #1#2 { ~ } }
              { \xeCJK_check_single_cs:NNn #1#2 { } }
          }
          {
            \group_align_safe_end:
            \bool_if:nTF
              {
                \l__xeCJK_plain_equation_bool &&
                \token_if_math_toggle_p:N \l_peek_token
              }
              {
                \bool_if:NTF \l__xeCJK_peek_ignore_spaces_bool
                  { \xeCJK_check_single_equation:NNnNw #1 #2 { ~ } }
                  { \xeCJK_check_single_equation:NNnNw #1 #2 { } }
              }
              {
                \bool_if:NTF \l__xeCJK_peek_ignore_spaces_bool
                  { \__xeCJK_check_single_save:N #1 #2 ~ }
                  { \__xeCJK_check_single_save:N #1 #2 }
              }
          }
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_check_single_space:NN #1#2
  {
    \xeCJK_if_CJK_class:NTF #2
      {
        \xeCJK_if_CJK_class:NTF \l_peek_token
          { \__xeCJK_check_single_save:N #1 #2 }
          { \__xeCJK_check_single_save:N #1 #2 ~ }
      }
      { \__xeCJK_check_single_save:N #1 #2 ~ }
  }
\cs_new_protected_nopar:Npn \xeCJK_check_single_equation:NNnNw #1#2#3#4
  {
    \peek_catcode:NTF \c_math_toggle_token
      {
        \xeCJK_no_break: \__xeCJK_check_single_save:N #1
        \xeCJK_no_break: #2 #4
      }
      { \__xeCJK_check_single_save:N #1 #2#3#4 }
  }
\cs_new_protected_nopar:Npn \xeCJK_check_single_cs:NNn #1#2#3
  {
    \tl_case:Non \l_peek_token
      { \l__xeCJK_check_single_cs_case_tl }
      { \use_iii:nnn }
      { \xeCJK_check_single_env:nnNn }
      {
        \xeCJK_no_break: \__xeCJK_check_single_save:N #1
        \xeCJK_no_break: #2
      }
      { \__xeCJK_check_single_save:N #1 #2#3 }
  }
\tl_new:N \l__xeCJK_check_single_cs_case_tl
\cs_new_protected_nopar:Npn \xeCJK_check_single_env:nnNn #1#2#3#4
  {
    \str_case_x:non {#4}
      { \l__xeCJK_inline_env_case_tl }
      { \use_i:nn }
      {#1} {#2}
    \scan_stop: #3 {#4}
  }
\cs_generate_variant:Nn \str_case_x:nnn { no }
\xeCJK_cs_case_keys_define:nNNnn { NewLineCS }
  \l__xeCJK_new_line_cs_case_tl \l__xeCJK_new_line_cs_seq { \use_ii:nnn }
  {
    \tl_concat:NNN \l__xeCJK_check_single_cs_case_tl
      \l__xeCJK_new_line_cs_case_tl \l__xeCJK_env_cs_case_tl
  }
\xeCJK_cs_case_keys_define:nNNnn { EnvCS }
  \l__xeCJK_env_cs_case_tl \l__xeCJK_env_cs_seq { \use:n }
  {
    \tl_concat:NNN \l__xeCJK_check_single_cs_case_tl
      \l__xeCJK_new_line_cs_case_tl \l__xeCJK_env_cs_case_tl
  }
\keys_define:nn { xeCJK / options }
  {
    InlineEnv  .code:n =
      {
        \seq_set_from_clist:Nn \l__xeCJK_inline_env_seq {#1}
        \__xeCJK_update_inline_env_case_tl:
      } ,
    InlineEnv+      .code:n =
      {
        \clist_map_inline:nn {#1}
          {
            \seq_if_in:NnF \l__xeCJK_inline_env_seq {##1}
              { \seq_put_right:Nn \l__xeCJK_inline_env_seq {##1} }
          }
        \__xeCJK_update_inline_env_case_tl:
      } ,
    InlineEnv-      .code:n =
      {
        \clist_map_inline:nn {#1}
          { \seq_remove_all:Nn \l__xeCJK_inline_env_seq {##1} }
        \__xeCJK_update_inline_env_case_tl:
      }
  }
\seq_new:N \l__xeCJK_inline_env_seq
\cs_new_protected:Npn \__xeCJK_update_inline_env_case_tl:
  {
    \tl_clear:N \l__xeCJK_inline_env_case_tl
    \seq_map_inline:Nn \l__xeCJK_inline_env_seq
      { \tl_put_right:Nn \l__xeCJK_inline_env_case_tl { {##1} { \use_ii:nn } } }
  }
\tl_new:N \l__xeCJK_inline_env_case_tl
\keys_define:nn { xeCJK / options }
  { PlainEquation .bool_set:N = \l__xeCJK_plain_equation_bool }
\seq_new:N \g__xeCJK_CJK_sub_class_seq
\NewDocumentCommand \xeCJKDeclareSubCJKBlock
  { s > { \TrimSpaces } m > { \TrimSpaces } m }
  {
    \xeCJK_declare_sub_char_class:nxx { 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:x {#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:x {#2}
        \IfBooleanT {#1} { \xeCJKResetPunctClass }
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_sub_restore_or_cancel:n #1
  {
    \clist_map_inline:nn {#1}
      {
        \int_if_exist:cTF { \__xeCJK_class_csname:n { CJK/##1 } }
          {
            \xeCJK_declare_char_class:nx
              { 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} }
      }
  }
\cs_generate_variant:Nn \__xeCJK_sub_restore_or_cancel:n { x }
\__xeCJK_msg_new:nn { SubBlock-undefined }
  {
    The~CJK~sub~block~`#1'~is~undefined.\\\\
    Try~to~use~\token_to_str:N \xeCJKDeclareSubCJKBlock \
    to~declare~it.
  }
\cs_new_protected_nopar:Npn \xeCJK_declare_sub_char_class:nnn #1#2#3
  {
    \int_if_exist:cF { \__xeCJK_class_csname:n { #1/#2 } }
      {
        \xeCJK_new_class:n { #1/#2 }
        \__xeCJK_set_sub_class_toks:nn {#1} {#2}
        \xeCJK_new_sub_key:n {#2}
      }
    \xeCJK_declare_char_class:nn { #1/#2 } {#3}
  }
\cs_generate_variant:Nn \xeCJK_declare_sub_char_class:nnn { nxx }
\cs_new_protected_nopar:Npn \__xeCJK_set_sub_class_toks:nn #1#2
  {
    \seq_map_inline:Nn \g__xeCJK_base_class_seq
      {
        \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:nnTF {##1} { CJK }
          {
            \xeCJK_pre_inter_class_toks:nnn {##1} { #1/#2 }
              { \__xeCJK_switch_font:nn {#1} {#2} }
          }
          {
            \xeCJK_replace_inter_class_toks:nnnn {##1} { #1/#2 }
              { \CJKsymbol }
              { \__xeCJK_switch_font:nn {#1} {#2} \CJKsymbol }
          }
      }
    \xeCJK_copy_inter_class_toks:nnnn { #1/#2 } { #1/#2 } {#1} {#1}
    \seq_map_inline:Nn \g__xeCJK_CJK_sub_class_seq
      {
        \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} }
      }
    \seq_gput_right:Nn \g__xeCJK_CJK_sub_class_seq {#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} }
      }
  }
\__xeCJK_msg_new:nn { XeTeX-too-old }
  {
    \token_to_str:N \XeTeXglyphbounds \ is~not~defined.\\
    CJK~punctuation~kerning~will~not~be~available.\\\\
    You~have~to~update~XeTeX~to~the~version~0.9995.0~or~later.
  }
\cs_if_exist:NF \XeTeXglyphbounds
  {
    \__xeCJK_error:n { XeTeX-too-old }
    \__xeCJK_after_end_preamble:n { \xeCJKsetup { PunctStyle = plain } }
  }
\NewDocumentCommand \xeCJKsetwidth { m m }
  { \tl_map_inline:xn {#1} { \tl_gset:cn { g__xeCJK_punct_width/##1/tl } {#2} } }
\cs_generate_variant:Nn \tl_map_inline:nn { x }
\NewDocumentCommand \xeCJKsetkern { m m m }
  { \tl_gset:cn { g__xeCJK_punct/kern/#1/#2/tl } {#3} }
\tl_const:Nn \c__xeCJK_left_tl  { left }
\tl_const:Nn \c__xeCJK_right_tl { right }
\keys_define:nn { xeCJK / options }
  {
    AllowBreakBetweenPuncts .choice: ,
    AllowBreakBetweenPuncts / true  .code:n =
      { \cs_set_eq:NN \__xeCJK_punct_break: \xeCJK_allow_break: } ,
    AllowBreakBetweenPuncts / false .code:n =
      { \cs_set_eq:NN \__xeCJK_punct_break: \xeCJK_no_break: } ,
    AllowBreakBetweenPuncts      .default:n = { true } ,
    KaiMingPunct  .code:n = { \__xeCJK_set_special_punct:nn { mixed_width } {#1} } ,
    KaiMingPunct+ .code:n = { \__xeCJK_add_special_punct:nn { mixed_width } {#1} } ,
    KaiMingPunct- .code:n = { \__xeCJK_sub_special_punct:nn { mixed_width } {#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_set_special_punct:nn { middle } {#1} } ,
    MiddlePunct+  .code:n = { \__xeCJK_add_special_punct:nn { middle } {#1} } ,
    MiddlePunct-  .code:n = { \__xeCJK_sub_special_punct:nn { middle } {#1} } ,
    PunctWidth .tl_gset:N = \g__xeCJK_punct_width_tl
  }
\clist_new:N \g__xeCJK_special_punct_clist
\clist_gset:Nn \g__xeCJK_special_punct_clist { mixed_width , long , middle }
\cs_new_nopar:Npn \__xeCJK_special_punct_seq:n #1 { g__xeCJK_special_punct_#1_seq }
\cs_new_nopar:Npn \__xeCJK_special_punct_tl:nN #1#2 { g__xeCJK_special_punct_#1_#2_tl }
\clist_map_inline:Nn \g__xeCJK_special_punct_clist
  { \seq_new:c { \__xeCJK_special_punct_seq:n {#1} } }
\cs_new_protected_nopar:Npn \__xeCJK_set_special_punct:nn #1#2
  {
    \seq_map_inline:cn { \__xeCJK_special_punct_seq:n {#1} }
      { \cs_undefine:c { \__xeCJK_special_punct_tl:nN {#1} {##1} } }
    \seq_gclear:c { \__xeCJK_special_punct_seq:n {#1} }
    \tl_map_inline:xn {#2}
      {
        \tl_new:c { \__xeCJK_special_punct_tl:nN {#1} {##1} }
        \seq_gput_right:cn { \__xeCJK_special_punct_seq:n {#1} } {##1}
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_add_special_punct:nn #1#2
  {
    \tl_map_inline:xn {#2}
      {
        \seq_if_in:cnF { \__xeCJK_special_punct_seq:n {#1} } {##1}
          {
            \tl_new:c { \__xeCJK_special_punct_tl:nN {#1} {##1} }
            \seq_gput_right:cn { \__xeCJK_special_punct_seq:n {#1} } {##1}
          }
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_sub_special_punct:nn #1#2
  {
    \tl_map_inline:xn {#2}
      {
        \cs_undefine:c { \__xeCJK_special_punct_tl:nN {#1} {##1} }
        \seq_gremove_all:cn { \__xeCJK_special_punct_seq:n {#1} } {##1}
      }
  }
\prg_new_conditional:Npnn \__xeCJK_punct_if_right:N #1 { p , T , F , TF }
  {
    \if_int_compare:w \xeCJK_token_value_class:N #1 = \xeCJK_class_num:n { FullRight }
      \prg_return_true: \else: \prg_return_false: \fi:
  }
\clist_map_inline:Nn \g__xeCJK_special_punct_clist
  {
    \exp_args:Nc
    \prg_new_conditional:Npnn { __xeCJK_punct_if_#1:N } ##1 { p , T , F , TF }
      {
        \if_cs_exist:w \__xeCJK_special_punct_tl:nN {#1} {##1} \cs_end:
          \prg_return_true: \else: \prg_return_false: \fi:
      }
  }
\cs_new_nopar:Npn \__xeCJK_punct_dim_csname:nn #1#2
  { g__\l_xeCJK_current_font_tl/\l_xeCJK_punct_style_tl/#1/#2/tl }
\cs_new_nopar:Npn \__xeCJK_punct_dim_csname:nnn
  { \__xeCJK_punct_dim_csname:nnnn { \l_xeCJK_punct_style_tl } }
\cs_new_nopar:Npn \__xeCJK_punct_dim_csname:nnnn #1#2#3#4
  { g__\l_xeCJK_current_font_tl/#1/#2/#3/#4/tl }
\cs_new_nopar:Npn \__xeCJK_use_punct_dim:nn #1#2
  { \tl_use:c { \__xeCJK_punct_dim_csname:nn {#1} {#2} } }
\cs_new_nopar:Npn \__xeCJK_use_punct_dim:nnn #1#2#3
  { \tl_use:c { \__xeCJK_punct_dim_csname:nnn {#1} {#2} {#3} } }
\cs_new_protected_nopar:Npn \__xeCJK_gset_punct_dim:nnx #1#2#3
  { \tl_gset:cx { \__xeCJK_punct_dim_csname:nn {#1} {#2} } {#3} }
\cs_new_protected_nopar:Npn \__xeCJK_gset_punct_dim:nnnx #1#2#3#4
  { \tl_gset:cx { \__xeCJK_punct_dim_csname:nnn {#1} {#2} {#3} } {#4} }
\cs_new_protected_nopar:Npn \__xeCJK_gset_punct_dim:nnnnx #1#2#3#4#5
  { \tl_gset:cx { \__xeCJK_punct_dim_csname:nnnn {#1} {#2} {#3} {#4} } {#5} }
\DeclareObjectType { xeCJK / punctuation } { \c_three }
\DeclareTemplateInterface { xeCJK / punctuation } { basic } { \c_three }
  {
    enabled-global-setting  : boolean = true ,
    fixed-punct-width       : length  = \c_max_dim ,
    fixed-punct-ratio       : real    = \c_one_fp ,
    mixed-punct-width       : length  = \KeyValue { fixed-punct-width } ,
    mixed-punct-ratio       : real    = \KeyValue { fixed-punct-ratio } ,
    middle-punct-width      : length  = \KeyValue { fixed-punct-width } ,
    middle-punct-ratio      : real    = \KeyValue { fixed-punct-ratio } ,
    fixed-margin-width      : length  = \c_max_dim ,
    fixed-margin-ratio      : real    = \c_one_fp ,
    mixed-margin-width      : length  = \KeyValue { fixed-margin-width } ,
    mixed-margin-ratio      : real    = \KeyValue { fixed-margin-ratio } ,
    middle-margin-width     : length  = \KeyValue { fixed-margin-width } ,
    middle-margin-ratio     : real    = \KeyValue { fixed-margin-ratio } ,
    add-min-bound-to-margin : boolean = false ,
    optimize-margin         : boolean = false ,
    margin-minimum          : length  = \c_zero_dim ,
    enabled-kerning         : boolean = true ,
    min-bound-to-kerning    : boolean = false ,
    kerning-total-width     : length  = \c_max_dim ,
    kerning-total-ratio     : real    = 0.75 ,
    optimize-kerning        : boolean = false ,
    same-align-margin       : length  = \c_max_dim ,
    same-align-ratio        : real    = \c_zero_fp ,
    different-align-margin  : length  = \c_max_dim ,
    different-align-ratio   : real    = \c_zero_fp ,
    kerning-margin-width    : length  = \c_max_dim ,
    kerning-margin-ratio    : real    = \c_one_fp ,
    kerning-margin-minimum  : length  = \c_zero_dim
  }
\DeclareTemplateCode { xeCJK / punctuation } { basic } { \c_three }
  {
    enabled-global-setting  = \l__xeCJK_enabled_global_setting_bool ,
    fixed-punct-width       = \l__xeCJK_fixed_punct_width_dim ,
    fixed-punct-ratio       = \l__xeCJK_fixed_punct_ratio_fp ,
    mixed-punct-width       = \l__xeCJK_mixed_punct_width_dim ,
    mixed-punct-ratio       = \l__xeCJK_mixed_punct_ratio_fp ,
    middle-punct-width      = \l__xeCJK_middle_punct_width_dim ,
    middle-punct-ratio      = \l__xeCJK_middle_punct_ratio_fp ,
    fixed-margin-width      = \l__xeCJK_fixed_margin_width_dim ,
    fixed-margin-ratio      = \l__xeCJK_fixed_margin_ratio_fp ,
    mixed-margin-width      = \l__xeCJK_mixed_margin_width_dim ,
    mixed-margin-ratio      = \l__xeCJK_mixed_margin_ratio_fp ,
    middle-margin-width     = \l__xeCJK_middle_margin_width_dim ,
    middle-margin-ratio     = \l__xeCJK_middle_margin_ratio_fp ,
    add-min-bound-to-margin = \l__xeCJK_add_min_bound_to_margin_bool ,
    optimize-margin         = \l__xeCJK_optimize_margin_bool ,
    margin-minimum          = \l__xeCJK_margin_minimum_dim ,
    enabled-kerning         = \l__xeCJK_enabled_kerning_bool ,
    min-bound-to-kerning    = \l__xeCJK_min_bound_to_kerning_bool ,
    kerning-total-width     = \l__xeCJK_kerning_total_width_dim ,
    kerning-total-ratio     = \l__xeCJK_kerning_total_ratio_fp ,
    optimize-kerning        = \l__xeCJK_optimize_kerning_bool ,
    same-align-margin       = \l__xeCJK_same_align_margin_dim ,
    same-align-ratio        = \l__xeCJK_same_align_ratio_fp ,
    different-align-margin  = \l__xeCJK_different_align_margin_dim ,
    different-align-ratio   = \l__xeCJK_different_align_ratio_fp ,
    kerning-margin-width    = \l__xeCJK_kerning_margin_width_dim ,
    kerning-margin-ratio    = \l__xeCJK_kerning_margin_ratio_fp ,
    kerning-margin-minimum  = \l__xeCJK_kerning_margin_minimum_dim
  }
  {
    \AssignTemplateKeys
    \tl_if_blank:nTF {#3}
      { \xeCJK_punct_margin_process:NN {#1} {#2} }
      { \xeCJK_punct_kerning_process:NN {#2} {#3} }
  }
\cs_new_protected_nopar:Npn \xeCJK_punct_margin_process:NN #1#2
  {
    \tl_set:Nx \l__xeCJK_tmpa_tl { \__xeCJK_use_punct_dim:nnn { bound } {#1} {#2} }
    \tl_set:Nx \l__xeCJK_tmpb_tl
      {
        \__xeCJK_use_punct_dim:nnn { bound }
          { \xeCJK_reverse:nnn {#1} \c__xeCJK_left_tl \c__xeCJK_right_tl } {#2}
      }
    \dim_set:Nn \l__xeCJK_tmp_dim
      {
        \bool_if:NTF \l__xeCJK_enabled_global_setting_bool
          {
            \cs_if_exist_use:cTF { g__xeCJK_punct_width/#2/tl }
              { \use_none:n }
              {
                \xeCJK_if_blank_x:nTF \g__xeCJK_punct_width_tl
                  { \use:n }
                  { \g__xeCJK_punct_width_tl \use_none:n }
              }
          }
          { \use:n }
          {
            \__xeCJK_punct_if_middle:NTF {#2}
              { \__xeCJK_punct_width_or_ratio:nN { middle } {#2} }
              {
                \__xeCJK_punct_if_mixed_width:NTF {#2}
                  { \__xeCJK_punct_width_or_ratio:nN { mixed } {#2} }
                  { \__xeCJK_punct_width_or_ratio:nN { fixed } {#2} }
              }
          }
      }
    \__xeCJK_gset_punct_dim:nnnx { glue } {#1} {#2}
      {
        \dim_max:nn
          { \l__xeCJK_margin_minimum_dim }
          {
            \dim_compare:nNnTF \l__xeCJK_tmp_dim < \c_max_dim
              {
                \__xeCJK_punct_if_middle:NTF {#2}
                  {
                    (
                      \l__xeCJK_tmp_dim - ( \__xeCJK_use_punct_dim:nn { dimen } {#2} )
                    ) / \c_two
                  }
                  {
                    \bool_if:NTF \l__xeCJK_optimize_margin_bool
                      { \dim_max:nn { \dim_min:nn \l__xeCJK_tmpa_tl \l__xeCJK_tmpb_tl } }
                      { \use:n }
                      {
                        \l__xeCJK_tmp_dim - ( \l__xeCJK_tmpb_tl )
                        - ( \__xeCJK_use_punct_dim:nn { dimen } {#2} )
                      }
                  }
              }
              {
                \bool_if:NTF \l__xeCJK_optimize_margin_bool
                  { \dim_min:nn { \l__xeCJK_tmpa_tl } }
                  { \use:n }
                  {
                    \__xeCJK_punct_if_middle:NTF {#2}
                      {
                        \dim_compare:nNnTF \l__xeCJK_middle_margin_width_dim < \c_max_dim
                          { \l__xeCJK_middle_margin_width_dim }
                          {
                            \fp_use:N \l__xeCJK_middle_margin_ratio_fp
                            \etex_dimexpr:D
                              ( \l__xeCJK_tmpa_tl + \l__xeCJK_tmpb_tl ) / \c_two
                            \scan_stop:
                          }
                      }
                      {
                        \__xeCJK_punct_if_mixed_width:NTF {#2}
                          { \__xeCJK_margin_width_or_ratio:n { mixed } }
                          { \__xeCJK_margin_width_or_ratio:n { fixed } }
                      }
                  }
              }
          }
      }
  }
\cs_new_nopar:Npn \__xeCJK_punct_width_or_ratio:nN #1#2
  {
    \dim_compare:nNnTF { \use:c { l__xeCJK_#1_punct_width_dim } } < \c_max_dim
      { \use:c { l__xeCJK_#1_punct_width_dim } }
      {
        \fp_compare:nNnTF { \use:c { l__xeCJK_#1_punct_ratio_fp } } = \c_zero_fp
          { \c_max_dim }
          {
            \fp_use:c { l__xeCJK_#1_punct_ratio_fp }
            \etex_dimexpr:D \__xeCJK_use_punct_dim:nn { width } {#2} \scan_stop:
          }
      }
  }
\cs_new_nopar:Npn \__xeCJK_margin_width_or_ratio:n #1
  {
    \dim_compare:nNnTF { \use:c { l__xeCJK_#1_margin_width_dim } } < \c_max_dim
      { \use:c { l__xeCJK_#1_margin_width_dim } }
      {
        \fp_use:c { l__xeCJK_#1_margin_ratio_fp }
        \etex_dimexpr:D \l__xeCJK_tmpa_tl \scan_stop:
      }
    \bool_if:NT \l__xeCJK_add_min_bound_to_margin_bool
      { + \dim_min:nn \l__xeCJK_tmpa_tl \l__xeCJK_tmpb_tl }
  }
\cs_new_protected_nopar:Npn \xeCJK_punct_kerning_process:NN #1#2
  {
    \__xeCJK_gset_punct_dim:nnnx { kern } {#1} {#2}
      {
        \dim_eval:n
          {
            \bool_if:nTF
              {
                \l__xeCJK_enabled_global_setting_bool &&
                \tl_if_exist_p:c { g__xeCJK_punct/kern/#1/#2/tl }
              }
              { \tl_use:c { g__xeCJK_punct/kern/#1/#2/tl } }
              {
                \bool_if:NTF \l__xeCJK_enabled_kerning_bool
                  { \__xeCJK_calc_kerning_margin:NN {#1} {#2} }
                  { \__xeCJK_original_kerning_margin:NN {#1} {#2} }
              }
            - ( \__xeCJK_use_punct_dim:nnn { bound } \c__xeCJK_right_tl {#1} )
            - ( \__xeCJK_use_punct_dim:nnn { bound } \c__xeCJK_left_tl  {#2} )
          }
      }
  }
\cs_new_nopar:Npn \__xeCJK_original_kerning_margin:NN #1#2
  {
    \dim_eval:n
      {
        \__xeCJK_use_punct_dim:nnn
          { \__xeCJK_punct_if_right:NTF {#1} { glue } { bound } }
          { \c__xeCJK_right_tl } {#1} +
        \__xeCJK_use_punct_dim:nnn
          { \__xeCJK_punct_if_right:NTF {#2} { bound } { glue } }
          { \c__xeCJK_left_tl  } {#2}
      }
  }
\cs_new_nopar:Npn \__xeCJK_calc_kerning_margin:NN #1#2
  {
    \dim_max:nn
      { \l__xeCJK_kerning_margin_minimum_dim }
      {
        \bool_if:NTF \l__xeCJK_min_bound_to_kerning_bool
          { \__xeCJK_punct_min_bound:NN  {#1} {#2} }
          {
            \bool_if:NTF \l__xeCJK_optimize_kerning_bool
              { \dim_max:nn { \__xeCJK_punct_min_bound:NN  {#1} {#2} } }
              { \use:n }
              {
                \dim_compare:nNnTF \l__xeCJK_kerning_total_width_dim < \c_max_dim
                  { \__xeCJK_calc_kerning_margin:nNN \l__xeCJK_kerning_total_width_dim }
                  {
                    \fp_compare:nNnTF \l__xeCJK_kerning_total_ratio_fp = \c_zero_fp
                      {
                        \xeCJK_if_same_class:NNTF {#1} {#2}
                          { \__xeCJK_kerning_width_or_ratio:nNN { same } }
                          { \__xeCJK_kerning_width_or_ratio:nNN { different } }
                      }
                      {
                        \__xeCJK_calc_kerning_margin:nNN
                          {
                            \fp_use:N \l__xeCJK_kerning_total_ratio_fp
                            \etex_dimexpr:D
                              \__xeCJK_use_punct_dim:nn { width } {#1} +
                              \__xeCJK_use_punct_dim:nn { width } {#2}
                            \scan_stop:
                          }
                      }
                  }
                  {#1} {#2}
              }
          }
      }
  }
\cs_new_nopar:Npn \__xeCJK_kerning_width_or_ratio:nNN #1#2#3
  {
    \dim_compare:nNnTF { \use:c { l__xeCJK_#1_align_margin_dim } } < \c_max_dim
      { \use:c { l__xeCJK_#1_align_margin_dim } \use_none:nn }
      {
        \fp_compare:nNnTF { \use:c { l__xeCJK_#1_align_ratio_fp } } = \c_zero_fp
          { \use:n }
          { \fp_use:c { l__xeCJK_#1_align_ratio_fp } \use_ii:nn }
      }
      {
        \dim_compare:nNnTF \l__xeCJK_kerning_margin_width_dim < \c_max_dim
          { \l__xeCJK_kerning_margin_width_dim \use_none:n }
          { \fp_use:N \l__xeCJK_kerning_margin_ratio_fp \use:n }
      }
      { \etex_dimexpr:D \__xeCJK_original_kerning_margin:NN {#2} {#3} \scan_stop: }
  }
\cs_new_nopar:Npn \__xeCJK_punct_min_bound:NN #1#2
  {
    \dim_max:nn
      {
        \dim_min:nn
          { \__xeCJK_use_punct_dim:nnn { bound } \c__xeCJK_left_tl  {#1} }
          { \__xeCJK_use_punct_dim:nnn { bound } \c__xeCJK_right_tl {#1} }
      }
      {
        \dim_min:nn
          { \__xeCJK_use_punct_dim:nnn { bound } \c__xeCJK_left_tl  {#2} }
          { \__xeCJK_use_punct_dim:nnn { bound } \c__xeCJK_right_tl {#2} }
      }
  }
\cs_new_nopar:Npn \__xeCJK_calc_kerning_margin:nNN #1#2#3
  {
    \dim_eval:n
      {
        (#1)
        - ( \__xeCJK_use_punct_dim:nnn
              { \__xeCJK_punct_if_right:NTF {#2} { bound } { glue } }
              { \c__xeCJK_left_tl } {#2} )
        - ( \__xeCJK_use_punct_dim:nnn
              { \__xeCJK_punct_if_right:NTF {#3} { glue } { bound } }
              { \c__xeCJK_right_tl } {#3} )
        - ( \__xeCJK_use_punct_dim:nn { dimen } {#2} )
        - ( \__xeCJK_use_punct_dim:nn { dimen } {#3} )
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_get_punct_bounds:NN #1#2
  {
    \tl_if_exist:cF { \__xeCJK_punct_dim_csname:nnn { glue } {#1} {#2} }
      {
        \tl_if_eq:NNTF \l_xeCJK_punct_style_tl \c__xeCJK_punct_style_plain_tl
          {
            \__xeCJK_gset_punct_dim:nnnx { glue } {#1} {#2} { \c_zero_dim }
            \__xeCJK_gset_punct_dim:nnnx { bound } \c__xeCJK_left_tl  {#2} { \c_zero_dim }
            \__xeCJK_gset_punct_dim:nnnx { bound } \c__xeCJK_right_tl {#2} { \c_zero_dim }
          }
          {
            { \xeCJK_select_font: \xeCJK_calc_punct_dimen:f {#2} }
            \__xeCJK_punct_if_long:NTF {#2}
              { \__xeCJK_gset_punct_dim:nnnx { glue } {#1} {#2} { \c_zero_dim } }
              {
                \UseInstance { xeCJK / punctuation }
                  { \l_xeCJK_punct_style_tl } {#1} {#2} { }
              }
          }
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_calc_punct_dimen:N #1
  {
    \__xeCJK_gset_punct_dim:nnnx { bound } \c__xeCJK_left_tl {#1}
      { \xeCJK_glyph_bounds:NN \c_one {#1} }
    \__xeCJK_gset_punct_dim:nnnx { bound } \c__xeCJK_right_tl {#1}
      { \xeCJK_glyph_bounds:NN \c_three {#1} }
    \dim_set:Nn \l__xeCJK_tmp_dim
      {
        ( \__xeCJK_use_punct_dim:nnn { bound } \c__xeCJK_left_tl  {#1} ) +
        ( \__xeCJK_use_punct_dim:nnn { bound } \c__xeCJK_right_tl {#1} )
      }
    \__xeCJK_gset_punct_dim:nnx { width } {#1}
      { \dim_use:N \etex_fontcharwd:D \tex_font:D \xeCJK_token_value_charcode:N #1 }
    \__xeCJK_gset_punct_dim:nnx { dimen } {#1}
      { \dim_eval:n { \__xeCJK_use_punct_dim:nn { width } {#1} - \l__xeCJK_tmp_dim } }
    \__xeCJK_punct_if_long:NT {#1}
      {
        \seq_map_inline:Nn \g__xeCJK_punct_style_seq
          {
            \__xeCJK_gset_punct_dim:nnnnx {##1} { kern } {#1} {#1}
              {
                \bool_if:nTF
                  {
                    \str_if_eq_p:nn {#1} { ^^^^2025 } ||
                    \str_if_eq_p:nn {#1} { ^^^^2026 }
                  }
                  { \c_zero_dim }
                  { - \dim_use:N \l__xeCJK_tmp_dim }
              }
          }
      }
  }
\cs_generate_variant:Nn \xeCJK_calc_punct_dimen:N { f }
\cs_new_nopar:Npn \xeCJK_glyph_bounds:NN #1#2
  {
    \dim_use:N \XeTeXglyphbounds #1 ~
    \XeTeXcharglyph \xeCJK_token_value_charcode:N #2 \exp_stop_f:
  }
\cs_new_protected_nopar:Npn \xeCJK_get_punct_kerning:NN #1#2
  {
    \tl_if_exist:cF { \__xeCJK_punct_dim_csname:nnn { kern } {#1} {#2} }
      {
        \tl_if_eq:NNTF \l_xeCJK_punct_style_tl \c__xeCJK_punct_style_plain_tl
          { \__xeCJK_gset_punct_dim:nnnx { kern } {#1} {#2} { \c_zero_dim } }
          {
            \UseInstance { xeCJK / punctuation }
              { \l_xeCJK_punct_style_tl } { } {#1} {#2}
          }
      }
  }
\cs_generate_variant:Nn \xeCJK_get_punct_kerning:NN { o }
\keys_define:nn { xeCJK / options }
  {
    PunctStyle .choice: ,
    PunctStyle              .default:n = { quanjiao } ,
    PunctStyle / halfwidth     .meta:n = { PunctStyle = banjiao } ,
    PunctStyle / fullwidth     .meta:n = { PunctStyle = quanjiao } ,
    PunctStyle / mixedwidth    .meta:n = { PunctStyle = kaiming } ,
    PunctStyle / marginkerning .meta:n = { PunctStyle = hangmobanjiao } ,
    PunctStyle / plain         .code:n =
      { \tl_set_eq:NN \l_xeCJK_punct_style_tl \c__xeCJK_punct_style_plain_tl } ,
    PunctStyle / unknown       .code:n =
      {
        \IfInstanceExistTF { xeCJK / punctuation } { \l_keys_value_tl }
          { \tl_set:Nx \l_xeCJK_punct_style_tl { \l_keys_value_tl } }
          { \__xeCJK_error:nx { punct-style-unknown } { \l_keys_value_tl } }
      }
  }
\tl_const:Nn \c__xeCJK_punct_style_plain_tl { plain }
\__xeCJK_msg_new:nn { punct-style-unknown }
  {
    Punctuation~style~"#1"~is~unknown. \\\\
    The~available~styles~are~listed~as~follow.\\\\
    "plain,~\seq_use:Nnnn \g__xeCJK_punct_style_seq { ~and~ } { ,~ } { ,~and~ }".\\
  }
\NewDocumentCommand \xeCJKDeclarePunctStyle { > { \TrimSpaces } m m }
  {
    \IfInstanceExistTF { xeCJK / punctuation } {#1}
      { \__xeCJK_warning:nx { punct-style-already-defined } {#1} }
      { \seq_gput_right:Nn \g__xeCJK_punct_style_seq {#1} }
    \DeclareInstance { xeCJK / punctuation } {#1} { basic } {#2}
  }
\seq_new:N \g__xeCJK_punct_style_seq
\__xeCJK_msg_new:nn { punct-style-already-defined }
  {
    Punctuation~style~"#1"~is~already~defined!. \\\\
    The~existing~style~of~"#1"~will~be~overwritten.\\
  }
\@onlypreamble \xeCJKDeclarePunctStyle
\NewDocumentCommand \xeCJKEditPunctStyle { > { \TrimSpaces } m m }
  {
    \IfInstanceExistTF { xeCJK / punctuation } {#1}
      { \EditInstance { xeCJK / punctuation } {#1} {#2} }
      { \__xeCJK_error:nx { punct-style-unknown } {#1} }
  }
\@onlypreamble \xeCJKEditPunctStyle
\xeCJKDeclarePunctStyle { quanjiao } { }
\xeCJKDeclarePunctStyle { hangmobanjiao } { enabled-kerning = false }
\xeCJKDeclarePunctStyle { banjiao }
  {
    fixed-punct-ratio   = 0.5  ,
    optimize-margin     = true ,
    kerning-total-ratio = 0.5  ,
    optimize-kerning    = true
  }
\xeCJKDeclarePunctStyle { kaiming }
  {
    fixed-punct-ratio   = 0.5  ,
    mixed-punct-ratio   = 0.8  ,
    optimize-margin     = true ,
    kerning-total-ratio = 0.5  ,
    optimize-kerning    = true
  }
\xeCJKDeclarePunctStyle { CCT }
  {
    fixed-punct-ratio   = 0.7  ,
    optimize-margin     = true ,
    kerning-total-ratio = 0.6  ,
    optimize-kerning    = true
  }
\keys_define:nn { xeCJK / options }
  {
    AutoFallBack .choice: ,
    AutoFallBack / true  .code:n =
      {
        \cs_if_eq:NNF \CJKsymbol \xeCJK_fallback_test_glyph:N
          {
            \cs_set_eq:NN \__xeCJK_fallback_save_CJKsymbol:N \CJKsymbol
            \cs_set_eq:NN \CJKsymbol \xeCJK_fallback_test_glyph:N
          }
      } ,
    AutoFallBack / false .code:n =
      {
        \cs_if_eq:NNT \CJKsymbol \xeCJK_fallback_test_glyph:N
          { \cs_set_eq:NN \CJKsymbol \__xeCJK_fallback_save_CJKsymbol:N }
      } ,
    AutoFallBack      .default:n = { true } ,
    fallback             .meta:n = { AutoFallBack = true }
  }
\cs_new_protected_nopar:Npn \xeCJK_fallback_test_glyph:N #1
  {
    \xeCJK_glyph_if_exist:NTF {#1}
      { \__xeCJK_fallback_save_CJKsymbol:N {#1} }
      { { \xeCJK_fallback_loop:Nn {#1} { \l_xeCJK_family_tl/FallBack } } }
  }
\cs_new_protected_nopar:Npn \xeCJK_fallback_loop:Nn #1#2
  {
    \xeCJK_family_if_exist:xTF {#2}
      {
        \xeCJK_select_font:x {#2}
        \xeCJK_glyph_if_exist:NTF {#1}
          { \__xeCJK_fallback_save_CJKsymbol:N {#1} }
          { \xeCJK_fallback_loop:Nn {#1} { #2/FallBack } }
      }
      {
        \xeCJK_family_if_exist:xT { \l_xeCJK_family_tl/FallBack }
          { \__xeCJK_warning:nxx { fallback } {#1} {#2} }
        \__xeCJK_fallback_save_CJKsymbol:N {#1}
      }
  }
\__xeCJK_msg_new:nn { fallback }
  {
    CJKfamily~`#2'~
    ( \prop_get:No \g__xeCJK_family_font_name_prop {#2} )~
    does~not~contain~glyph~`#1'~(U+\int_to_hexadecimal:n {`#1}).\\
  }
\bool_new:N \l__xeCJK_fallback_first_bool
\cs_generate_variant:Nn \prop_get:Nn { No }
\NewDocumentCommand \setCJKfallbackfamilyfont { m O{} m }
  {
    \clist_set:Nx \l__xeCJK_tmpa_clist {#3}
    \int_compare:nNnTF { \clist_count:N \l__xeCJK_tmpa_clist } > \c_one
      { \xeCJK_set_family_fallback:xxN {#1} {#2} \l__xeCJK_tmpa_clist }
      { \xeCJK_set_family:xxx { #1/FallBack } {#2} {#3} }
  }
\cs_new_protected_nopar:Npn \xeCJK_set_family_fallback:nnN #1#2#3
  {
    \group_begin:
    \tl_set:Nn \l__xeCJK_fallback_family_tl {#1}
    \prop_get:NVNF \g__xeCJK_family_font_name_prop
      \l__xeCJK_fallback_family_tl \l__xeCJK_font_name_tl
      { \tl_clear:N \l__xeCJK_font_name_tl }
    \clist_map_inline:Nn #3
      {
        \tl_put_right:Nn \l__xeCJK_fallback_family_tl { /FallBack }
        \__xeCJK_get_sub_features:Vn \l__xeCJK_fallback_family_tl {##1}
        \clist_put_left:cn
          { l__xeCJK_ \l__xeCJK_fallback_family_tl _font_options_clist } {#2}
        \xeCJK_set_family:Vvv \l__xeCJK_fallback_family_tl
          { l__xeCJK_ \l__xeCJK_fallback_family_tl _font_options_clist }
          { l__xeCJK_ \l__xeCJK_fallback_family_tl _font_name_tl }
      }
    \group_end:
  }
\cs_generate_variant:Nn \xeCJK_set_family_fallback:nnN { xx }
\bool_new:N \g__xeCJK_auto_fake_bold_bool
\bool_new:N \g__xeCJK_auto_fake_slant_bool
\fp_new:N \g__xeCJK_embolden_factor_fp
\fp_new:N \g__xeCJK_slant_factor_fp
\keys_define:nn { xeCJK / options }
  {
    AutoFakeBold .choices:nn = { true , false }
      { \use:c { bool_gset_ \l_keys_choice_tl :N } \g__xeCJK_auto_fake_bold_bool } ,
    AutoFakeBold / unknown .code:n =
      {
        \bool_gset_true:N  \g__xeCJK_auto_fake_bold_bool
        \fp_gset:Nn \g__xeCJK_embolden_factor_fp { \l_keys_value_tl }
      } ,
    AutoFakeBold  .default:n  = { true } ,
    AutoFakeSlant .choices:nn = { true , false }
      { \use:c { bool_gset_ \l_keys_choice_tl :N } \g__xeCJK_auto_fake_slant_bool } ,
    AutoFakeSlant / unknown  .code:n =
      {
        \bool_gset_true:N  \g__xeCJK_auto_fake_slant_bool
        \fp_gset:Nn \g__xeCJK_slant_factor_fp { \l_keys_value_tl }
      } ,
    AutoFakeSlant  .default:n = { true } ,
    EmboldenFactor .fp_gset:N = \g__xeCJK_embolden_factor_fp ,
    SlantFactor    .fp_gset:N = \g__xeCJK_slant_factor_fp ,
    BoldFont  .meta:n = { AutoFakeBold  = true } ,
    boldfont  .meta:n = { AutoFakeBold  = true } ,
    SlantFont .meta:n = { AutoFakeSlant = true } ,
    slantfont .meta:n = { AutoFakeSlant = true }
  }
\seq_new:N \g__xeCJK_sub_key_seq
\cs_new_protected_nopar:Npn \xeCJK_new_sub_key:n #1
  {
    \seq_gput_right:Nn \g__xeCJK_sub_key_seq {#1}
    \keys_define:nn { xeCJK / features }
      {
        #1 .code:n =
          {
            \tl_if_blank:nTF {##1}
              {
                \bool_set_false:c { l__xeCJK_copy_#1_bool }
                \bool_set_false:c { l__xeCJK_add_#1_bool }
                \tl_put_right:Nn \l__xeCJK_family_name_tl { /#1 }
              }
              {
                \seq_put_right:Nn \l__xeCJK_sub_key_seq {#1}
                \str_if_eq: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 = { }
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_get_sub_features:nn #1#2
  {
    \tl_set:Nx \l__xeCJK_tmpa_tl { \xeCJK_tl_remove_outer_braces:n {#2} }
    \clist_clear:N \l__xeCJK_sub_font_options_clist
    \tl_if_head_eq_meaning:VNTF \l__xeCJK_tmpa_tl [ % ]
      {
        \exp_after:wN \__xeCJK_get_sub_features:wn \l__xeCJK_tmpa_tl \c_empty_tl
        \tl_if_blank:VT \l__xeCJK_sub_font_name_tl
          {
            \tl_set_eq:NN \l__xeCJK_sub_font_name_tl \l__xeCJK_tmpa_tl
            \clist_clear:N \l__xeCJK_sub_font_options_clist
          }
      }
      { \tl_set_eq:NN \l__xeCJK_sub_font_name_tl \l__xeCJK_tmpa_tl }
    \tl_if_blank:VTF \l__xeCJK_sub_font_name_tl
      { \tl_set_eq:NN \l__xeCJK_sub_font_name_tl \l__xeCJK_font_name_tl }
      { \tl_replace_all:NnV \l__xeCJK_sub_font_name_tl { * } \l__xeCJK_font_name_tl }
    \clist_set_eq:cN { l__xeCJK_#1_font_options_clist } \l__xeCJK_sub_font_options_clist
    \tl_set_eq:cN { l__xeCJK_#1_font_name_tl } \l__xeCJK_sub_font_name_tl
  }
\cs_new_protected_nopar:Npn \__xeCJK_get_sub_features:wn [#1] #2
  {
    \clist_set:Nn \l__xeCJK_sub_font_options_clist {#1}
    \str_if_eq:nnTF {#2} { \c_empty_tl }
      { \tl_set_eq:NN \l__xeCJK_sub_font_name_tl \c_empty_tl }
      { \tl_set:Nn \l__xeCJK_sub_font_name_tl {#2} }
  }
\cs_generate_variant:Nn \__xeCJK_get_sub_features:nn { V }
\cs_generate_variant:Nn \tl_if_head_eq_meaning:nNTF { V }
\cs_generate_variant:Nn \tl_replace_all:Nnn { NnV }
\xeCJK_new_sub_key:n { FallBack }
\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:c = { l__xeCJK_font_name_#1_tl } ,
        #2Features .clist_set:c = { l__xeCJK_font_feat_#1_clist }
      }
  }
\keys_define:nn { xeCJK / features }
  {
    AutoFakeBold  .choice: ,
    AutoFakeBold / false   .code:n =
      { \bool_set_false:N \l__xeCJK_auto_fake_bold_bool } ,
    AutoFakeBold / unknown .code:n =
      {
        \bool_set_true:N \l__xeCJK_auto_fake_bold_bool
        \fp_set:Nn \l__xeCJK_embolden_factor_fp { \l_keys_value_tl }
      } ,
    AutoFakeBold .default:n  = { \g__xeCJK_embolden_factor_fp } ,
    AutoFakeSlant  .choice: ,
    AutoFakeSlant / false   .code:n =
      { \bool_set_false:N \l__xeCJK_auto_fake_slant_bool } ,
    AutoFakeSlant / unknown .code:n =
      {
        \bool_set_true:N \l__xeCJK_auto_fake_slant_bool
        \fp_set:Nn \l__xeCJK_slant_factor_fp { \l_keys_value_tl }
      } ,
    AutoFakeSlant .default:n  = { \g__xeCJK_slant_factor_fp }
  }
\cs_new_protected_nopar:Npn \__xeCJK_set_family_initial:
  {
    \int_gincr:N \g__xeCJK_family_int
    \prop_clear:N \l__xeCJK_add_font_prop
    \prop_map_inline:Nn \g__xeCJK_features_id_prop
      {
        \tl_clear:c { l__xeCJK_font_name_##1_tl }
        \clist_clear:c { l__xeCJK_font_feat_##1_clist }
      }
    \clist_clear:N \l__xeCJK_fontspec_options_clist
    \seq_clear:N \l__xeCJK_sub_key_seq
    \seq_map_inline:Nn \g__xeCJK_sub_key_seq
      {
        \bool_set_false:c { l__xeCJK_copy_##1_bool }
        \bool_set_false:c { l__xeCJK_add_##1_bool  }
      }
    \bool_set_eq:NN \l__xeCJK_auto_fake_bold_bool   \g__xeCJK_auto_fake_bold_bool
    \bool_set_eq:NN \l__xeCJK_auto_fake_slant_bool  \g__xeCJK_auto_fake_slant_bool
    \fp_set_eq:NN \l__xeCJK_embolden_factor_fp \g__xeCJK_embolden_factor_fp
    \fp_set_eq:NN \l__xeCJK_slant_factor_fp    \g__xeCJK_slant_factor_fp
  }
\int_new:N \g__xeCJK_family_int
\cs_new_protected_nopar:Npn \xeCJK_set_family:nnn #1#2#3
  {
    \group_begin:
    \__xeCJK_set_family_initial:
    \tl_set:Nn \l__xeCJK_family_name_tl {#1}
    \clist_set:Nn \l__xeCJK_font_options_clist {#2}
    \tl_set:Nn \l__xeCJK_font_name_tl {#3}
    \clist_concat:NNN \l__xeCJK_font_features_clist
      \g__xeCJK_default_features_clist \l__xeCJK_font_options_clist
    \__xeCJK_remove_duplicate_keys:N \l__xeCJK_font_features_clist
    \keys_set_known:nVN { xeCJK / features }
      \l__xeCJK_font_features_clist \l__xeCJK_fontspec_options_clist
    \__xeCJK_parse_features:
    \__xeCJK_pass_features:
    \__xeCJK_check_family:V \l__xeCJK_family_name_tl
    \__xeCJK_gset_family_cs:x { \l__xeCJK_family_name_tl }
    \__xeCJK_save_family_info:
    \__xeCJK_set_sub_block_family:
    \group_end:
  }
\cs_generate_variant:Nn \xeCJK_set_family:nnn { Vnn , xxx , Vvv }
\cs_new_protected_nopar:Npn \__xeCJK_remove_duplicate_keys:N #1
  {
    \prop_clear:N \l__xeCJK_tmp_prop
    \keyval_parse:NNV \__xeCJK_prop_put_aux:n \__xeCJK_prop_put_aux:nn #1
    \clist_clear:N #1
    \prop_map_inline:Nn \l__xeCJK_tmp_prop
      {
        \tl_if_blank:nTF {##2}
          { \clist_put_right:Nn #1 {##1} }
          { \clist_put_right:Nn #1 { ##1 = {##2} } }
      }
  }
\cs_generate_variant:Nn \keyval_parse:NNn { NNV }
\cs_new_protected_nopar:Npn \__xeCJK_prop_put_aux:n #1
  { \prop_put:Nnn \l__xeCJK_tmp_prop {#1} { } }
\cs_new_protected_nopar:Npn \__xeCJK_prop_put_aux:nn #1#2
  { \prop_put:Nnn \l__xeCJK_tmp_prop {#1} {#2} }
\cs_new_protected_nopar:Npn \__xeCJK_gset_family_cs:x #1
  {
    \cs_gset_protected_nopar:cpx { \__xeCJK_family_csname:n {#1} }
      {
        \group_begin:
        \exp_not:n { \cs_set_eq:NN \__xeCJK_update_family:n \use_none:n }
        \exp_not:n { \fontspec_set_family:Nnn \l__xeCJK_fontspec_family_tl }
          { \exp_not:V \l__xeCJK_fontspec_options_clist }
          { \exp_not:V \l__xeCJK_font_name_tl }
        \__xeCJK_gset_family_nfss_cs:xx {#1} { \exp_not:N \l__xeCJK_fontspec_family_tl }
        \group_end:
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_check_family:n #1
  {
    \prop_get:NnNT \g__xeCJK_family_font_name_prop {#1} \l__xeCJK_tmpa_tl
      {
        \prop_gpop:NnNT \g__xeCJK_family_name_prop {#1} \l__xeCJK_tmpa_tl
          { \cs_undefine:c { \__xeCJK_family_nfss_csname:n {#1} } }
        \__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~`\__xeCJK_msg_family_map:n {#1}'~(#2). }
\cs_new_protected_nopar:Npn \__xeCJK_add_font:nn #1#2
  { \prop_put:Nnn \l__xeCJK_add_font_prop { #1 Font } {#2} }
\cs_new_protected_nopar:Npn \__xeCJK_add_font_if_new:nn #1#2
  { \prop_put_if_new:Nnn \l__xeCJK_add_font_prop { #1 Font } {#2} }
\cs_generate_variant:Nn \__xeCJK_add_font:nn        { nx , nV , nv }
\cs_generate_variant:Nn \__xeCJK_add_font_if_new:nn { nx , nV , nv }
\cs_new_protected_nopar:Npn \__xeCJK_add_fake_bold:n #1
  {
    \clist_put_left:cx { l__xeCJK_font_feat_#1_clist }
      { FakeBold = { \fp_use:N \l__xeCJK_embolden_factor_fp } }
  }
\cs_new_protected_nopar:Npn \__xeCJK_add_fake_slant:n #1
  {
    \clist_put_left:cx { l__xeCJK_font_feat_#1_clist }
      { FakeSlant = { \fp_use:N \l__xeCJK_slant_factor_fp } }
  }
\cs_new_protected_nopar:Npn \__xeCJK_parse_features:
  { \prop_map_function:NN \g__xeCJK_features_id_prop \__xeCJK_parse_features:nn }
\cs_new_protected_nopar:Npn \__xeCJK_parse_features:nn #1#2
  {
    \__xeCJK_if_font_select:nTF {#1}
      {
        \__xeCJK_add_font:nv {#2} { l__xeCJK_font_name_#1_tl }
        \__xeCJK_if_it_or_sl:nTF {#1}
          {
            \__xeCJK_if_font_select:nF { bf #1 }
              { \__xeCJK_add_font_if_new:nv {#2} { l__xeCJK_font_name_#1_tl }  }
          }
          {
            \str_if_eq:nnT {#1} { bf }
              {
                \__xeCJK_if_font_select:nF { bfit }
                  { \__xeCJK_add_font:nV { BoldItalic } \l__xeCJK_font_name_bf_tl }
                \__xeCJK_if_font_select:nF { bfsl }
                  { \__xeCJK_add_font:nV { BoldSlanted } \l__xeCJK_font_name_bf_tl }
              }
          }
      }
      { \__xeCJK_set_fake_font:nn {#1} {#2} }
  }
\prg_new_conditional:Npnn \__xeCJK_if_font_select:n #1 { p , T , F , TF }
  {
    \tl_if_blank:vTF { l__xeCJK_font_name_#1_tl }
      { \prg_return_false: } { \prg_return_true: }
  }
\prg_new_conditional:Npnn \__xeCJK_if_it_or_sl:n #1 { p , T , F , TF }
  {
    \if_predicate:w
      \bool_if_p:n { \str_if_eq_p:nn { it } {#1} || \str_if_eq_p:nn { sl } {#1} }
      \prg_return_true: \else: \prg_return_false: \fi:
  }
\cs_generate_variant:Nn \tl_if_blank:nTF { v }
\cs_new_protected_nopar:Npn \__xeCJK_set_fake_font:nn #1#2
  {
    \str_if_eq:nnTF {#1} { bf }
      { \bool_if:NT \l__xeCJK_auto_fake_bold_bool { \__xeCJK_add_fake_bold:n {#1} } }
      {
        \bool_if:NTF \l__xeCJK_auto_fake_slant_bool
          {
            \bool_if:nT
              {    \__xeCJK_if_it_or_sl_p:n {#1}
                || ( \str_if_eq_p:nn {#1} { bfit }
                     && ! ( \__xeCJK_if_font_select_p:n { it } ) )
                || ( \str_if_eq_p:nn {#1} { bfsl }
                     && ! ( \__xeCJK_if_font_select_p:n { sl } ) )
              }
              { \__xeCJK_add_fake_slant:n {#1} }
          }
          { \__xeCJK_if_it_or_sl:nT {#1} { \__xeCJK_map_it_sl:nn {#1} {#2} } }
        \bool_if:nT
          {      \l__xeCJK_auto_fake_bold_bool
            && ! ( \__xeCJK_if_it_or_sl_p:n {#1} )
            && ! ( \__xeCJK_if_font_select_p:n { bf } )
          }
          { \__xeCJK_add_fake_bold:n {#1} }
      }
    \__xeCJK_add_font_if_new:nn {#2} { * }
  }
\cs_new_protected_nopar:Npn \__xeCJK_map_it_sl:nn #1#2
  {
    \__xeCJK_if_map_font_select:nT {#1}
      {
        \__xeCJK_add_font:nx {#2} { \__xeCJK_get_map_font:n {#1} }
        \__xeCJK_if_font_select:nF { bf #1 }
          { \__xeCJK_add_font_if_new:nx { Bold #2 } { \__xeCJK_get_map_font:n {#1} } }
      }
  }
\cs_new_nopar:Npn \__xeCJK_get_map_font:n #1
  { \exp_not:v { l__xeCJK_font_name_ \xeCJK_reverse:nnn {#1} { it } { sl } _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_font_feat_##1_clist }
          {
            \clist_put_right:Nx \l__xeCJK_fontspec_options_clist
              { ##2Features = { \exp_not:v { l__xeCJK_font_feat_##1_clist } } }
          }
      }
    \prop_map_inline:Nn \l__xeCJK_add_font_prop
      { \clist_put_right:Nn \l__xeCJK_fontspec_options_clist { ##1 = {##2} } }
  }
\prop_new:N \g__xeCJK_family_name_prop
\prop_new:N \g__xeCJK_family_font_name_prop
\prop_new:N \g__xeCJK_family_font_options_prop
\cs_new_protected_nopar:Npn \__xeCJK_save_family_info:
  {
    \group_begin:
    \seq_map_inline:Nn \g__xeCJK_CJK_sub_class_seq
      { \clist_remove_all:Nn \l__xeCJK_font_options_clist {##1} }
    \prop_gput:NVV \g__xeCJK_family_font_name_prop
      \l__xeCJK_family_name_tl \l__xeCJK_font_name_tl
    \prop_gput:NVV \g__xeCJK_family_font_options_prop
      \l__xeCJK_family_name_tl \l__xeCJK_font_options_clist
    \group_end:
  }
\cs_new_protected_nopar:Npn \__xeCJK_set_sub_block_family:
  {
    \seq_map_inline:Nn \l__xeCJK_sub_key_seq
      {
        \tl_set:Nx \l__xeCJK_sub_family_tl { \l__xeCJK_family_name_tl/##1 }
        \bool_if:cT { l__xeCJK_copy_##1_bool } { \__xeCJK_copy_sub_family:n {##1} }
        \bool_if:cT { l__xeCJK_add_##1_bool }
          {
            \xeCJK_set_family:Vvv \l__xeCJK_sub_family_tl
              { l__xeCJK_##1_font_options_clist } { l__xeCJK_##1_font_name_tl }
          }
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_copy_sub_family:n #1
  {
    \__xeCJK_check_family:V \l__xeCJK_sub_family_tl
    \prop_get:NVNT \g__xeCJK_family_font_name_prop
      \l__xeCJK_family_name_tl \l__xeCJK_tmpa_tl
      {
        \prop_gput:NVV \g__xeCJK_family_font_name_prop
          \l__xeCJK_sub_family_tl \l__xeCJK_tmpa_tl
      }
    \prop_get:NVNT \g__xeCJK_family_font_options_prop
      \l__xeCJK_family_name_tl \l__xeCJK_tmpa_clist
      {
        \clist_remove_all:Nn \l__xeCJK_tmpa_clist { #1 = * }
        \prop_gput:NVV \g__xeCJK_family_font_options_prop
          \l__xeCJK_sub_family_tl \l__xeCJK_tmpa_clist
      }
    \cs_gset_protected_nopar:cpx { \__xeCJK_family_csname:n { \l__xeCJK_sub_family_tl } }
      {
        \xeCJK_family_if_exist:xT { \l__xeCJK_family_name_tl }
          {
            \prop_get:NnNT \exp_not:N \g__xeCJK_family_name_prop
              { \l__xeCJK_family_name_tl } \exp_not:N \l__xeCJK_tmpa_tl
              {
                \__xeCJK_gset_family_nfss_cs:xx
                  { \l__xeCJK_sub_family_tl } { \exp_not:N \l__xeCJK_tmpa_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_name_prop
            \g__xeCJK_family_font_name_prop
            \g__xeCJK_family_font_options_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_nfss_csname:n {#1} }
          { \__xeCJK_family_nfss_csname:n {#2} }
      }
  }
\cs_generate_variant:Nn \__xeCJK_copy_family:nn { xx }
\tl_new:N \l_xeCJK_current_font_tl
\tl_set:Nn \l_xeCJK_current_font_tl { \__xeCJK_font_csname:n { \l_xeCJK_family_tl } }
\cs_new_nopar:Npn \__xeCJK_font_csname:n #1 { xeCJK/#1/\f@series/\f@shape/\f@size }
\cs_new_protected_nopar:Npn \xeCJK_select_font:
  {
    \cs_if_exist_use:cF { \l_xeCJK_current_font_tl }
      {
        \tl_set:Nx \l__xeCJK_current_coor_tl { \l_xeCJK_current_font_tl }
        \__xeCJK_family_use:x { \l_xeCJK_family_tl }
        \xeCJK_font_gset_to_current:c { \l__xeCJK_current_coor_tl }
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_select_font:x #1
  {
    \cs_if_exist_use:cF { \__xeCJK_font_csname:n {#1} }
      {
        \tl_set:Nx \l__xeCJK_current_coor_tl { \__xeCJK_font_csname:n {#1} }
        \__xeCJK_family_use:x {#1}
        \xeCJK_font_gset_to_current:c { \l__xeCJK_current_coor_tl }
      }
  }
\cs_new_eq:NN \xeCJK@setfont \xeCJK_select_font:
\cs_new_protected_nopar:Npn \__xeCJK_switch_font:nn #1#2
  {
    \str_if_eq:nnF {#1} {#2}
      {
        \__xeCJK_info:nxx { CJK-block } {#1} {#2}
        \str_if_eq:nnTF {#2} { CJK }
          { \xeCJK_select_font: }
          { \__xeCJK_block_select_font:n {#2} }
      }
  }
\__xeCJK_msg_new:nn { CJK-block } { Switch~from~block~`#1'~to~`#2'. }
\cs_new_protected_nopar:Npn \__xeCJK_block_select_font:n #1
  {
    \cs_if_exist_use:cF { \__xeCJK_font_csname:n { \l_xeCJK_family_tl/#1 } }
      {
        \tl_set:Nx \l__xeCJK_current_coor_tl
          { \__xeCJK_font_csname:n { \l_xeCJK_family_tl/#1 } }
        \xeCJK_family_if_exist:xF { \l_xeCJK_family_tl/#1 }
          {
            \__xeCJK_copy_family:xx { \l_xeCJK_family_tl/#1 }
              {
                \cs_if_exist:cTF
                  { \__xeCJK_family_csname:n { \CJKfamilydefault/#1 } }
                  { \CJKfamilydefault/#1 } { \l_xeCJK_family_tl }
              }
          }
        \__xeCJK_family_use:x { \l_xeCJK_family_tl/#1 }
        \xeCJK_font_gset_to_current:c { \l__xeCJK_current_coor_tl }
      }
  }
\cs_new_nopar:Npn \__xeCJK_family_csname:n #1 { xeCJK/family/#1 }
\cs_new_nopar:Npn \__xeCJK_family_nfss_csname:n #1 { xeCJK/family/nfss/#1 }
\cs_new_nopar:Npn \__xeCJK_family_use:x #1 { \use:c { \__xeCJK_family_nfss_csname:n {#1} } }
\cs_new_protected_nopar:Npn \__xeCJK_gset_family_nfss_cs:xx #1#2
  {
    \prop_gput:Nxx \g__xeCJK_family_name_prop {#1} {#2}
    \cs_gset_protected_nopar:cpx { \__xeCJK_family_nfss_csname:n {#1} }
      {
        \tl_set:Nx \exp_not:N \f@encoding { \c__xeCJK_encoding_tl }
        \tl_set:Nx \exp_not:N \f@family {#2}
        \exp_not:N \selectfont
      }
  }
\cs_generate_variant:Nn \prop_gput:Nnn { Nxx }
\prg_new_protected_conditional:Npnn \xeCJK_family_if_exist:x #1 { T , F , TF }
  {
    \cs_if_exist:cTF { \__xeCJK_family_nfss_csname:n {#1} }
      { \use_i:nn }
      { \cs_if_exist_use:cTF { \__xeCJK_family_csname:n {#1} } }
      { \prg_return_true: } { \prg_return_false: }
  }
\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} { \__xeCJK_family_use:x {#3} }
              }
              { \__xeCJK_family_unknown_warning:x {#3} }
          }
      }
    \tex_ignorespaces:D
  }
\tl_new:N \l_xeCJK_family_tl
\tl_set:Nn \l_xeCJK_family_tl { \CJKfamilydefault }
\cs_new_protected_nopar:Npn \__xeCJK_gobble_CJKfamily:
  { \cs_set_eq:NN \CJKfamily \__xeCJK_gobble_CJKfamily:wn }
\DeclareExpandableDocumentCommand \__xeCJK_gobble_CJKfamily:wn { t+ t- m } {  }
\cs_new_protected_nopar:Npn \xeCJK_family_if_exist_use:x #1
  {
    \xeCJK_family_if_exist:xTF {#1}
      { \__xeCJK_family_use:x {#1} }
      { \__xeCJK_family_unknown_warning:x {#1} }
  }
\cs_new_protected_nopar:Npn \__xeCJK_family_unknown_warning:n #1
  {
    \prop_if_empty:NF \g__xeCJK_family_font_name_prop
      {
        \seq_if_in:NnF \g__xeCJK_unknown_family_seq {#1}
          {
            \seq_gput_right:Nn \g__xeCJK_unknown_family_seq {#1}
            \__xeCJK_warning:nx { CJKfamily-Unknown } {#1}
          }
      }
  }
\cs_generate_variant:Nn \__xeCJK_family_unknown_warning:n { x }
\seq_new:N \g__xeCJK_unknown_family_seq
\__xeCJK_msg_new:nn { CJKfamily-Unknown }
  {
    Unknown~CJK~family~`\__xeCJK_msg_family_map:n {#1}'~is~being~ignored.\\\\
    Try~to~use~`\__xeCJK_msg_def_family_map:n {#1}'~to~define~it.
  }
\cs_new_nopar:Npn \__xeCJK_msg_def_family_map:n #1
  {
    \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} }
    [...]{...}
  }
\cs_new_nopar:Npn \__xeCJK_msg_family_map:n #1
  {
    \str_case_x:nnn {#1}
      {
        \CJKrmdefault { \token_to_str:N \CJKrmdefault }
        \CJKsfdefault { \token_to_str:N \CJKsfdefault }
        \CJKttdefault { \token_to_str:N \CJKttdefault }
      }
      {#1}
  }
\NewDocumentCommand \setCJKmainfont { O{} m }
  { \xeCJK_set_family:xxx { \CJKrmdefault } {#1} {#2} }
\cs_new_eq:NN \setCJKromanfont \setCJKmainfont
\NewDocumentCommand \setCJKsansfont { O{} m }
  { \xeCJK_set_family:xxx { \CJKsfdefault } {#1} {#2} }
\NewDocumentCommand \setCJKmonofont { O{} m }
  { \xeCJK_set_family:xxx { \CJKttdefault } {#1} {#2} }
\@onlypreamble \setCJKmainfont
\@onlypreamble \setCJKmathfont
\@onlypreamble \setCJKsansfont
\@onlypreamble \setCJKmonofont
\@onlypreamble \setCJKromanfont
\NewDocumentCommand \setCJKfamilyfont { m O{} m }
  { \xeCJK_set_family:xxx {#1} {#2} {#3} }
\NewDocumentCommand \newCJKfontfamily { o m O{} m }
  {
    \tl_set:Nx \l__xeCJK_tmpa_tl { \IfNoValueTF {#1} { \cs_to_str:N #2 } {#1} }
    \cs_new_protected_nopar:Npx #2 { \CJKfamily { \l__xeCJK_tmpa_tl } }
    \xeCJK_set_family:xxx { \l__xeCJK_tmpa_tl } {#3} {#4}
  }
\NewDocumentCommand \CJKfontspec { O{} m }
  {
    \xeCJK_fontspec:xx {#1} {#2}
    \tex_ignorespaces:D
  }
\cs_new_protected_nopar:Npn \xeCJK_fontspec:nn #1#2
  {
    \tl_set:Nx \l__xeCJK_tmpa_tl { \tl_to_str:n { CJKfontspec/#1/#2/id } }
    \tl_if_exist:cF { \l__xeCJK_tmpa_tl }
      {
        \tl_set:Nx \l__xeCJK_tmpb_tl
          { CJKfontspec ( \int_eval:n { \g__xeCJK_family_int + \c_one } ) }
        \tl_gset_eq:cN { \l__xeCJK_tmpa_tl } \l__xeCJK_tmpb_tl
        \xeCJK_set_family:Vnn \l__xeCJK_tmpb_tl {#1} {#2}
      }
    \exp_args:Nc \CJKfamily { \l__xeCJK_tmpa_tl }
  }
\cs_generate_variant:Nn \xeCJK_fontspec:nn { VV , xx }
\clist_new:N \g__xeCJK_default_features_clist
\NewDocumentCommand \defaultCJKfontfeatures { m }
  { \clist_gset:Nn \g__xeCJK_default_features_clist {#1} }
\@onlypreamble \defaultCJKfontfeatures
\NewDocumentCommand \addCJKfontfeatures { m }
  {
    \xeCJK_add_font_features:x {#1}
    \tex_ignorespaces:D
  }
\cs_new_eq:NN \addCJKfontfeature \addCJKfontfeatures
\cs_new_protected_nopar:Npn \xeCJK_add_font_features:n #1
  {
    \prop_get:NVNTF \g__xeCJK_family_font_name_prop \l_xeCJK_family_tl \l__xeCJK_tmpa_tl
      {
        \clist_set:Nn \l__xeCJK_tmpa_clist {#1}
        \seq_map_function:NN
          \g__xeCJK_CJK_sub_class_seq \__xeCJK_parse_sub_class_features:n
        \prop_get:NVNT \g__xeCJK_family_font_options_prop
          \l_xeCJK_family_tl \l__xeCJK_tmpb_clist
          {
            \clist_concat:NNN
              \l__xeCJK_tmpa_clist \l__xeCJK_tmpb_clist \l__xeCJK_tmpa_clist
          }
        \xeCJK_fontspec:VV \l__xeCJK_tmpa_clist \l__xeCJK_tmpa_tl
      }
      { \__xeCJK_warning:n { addCJKfontfeature-ignored } }
  }
\cs_generate_variant:Nn \xeCJK_add_font_features:n { x }
\__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.
  }
\cs_new_protected_nopar:Npn \__xeCJK_parse_sub_class_features:n #1
  {
    \clist_if_in:NnT \l__xeCJK_tmpa_clist {#1}
      {
        \clist_remove_all:Nn \l__xeCJK_tmpa_clist {#1}
        \prop_get:NoNF \g__xeCJK_family_font_name_prop
          { \l_xeCJK_family_tl/#1 } \l__xeCJK_tmpb_tl
          {
            \prop_get:NxNF \g__xeCJK_family_font_name_prop
              { \CJKfamilydefault/#1 } \l__xeCJK_tmpb_tl
              { \tl_set_eq:NN \l__xeCJK_tmpb_tl \l__xeCJK_tmpa_tl }
          }
        \clist_set:Nx \l__xeCJK_tmpa_clist
          { #1 = { [ \exp_not:V \l__xeCJK_tmpa_clist ] { \exp_not:V \l__xeCJK_tmpb_tl } } }
        \clist_map_break:
      }
  }
\cs_generate_variant:Nn \prop_get:NnNF { Nx }
\__xeCJK_at_end_preamble:n
  {
    \cs_set_eq:NN \__xeCJK_family_default_wrap:n \exp_not:n
    \tl_if_eq:NNT \CJKfamilydefault \l__xeCJK_family_default_init_tl
      {
        \tl_gset:Nx \CJKfamilydefault
          {
            \str_case_x:nnn { \familydefault }
              {
                { \rmdefault } { \exp_not:N \CJKrmdefault }
                { \sfdefault } { \exp_not:N \CJKsfdefault }
                { \ttdefault } { \exp_not:N \CJKttdefault }
              }
              { \CJKfamilydefault }
          }
      }
    \cs_undefine:N \__xeCJK_family_default_wrap:n
    \prop_if_empty:NTF \g__xeCJK_family_font_name_prop
      { \__xeCJK_warning:nx { no-CJKfamily } { \CJKfamilydefault } }
      {
        \xeCJK_family_if_exist:xF { \CJKfamilydefault }
          {
            \tl_set_eq:NN \l__xeCJK_tmpa_tl \CJKfamilydefault
            \str_if_eq_x:nnTF { \CJKfamilydefault } { \CJKrmdefault }
              { \use:n }
              {
                \xeCJK_family_if_exist:xTF { \CJKrmdefault }
                  { \tl_gset:Nn \CJKfamilydefault { \CJKrmdefault } }
              }
              {
                \prop_map_inline:Nn \g__xeCJK_family_font_name_prop
                  { \prop_map_break:n { \tl_gset:Nn \CJKfamilydefault {#1} } }
              }
            \__xeCJK_warning:nxx { CJKfamilydefault-undefined }
              { \l__xeCJK_tmpa_tl } { \CJKfamilydefault }
          }
        \CJKfamily { \CJKfamilydefault }
        \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\\\\
    `\__xeCJK_msg_def_family_map:n {#1}'\\\\
    in~the~preamble~to~declare~the~default~CJKfamily.\\
  }
\__xeCJK_msg_new:nn { CJKfamilydefault-undefined }
  {
    Undefined~CJK~default~family~`\__xeCJK_msg_family_map:n {#1}'~
    has~been~replaced~by~`\__xeCJK_msg_family_map:n {#2}'.\\\\
    Try~to~use~`\__xeCJK_msg_def_family_map:n {#1}'~to~define~it.
  }
\keys_define:nn { xeCJK / options } { CJKmath .bool_gset:N = \g__xeCJK_math_bool }
\NewDocumentCommand \setCJKmathfont { O{} m }
  { \xeCJK_set_family:xxx { \c__xeCJK_math_tl } {#1} {#2} }
\tl_const:Nn \c__xeCJK_math_tl { CJKmath }
\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 } }
          { \use_none:nnnnn }
      }
    \prop_get:NVNT \g__xeCJK_family_name_prop \l__xeCJK_tmpa_tl \l__xeCJK_tmpb_tl
      {
        \tl_const:Nx \c__xeCJK_math_family_tl { \l__xeCJK_tmpb_tl }
        \DeclareSymbolFont \c__xeCJK_math_tl
          \c__xeCJK_encoding_tl \c__xeCJK_math_family_tl \mddefault \shapedefault
        \SetSymbolFont \c__xeCJK_math_tl { bold }
          \c__xeCJK_encoding_tl \c__xeCJK_math_family_tl \bfdefault \shapedefault
        \int_const:Nn \c_xeCJK_math_fam_int { \use:c { sym \c__xeCJK_math_tl } }
        \clist_concat:NNN
          \l__xeCJK_tmpa_clist \c__xeCJK_CJK_chars_clist \c__xeCJK_FullLeft_chars_clist
        \clist_concat:NNN
          \l__xeCJK_tmpa_clist \l__xeCJK_tmpa_clist \c__xeCJK_FullRight_chars_clist
        \clist_map_inline:Nn \l__xeCJK_tmpa_clist
          {
            \__xeCJK_set_char_class_aux:Nnw \xeCJK_gset_mathcode:nnnn {##1}
              { \c_seven } { \c_xeCJK_math_fam_int }
          }
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_gset_mathcode:nnnn #1#2#3#4
  {
    \__xeCJK_check_num_range:nnNN {#1} {#2} \l__xeCJK_tmpa_int \l__xeCJK_tmpb_int
    \xeCJK_int_until_do:nn { \l__xeCJK_tmpa_int > \l__xeCJK_tmpb_int }
      {
        \tex_global:D \XeTeXmathcode \l__xeCJK_tmpa_int = #3 ~ #4 \l__xeCJK_tmpa_int
        \int_incr:N \l__xeCJK_tmpa_int
      }
  }
\NewDocumentCommand \xeCJKVerbAddon { }
  {
    \int_compare:nNnF \etex_currentgrouplevel:D = \c_zero
      {
        \__xeCJK_set_verb_exspace:
        \bool_if:NF \l__xeCJK_verb_addon_bool
          {
            \bool_set_true:N \l__xeCJK_verb_addon_bool
            \__xeCJK_set_char_class_eq:nn { FullLeft }    { CJK }
            \__xeCJK_set_char_class_eq:nn { FullRight }   { CJK }
            \__xeCJK_set_char_class_eq:nn { HalfLeft }    { Default }
            \__xeCJK_set_char_class_eq:nn { HalfRight }   { Default }
            \__xeCJK_set_char_class_eq:nn { NormalSpace } { Default }
            \xeCJKsetup { xCJKecglue = false }
            \cs_set_protected_nopar:Npn \CJKglue
              { \skip_horizontal:N \g__xeCJK_verb_exspace_skip }
            \cs_set_protected_nopar:Npn \CJKecglue
              { \skip_horizontal:n { 0.5 \g__xeCJK_verb_exspace_skip } }
            \cs_set_eq:NN \xeCJK_check_for_glue: \CJKecglue
            \cs_set_eq:NN \xeCJK_ignore_spaces:w \CJKecglue
            \skip_set:Nn \tex_rightskip:D { \c_zero_dim plus 1 fil }
          }
      }
  }
\bool_new:N \l__xeCJK_verb_addon_bool
\cs_new_eq:NN \CJKfixedspacing \xeCJKVerbAddon
\__xeCJK_after_preamble:n { \tl_put_right:Nn \verbatim@font { \xeCJKVerbAddon } }
\cs_new_protected_nopar:Npn \__xeCJK_set_verb_exspace:
  {
    \tl_if_exist:cF { xeCJK/verb/\l_xeCJK_family_tl/\curr@fontshape/\f@size }
      {
        \group_begin:
        \xeCJK_select_font:
        \use:x
          {
            \group_end:
            \tl_gset:cx
            \exp_not:n { { xeCJK/verb/\l_xeCJK_family_tl/\curr@fontshape/\f@size } }
              {
                \exp_not:N \dim_max:nn { \c_zero_dim }
                  {
                    \c_two \tex_fontdimen:D \c_two \tex_font:D -
                    \dim_use:N \etex_fontcharwd:D \tex_font:D "4E00
                  }
              }
          }
      }
    \skip_gset:Nn \g__xeCJK_verb_exspace_skip
      { \use:c { xeCJK/verb/\l_xeCJK_family_tl/\curr@fontshape/\f@size } }
  }
\skip_new:N \g__xeCJK_verb_exspace_skip
\cs_new_protected_nopar:Npn \xeCJK_visible_space_fallback:
  { {
      \cs_if_exist_use:cF { xeCJK/space/\curr@fontshape/\f@size }
        { \xeCJK_set_visible_space_font: }
      \textvisiblespace
  } }
\AtEndOfPackage
  {
    \tl_put_left:Nn \fontspec_visible_space: { \scan_stop: }
    \cs_gset_eq:NN \fontspec_visible_space_fallback: \xeCJK_visible_space_fallback:
  }
\cs_new_protected_nopar:Npn \xeCJK_set_visible_space_font:
  {
    \tl_set:Nx \l__xeCJK_current_coor_tl { xeCJK/space/\curr@fontshape/\f@size }
    \exp_after:wN \__xeCJK_set_visible_space_size:n
    \exp_after:wN { \dim_use:N \tex_fontdimen:D \c_two \tex_font:D }
    \xeCJK_font_gset_to_current:c { \l__xeCJK_current_coor_tl }
  }
\cs_new_protected_nopar:Npn \__xeCJK_set_visible_space_size:n #1
  {
    \tl_set:Nx \f@encoding { \g_fontspec_encoding_tl }
    \tl_set:Nx \f@family { lmtt }
    \selectfont
    \dim_compare:nNnF {#1} = { \tex_fontdimen:D \c_two \tex_font:D }
      {
        \fontsize
          {
            \dim_eval:n
              {
                \f@size pt *
                \dim_ratio:nn {#1} { \tex_fontdimen:D \c_two \tex_font:D }
              }
          }
          { \f@baselineskip }
        \selectfont
      }
  }
\keys_define:nn { xeCJK / options }
  {
    LocalConfig .choice: ,
    LocalConfig / false   .code:n =
      { \bool_gset_false:N \g__xeCJK_config_bool } ,
    LocalConfig / true    .code:n =
      {
        \bool_gset_true:N \g__xeCJK_config_bool
        \tl_gset:Nn \g__xeCJK_config_name_tl { xeCJK }
      } ,
    LocalConfig / unknown .code:n =
      {
        \bool_gset_true:N \g__xeCJK_config_bool
        \tl_gset:Nx \g__xeCJK_config_name_tl { xeCJK - \l_keys_value_tl }
      } ,
    LocalConfig        .default:n = { true }
  }
\tl_new:N \g__xeCJK_config_name_tl
\bool_new:N \g__xeCJK_config_bool
\keys_define:nn { xeCJK / options }
  {
    CJKnumber    .bool_gset:N = \g__xeCJK_number_bool ,
    indentfirst  .bool_gset:N = \g__xeCJK_indent_bool ,
    normalindentfirst .meta:n = { indentfirst = false }
  }
\keys_define:nn { xeCJK / options }
  {
    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.
  }
\cs_new_nopar:Npn \CJKsymbol      #1 {#1}
\cs_new_nopar:Npn \CJKpunctsymbol #1 {#1}
\keys_set:nn { xeCJK / options }
  {
    CJKglue         = { \skip_horizontal:n { \c_zero_dim plus 0.08 \tex_baselineskip:D } } ,
    CJKecglue       = { ~ } ,
    xCJKecglue      = false ,
    CheckSingle     = false ,
    PlainEquation   = false ,
    CheckFullRight  = false ,
    CJKspace        = false ,
    CJKmath         = false ,
    CJKnumber       = false ,
    xeCJKactive     = true  ,
    LocalConfig     = true  ,
    indentfirst     = true  ,
    EmboldenFactor  = 4     ,
    SlantFactor     = 0.167 ,
    PunctStyle      = quanjiao ,
    NewLineCS       = { \par \[ } ,
    EnvCS           = { \begin \end } ,
    NoBreakCS       = { \footnote \footnotemark \nobreak } ,
    KaiMingPunct    = { ^^^^3002 ^^^^ff0e ^^^^ff1f ^^^^ff01 } ,
    LongPunct       = { ^^^^2014 ^^^^2015 ^^^^2500 ^^^^2025 ^^^^2026 } ,
    MiddlePunct     = { ^^^^2014 ^^^^2015 ^^^^2500 ^^^^00b7 ^^^^30fb ^^^^ff65 } ,
    AllowBreakBetweenPuncts = false
  }
\defaultCJKfontfeatures { Script = CJK }
\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 { \RequirePackage { indentfirst } }
\keys_define:nn { xeCJK / options }
  {
    LocalConfig .code:n = { \__xeCJK_warning:nx { option-invalid } { \l_keys_key_tl } } ,
    CJKnumber   .code:n = { \__xeCJK_warning:nx { option-invalid } { \l_keys_key_tl } } ,
    indentfirst .code:n = { \__xeCJK_warning:nx { option-invalid } { \l_keys_key_tl } }
  }
\__xeCJK_msg_new:nn { option-invalid }
  {
    The~`#1'~option~only~can~be~set~in~the~optional~argument~to~the\\
    \token_to_str:N \usepackage \ command~when~xeCJK~is~being~loaded.\\\\
    Please~do~not~set~it~via~the~\token_to_str:N \xeCJKsetup \ command.
  }
\tl_if_exist:NF \CJKrmdefault { \tl_gset:Nn \CJKrmdefault { rm } }
\tl_if_exist:NF \CJKsfdefault { \tl_gset:Nn \CJKsfdefault { sf } }
\tl_if_exist:NF \CJKttdefault { \tl_gset:Nn \CJKttdefault { tt } }
\tl_new:N \l__xeCJK_family_default_init_tl
\cs_new_eq:NN \__xeCJK_family_default_wrap:n \use:n
\tl_gset:Nx \l__xeCJK_family_default_init_tl
  {
    \exp_not:N \__xeCJK_family_default_wrap:n
      {
        \tl_if_exist:NTF \CJKfamilydefault
          { \exp_not:V \CJKfamilydefault }
          { \exp_not:N \CJKrmdefault }
      }
  }
\tl_gset_eq:NN \CJKfamilydefault \l__xeCJK_family_default_init_tl
\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 { } { \xeCJKsetup { PunctStyle = plain } }
\NewDocumentCommand \CJKsetecglue { m } { \xeCJKsetup { CJKecglue = {#1} } }
\cs_new_eq:NN \xeCJKsetecglue \CJKsetecglue
\NewDocumentCommand \CJKspace   { } { \xeCJKsetup { CJKspace = true } }
\NewDocumentCommand \CJKnospace { } { \xeCJKsetup { CJKspace = false } }
\NewDocumentCommand \xeCJKallowbreakbetweenpuncts { }
  { \xeCJKsetup { AllowBreakBetweenPuncts = true } }
\NewDocumentCommand \xeCJKnobreakbetweenpuncts { }
  { \xeCJKsetup { AllowBreakBetweenPuncts = false } }
\NewDocumentCommand \xeCJKenablefallback { }
  { \xeCJKsetup { AutoFallBack = true } }
\NewDocumentCommand \xeCJKdisablefallback { }
  { \xeCJKsetup { AutoFallBack = false } }
\NewDocumentCommand \xeCJKsetcharclass { m m m }
  {
    \xeCJK_set_char_class:nnn {#1} {#2} {#3}
    \xeCJKResetPunctClass
  }
\cs_if_exist:cT { ? - \token_to_str:N \nobreakspace }
  {
    \exp_args:NNv \ProvideTextCommandDefault \nobreakspace
      { ? - \token_to_str:N \nobreakspace }
  }
\__xeCJK_msg_new:nn { conflict-package }
  {
    The~`#1'~package~is~in~conflict~with~xeCJK. \\
    Please~do~not~use~it~or~load~it~after~xeCJK.
  }
\xeCJK_if_package_loaded:nTF { realscripts }
  {
    \@ifpackagelater { realscripts } { 2010/10/10 } { }
      {
        \__xeCJK_error:nx { conflict-package }
          {
            \xeCJK_if_package_loaded:nTF { xltxtra }
              { xltxtra } { realscripts }
          }
      }
  }
  {
    \cs_new_eq:NN \__xeCJK_dim_max:nn \dim_max:nn
    \cs_new_eq:NN \__xeCJK_dim_min:nn \dim_min:nn
    \__xeCJK_at_end_preamble:n
      {
        \xeCJK_if_package_loaded:nT { realscripts }
          {
            \@ifpackagelater { realscripts } { 2010/10/10 } { }
              {
                \cs_gset_eq:NN \dim_max:nn \__xeCJK_dim_max:nn
                \cs_gset_eq:NN \dim_min:nn \__xeCJK_dim_min:nn
              }
          }
        \cs_undefine:N \__xeCJK_dim_max:nn
        \cs_undefine:N \__xeCJK_dim_min:nn
      }
  }
\RenewDocumentCommand \fontfamily { m }
  {
    \tl_set:Nx \f@family {#1}
    \__xeCJK_update_family:n
      {
        \str_case:nnn {#1}
          {
            { \rmdefault }     { \CJKfamily { \CJKrmdefault } }
            { \sfdefault }     { \CJKfamily { \CJKsfdefault } }
            { \ttdefault }     { \CJKfamily { \CJKttdefault } }
            { \familydefault } { \CJKfamily { \CJKfamilydefault } }
          }
          { }
      }
  }
\cs_new_eq:NN \__xeCJK_update_family:n \use:n
\cs_new_eq:NN \xeCJK@fix@penalty \fix@penalty
\tl_replace_once:Nnn \xeCJK@fix@penalty { \@@italiccorr } { \xeCJK@italiccorr }
\tl_replace_once:Nnn \sw@slant          { \fix@penalty }  { \xeCJK@fix@penalty }
\cs_new_protected_nopar:Npn \xeCJK@italiccorr
  {
    \int_compare:nNnTF \XeTeXinterchartokenstate > \c_zero
      {
        \xeCJK_if_last_node:nTF { default }
          {
            \tex_unkern:D \tex_unkern:D \@@italiccorr
            { \xeCJK_make_node:n { default } }
          }
          {
            \xeCJK_if_last_node:nTF { CJK }
              {
                \tex_unkern:D \tex_unkern:D \@@italiccorr
                { \xeCJK_make_node:n { CJK } } \use:n
              }
              {
                \xeCJK_if_last_node:nTF { CJK-space }
                  {
                    \tex_unkern:D \tex_unkern:D \@@italiccorr
                    { \xeCJK_make_node:n { CJK-space } } \use:n
                  }
                  { \@@italiccorr \use_none:n }
              }
              {
                              \exp_after:wN \exp_after:wN \exp_after:wN
                \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN
                \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN
                \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN
                \xeCJK_ignore_spaces:w
              }
          }
      }
      { \@@italiccorr }
  }
\__xeCJK_after_end_preamble:n
  {
    \int_compare:nNnF
      { \c_three + \seq_count:N \g__xeCJK_new_class_seq } = \xe@alloc@intercharclass
      {
        \int_step_inline:nnnn \c_four \c_one \xe@alloc@intercharclass
          {
            \seq_if_in:NnF \g__xeCJK_new_class_seq {#1}
              { \__xeCJK_set_others_toks:n {#1} }
          }
      }
  }
\cs_new_protected_nopar:Npn \__xeCJK_set_others_toks:n #1
  {
    \int_set:cn { \__xeCJK_class_csname:n { Others } } {#1}
    \seq_map_inline:Nn \g__xeCJK_CJK_class_seq
      {
        \xeCJK_copy_inter_class_toks:nnnn {##1} { Others } {##1} { NormalSpace }
        \xeCJK_copy_inter_class_toks:nnnn { Others } {##1} { NormalSpace } {##1}
        \xeCJK_app_inter_class_toks:nnx {##1} { Others }
          { \xeCJK_get_inter_class_toks:nn { Default } { Others } }
        \xeCJK_pre_inter_class_toks:nnx { 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 }
          }
      }
  }
\__xeCJK_after_preamble:n
  {
    \tl_map_inline:nn
      {
        \textellipsis  \textemdash     \textperiodcentered \textcentereddot
        \textquoteleft \textquoteright \textquotedblleft   \textquotedblright
      }
      { \cs_gset_nopar:Npx #1 { { \makexeCJKinactive \exp_not:o {#1} } } }
    \tl_put_left:Nn \tipaencoding { \makexeCJKinactive }
    \cs_new_eq:NN \__xeCJK_aux_r:n \r
    \cs_set_nopar:Npn \r #1 { { \makexeCJKinactive \__xeCJK_aux_r:n {#1} } }
    \xeCJK_if_package_loaded:nT { pifont }
      {
        \RenewDocumentCommand \Pifont { m }
          { \makexeCJKinactive \usefont { U } {#1} { m } { n } }
      }
  }
\__xeCJK_after_end_preamble:n
  {
    \xeCJK_if_package_loaded:nT { hyperref }
      {
        \tl_gput_right:Nn \pdfstringdefPreHook
          {
            \__xeCJK_gobble_CJKfamily:
            \xeCJK_cs_clear:N \makexeCJKinactive
          }
      }
  }
\__xeCJK_after_end_preamble:n
  {
    \bool_if:nT
      { \xeCJK_if_package_loaded_p:n { cprotect } && \cs_if_exist_p:N \icprotect }
      { \exp_after:wN \tex_let:D \cs:w cprotect \cs_end: \icprotect }
  }
\tl_set:cn { ver@CJK.sty } { 9999/99/99 }
\tl_set_eq:cc { ver@CJKulem.sty }  { ver@CJK.sty }
\tl_set_eq:cc { ver@CJKpunct.sty } { ver@CJK.sty }
\cs_if_exist:NF \CJK@ifundefined
  { \cs_set_eq:NN \CJK@ifundefined \cs_if_free:NTF }
\NewDocumentCommand \xeCJKcaption { o m }
  {
    \IfNoValueF {#1} { \XeTeXdefaultencoding "#1" }
    \use:x
      {
        \char_set_catcode_letter:n { 64 }
        \file_input:n { #2.cpx }
        \char_set_catcode:nn { 64 } { \char_value_catcode:n { 64 } }
      }
    \XeTeXdefaultencoding "UTF-8"
  }
\cs_if_eq:NNTF \ifCTEX@fntef \tex_iftrue:D
  { \RequirePackage { xeCJKfntef } }
  {
    \__xeCJK_at_end_preamble:n
      {
        \xeCJK_if_package_loaded:nF { xeCJKfntef }
          {
            \xeCJK_if_package_loaded:nTF { CJKfntef }
              { \RequirePackage { xeCJKfntef } }
              {
                \xeCJK_if_package_loaded:nT { ulem }
                  { \RequirePackage { xeCJKfntef } }
              }
          }
      }
  }
\bool_if:NT \g__xeCJK_number_bool
  {
    \tl_set:Nn \CJK@UnicodeEnc { UTF8 }
    \cs_set_protected:Npn \CJKaddEncHook #1#2
      { \cs_set:cpn { __xeCJK_enc_#1_hook: } {#2} }
    \cs_set_protected_nopar:Npn \Unicode #1#2
      { \tex_char:D \etex_numexpr:D (#1) * \c_two_hundred_fifty_six + (#2) \scan_stop: }
    \RequirePackage { CJKnumb }
    \cs_if_exist_use:c { __xeCJK_enc_ \CJK@UnicodeEnc _hook: }
    \tl_set:Nn \CJK@tenthousand    { \Unicode { 78 } { 7 } }
    \tl_set:Nn \CJK@hundredmillion { \Unicode { 78 } { 191 } }
  }
\bool_if:NT \g__xeCJK_config_bool
  {
    \tl_const:Nn \c__xeCJK_config_ext_tl { cfg }
    \@onefilewithoptions
      { \g__xeCJK_config_name_tl } [ ] [ ] { \c__xeCJK_config_ext_tl }
  }
%% 
%%    This package consists of the file  xeCJK.dtx
%%                 and the derived files xeCJK.pdf,
%%                                       xeCJK.sty,
%%                                       xeCJK.cfg,
%%                                       xeCJK.ins,
%%                                       xeCJKfntef.sty,
%%                                       xeCJK-example-autofake.tex,
%%                                       xeCJK-example-fallback.tex,
%%                                       xeCJK-example-subCJKblock.tex,
%%                                       xeCJK-example-CJKecglue.tex,
%%                                       xeCJK-example-checksingle.tex,
%%                                       xeCJK-example-CJKfntef.tex,
%%                                       xeCJK-example-punctstyle.tex,
%%                                       xeCJK-example-verbatim.tex, and
%%                                       README.txt.
%%
%% End of file `xeCJK.sty'.

Zerion Mini Shell 1.0