二十日☆鼠 - IKEDA Soji > Unicode-LineBreak-2013.10 > Unicode::LineBreak~[ja]

Download:
Unicode-LineBreak-2013.10.tar.gz

Annotate this POD

CPAN RT

Open  1
View/Report Bugs
Source   Latest Release: Unicode-LineBreak-2013.11

NAME ^

Unicode::LineBreak~[ja] - UAX #14 Unicode 行分割アルゴリズム

SYNOPSIS ^

    use Unicode::LineBreak;
    $lb = Unicode::LineBreak->new();
    $broken = $lb->break($string);

DESCRIPTION ^

Unicode::LineBreak は、Unicode 標準の附属書14 [UAX #14] で述べる Unicode 行分割アルゴリズムを実行する。 分割位置を決定する際に、附属書11 [UAX #11] で定義される East_Asian_Width 参考特性も考慮する。

用語

便宜的に以下の用語を使う。

強制分割〔mandatory break〕は、基本規則で定められており、周囲の文字に関係なく義務的に実行される行分割動作。 任意分割は、基本規則で認められており、ユーザが実行すると決めた場合に行われる行分割動作。 [UAX #14] で定義される任意分割には直接分割〔direct break〕と間接分割〔indirect break〕とがある。

音素文字的な文字〔alphabetic characters〕は、通常、他の文字が分割の機会を与えないかぎり、文字同士の間で行分割できない文字。 表語文字的な文字〔ideographic characters〕は、通常、その前後で行分割できる文字。 [UAX #14] では音素文字的な文字のほとんどを AL に、表語文字的な文字のほとんどを ID に分類している (これらの用語は文字学の観点からすれば不正確である)。 若干の用字系では、個々の文字からは分割位置が明確にならないため、辞書による発見的方法を用いる。

文字列の桁数は、文字列に含まれる文字の数と等しいとはかぎらない。 個々の文字は広い〔wide〕か、狭い〔narrow〕か、前進を伴わない〔nonspacing〕かのいずれかであり、各々 2 桁、1 桁、0 桁を占める。 若干の文字は、使われる文脈によって広くも狭くもなり得る。 カスタマイズによって、文字はより多様な幅を持ちうる。

PUBLIC INTERFACE ^

行の分割

new ([KEY => VALUE, ...])

コンストラクタ。 KEY => VALUE の対については "オプション" を参照。

break (STRING)

インスタンスメソッド。 Unicode 文字列 STRING を分割し、それを返す。 配列コンテクストでは、結果の各行の配列を返す。

break_partial (STRING)

インスタンスメソッド。 break() と同じだが、文字列を少しずつ追加して入力する場合。 入力が完了したことを示すには、STRING 引数に undef を与える。

config (KEY)
config (KEY => VALUE, ...)

インスタンスメソッド。 設定を取得または変更する。 KEY => VALUE の対については "オプション" を参照。

copy

コピーコンストラクタ。 オブジェクトインスタンスの複製をつくる。

情報の取得

breakingRule (BEFORESTR, AFTERSTR)

インスタンスメソッド。 文字列 BEFORESTR と AFTERSTR の間での行分割動作を得る。 返値については "定数" を参照。

: このメソッドは、行分割のおおまかな動作を表す値を返すにすぎない。 実際のテキストを行折りするには、break() 等のメソッドを使ってほしい。

context ([Charset => CHARSET], [Language => LANGUAGE])

関数。 キャラクタセット CHARSET および言語コード LANGUAGE から、それを使う言語/地域の文脈を得る。

オプション

"new""config" の両メソッドには以下の対を指定できる。 桁数の算出 ([E])、書記素クラスタ分節 ([G]) (Unicode::GCString~[ja] も参照)、行分割動作 ([L]) に影響するものがある。

BreakIndent => "YES" | "NO"

[L] 行頭の SPACE の並び (インデント) の後では常に分割を許す。 [UAX #14] は SPACE のこのような用法を考慮していない。 初期値は "YES"

: このオプションはリリース 1.011 で導入された。

CharMax => NUMBER

[L] 行に含みうる最大の文字数。行末の空白文字と改行の文字列を除く。 文字数は一般に行の長さを表さないことに注意。 初期値は 9980 にはできない。

ColMin => NUMBER

[L] 任意分割された行の、改行の文字列と行末の空白文字を含めない最小桁数。 初期値は 0

ColMax => NUMBER

[L] 行の、改行の文字列と行末の空白文字を含めない最大桁数。つまり、行の最大長。 初期値は 76

"Urgent" オプションおよび "ユーザ定義の行分割動作" も参照。

ComplexBreaking => "YES" | "NO"

[L] 東南アジアの複雑な文脈で、発見的な行折りを行う。 初期値は、東南アジアの表記体系での単語分節が有効なら "YES"

Context => CONTEXT

[E][L] 言語/地域の文脈を指定する。 現在使える文脈は "EASTASIAN""NONEASTASIAN"。 初期の文脈は "NONEASTASIAN"

"EASTASIAN" 文脈では、East_Asian_Width 特性が曖昧 (A) であれば「広い」文字とみなし、行分割特性が AI であれば表語文字的 (ID) とみなす。

"NONEASTASIAN" 文脈では、East_Asian_Width 特性が曖昧 (A) であれば「狭い」文字とみなし、行分割特性が AI であれば音素文字的 (AL) とみなす。

EAWidth => [ ORD => PROPERTY ]
EAWidth => undef

[E] 個々の文字の East_Asian_Width 特性を手直しする。 ORD は文字の UCS インデクス値か、それらの配列への参照。 PROPERTY は East_Asian_Width 特性値か拡張値のいずれか ("定数" を参照)。 このオプションは複数回指定できる。 undef を指定すると、それまでの手直しをすべて取り消す。

初期値では、East_Asian_width 特性の手直しはしない。 "文字の特性の手直し" も参照。

Format => METHOD

[L] 分割した行を整形する方法を指定する。

"SIMPLE"

初期の方法。 任意分割の位置に改行を挿入するだけ。

"NEWLINE"

"Newline" オプションで指定したもので改行を置き換える。 改行の前とテキスト終端の空白文字を除去する。 テキスト終端に改行がなければ追加する。

"TRIM"

任意分割の位置に改行を挿入する。 改行の前の空白文字を除去する。

undef

なにもしない (改行の挿入も)。

サブルーチンへの参照

"行の整形" を参照。

HangulAsAL => "YES" | "NO"

[L] ハングル音節とハングル連結チャモ〔conjoining jamo〕を音素文字的な文字 (AL) と扱う。 初期値は "NO"

LBClass => [ ORD => CLASS ]
LBClass => undef

[G][L] 個々の文字の行分割特性 (分類) を手直しする。 ORD は文字の UCS インデクス値か、それらの配列への参照。 CLASS は行分割特性値のいずれか ("定数" を参照)。 このオプションは複数回指定できる。 undef を指定すると、それまでの手直しをすべて取り消す。

初期値では、行分割特性の手直しはしない。 "文字の特性の手直し" も参照。

LegacyCM => "YES" | "NO"

[G][L] 前に空白文字がついた結合文字を単独の結合文字 (ID) と扱う。 Unicode 5.0 版からは、空白文字のこのような使いかたは推奨されない。 初期値は "YES"

Newline => STRING

[L] 改行の文字列とする Unicode 文字列。 初期値は "\n"

Prep => METHOD

[L] ユーザ定義の行分割動作を追加する。 このオプションは複数回指定できる。 METHOD には以下のものを指定できる。

"NONBREAKURI"

URI を分割しない。

"BREAKURI"

URI を、印刷物に適した規則で分割する。 詳しくは [CMOS] の 6.17 節と 17.11 節を参照。

[ REGEX, SUBREF ]

正規表現 REGEX にマッチする文字列を、SUBREF で参照されるサブルーチンで分割する。 詳細は "ユーザ定義の行分割動作" を参照。

undef

それまでに追加した動作をすべて取り消す。

Sizing => METHOD

[L] 文字列の長さを算出する方法を指定する。 以下のオプションが使える。

"UAX11"

初期の方法。 組み込みの文字データベースによって文字の桁数を算出する。

undef

文字列に含まれる書記素クラスタ (Unicode::GCString 参照) の数を返す。

サブルーチンへの参照

"文字列長の算出" を参照。

"ColMax""ColMin""EAWidth" オプションも参照。

Urgent => METHOD

[L] 長すぎる行の扱いかたを指定する。 以下のオプションが使える。

"CROAK"

エラーメッセージを出力して死ぬ。

"FORCE"

長すぎる文字列を無理やり分割する。

undef

初期の方法。 長すぎる文字列も分割しない。

サブルーチンへの参照

"ユーザ定義の行分割動作" を参照。

ViramaAsJoiner => "YES" | "NO"

[G] ヴィラーマ記号 (ヒンディ語では「ハラント」、クメール文字での「脚」) とそれに続く字とを分離しない。 初期値は "YES": このオプションはリリース 2011.001_29 で導入された。 以前のリリースでは "NO" に固定であった。 これは、[UAX #29] で定義する「初期の」書記素クラスタには含まれない仕様である。

定数

EA_Na, EA_N, EA_A, EA_W, EA_H, EA_F

[UAX #11] で定義される 6 つの East_Asian_Width 特性値。 狭 (Na)、中立 (N)、曖昧 (A)、広 (W)、半角 (H)、全角 (F)。

EA_Z

前進を伴わない文字の East_Asian_Width 特性の値。

: この「前進を伴わない」値は当モジュールによる拡張であり、 [UAX #11] の一部ではない。

LB_BK, LB_CR, LB_LF, LB_NL, LB_SP, LB_OP, LB_CL, LB_CP, LB_QU, LB_GL, LB_NS, LB_EX, LB_SY, LB_IS, LB_PR, LB_PO, LB_NU, LB_AL, LB_HL, LB_ID, LB_IN, LB_HY, LB_BA, LB_BB, LB_B2, LB_CB, LB_ZW, LB_CM, LB_WJ, LB_H2, LB_H3, LB_JL, LB_JV, LB_JT, LB_SG, LB_AI, LB_CJ, LB_SA, LB_XX, LB_RI

[UAX #14] で定義される 40 の行分割特性値 (分類)。

: 特性値 CP はUnicode 5.2.0版で導入された。 特性値 HL と CJ はUnicode 6.1.0版で導入された。 特性値 RI は Unicode 6.2.0版で導入された。

MANDATORY, DIRECT, INDIRECT, PROHIBITED

行分割動作を表す 4 つの値。 強制分割。直接分割も間接分割も認める。間接分割を認めるが直接分割は禁ずる。分割を禁ずる。

Unicode::LineBreak::SouthEastAsian::supported

東南アジアの表記体系のための単語分節機能が有効かどうかを示すフラグ。 この機能が有効になっていれば、空でない文字列。 そうでなければ undef

: 現リリースでは現代タイ語のタイ文字にのみ対応している。

UNICODE_VERSION

このモジュールが参照する Unicode 標準の版を示す文字列。

CUSTOMIZATION ^

行の整形

"Format" オプションにサブルーチンへの参照を指定する場合、そのサブルーチンは 3 つの引数を取らなければならない。

    $修正後 = &サブルーチン(SELF, EVENT, STR);

SELF は Unicode::LineBreak オブジェクト、EVENT はサブルーチンが呼ばれた文脈を表す文字列、STR は分割位置の前または後の Unicode 文字列の断片。

    EVENT |駆動の契機           |STR
    -----------------------------------------------------------------
    "sot" |テキスト先頭         |最初の行の断片
    "sop" |強制分割の後         |次の行の断片
    "sol" |任意分割の後         |続きの行の断片
    ""    |分割の直前           |行全体 (終端の空白文字を除く)
    "eol" |任意分割             |分割位置の前の空白文字
    "eop" |強制分割             |改行とその前の空白文字
    "eot" |テキスト終端         |テキスト終端の空白文字 (と改行)
    -----------------------------------------------------------------

サブルーチンは、テキストの断片を修正して返さなければならない。なにも修正しなかったことを示すには、undef を返せばよい。 なお、"sot""sop""sol" の文脈での修正はその後の分割位置の決定に影響するが、ほかの文脈での修正は影響しない。

注意: 文字列の引数は実際には書記素クラスタ列である。 Unicode::GCString~[ja] 参照。

たとえば次のコードは、行末の空白を取り除いて行折りをする。

    sub fmt {
        if ($_[1] =~ /^eo/) {
            return "\n";
        }
        return undef;
    }
    my $lb = Unicode::LineBreak->new(Format => \&fmt);
    $output = $lb->break($text);

ユーザ定義の行分割動作

任意分割によって生じる行が CharMax、ColMax、ColMin のいずれかの制限を超えると見込まれるときは、引き続く文字列に対して緊急分割を実行できる。 "Urgent" オプションにサブルーチンへの参照を指定する場合、そのサブルーチンは 2 つの引数を取らなければならない。

    @分割後 = &サブルーチン(SELF, STR);

SELF は Unicode::LineBreak オブジェクト、STR は分割すべき Unicode 文字列。

サブルーチンは、文字列 STR を分割した結果の配列を返さなければならない。

注意: 文字列の引数は実際には書記素クラスタ列である。 Unicode::GCString~[ja] 参照。

たとえば次のコードは、若干の化学物質 (チチンのような) の名称にハイフンを挿入し、行折りできるようにする。

    sub hyphenize {
        return map {$_ =~ s/yl$/yl-/; $_} split /(\w+?yl(?=\w))/, $_[1];
    }
    my $lb = Unicode::LineBreak->new(Urgent => \&hyphenize);
    $output = $lb->break("Methionylthreonylthreonylglutaminylarginyl...");

"Prep" オプションに [REGEX, SUBREF] の配列参照を指定する場合、サブルーチンは 2 つの引数を取らなければならない。

    @分割後 = &サブルーチン(SELF, STR);

SELF は Unicode::LineBreak オブジェクト、STR は REGEX にマッチする分割すべき Unicode 文字列。

サブルーチンは、文字列 STR を分割した結果の配列を返さなければならない。

たとえば次のコードは、HTTP URL を [CMOS] の規則を用いて分割する。

    my $url = qr{http://[\x21-\x7E]+}i;
    sub breakurl {
        my $self = shift;
        my $str = shift;
        return split m{(?<=[/]) (?=[^/]) |
                       (?<=[^-.]) (?=[-~.,_?\#%=&]) |
                       (?<=[=&]) (?=.)}x, $str;
    }
    my $lb = Unicode::LineBreak->new(Prep => [$url, \&breakurl]);
    $output = $lb->break($string);

状態の保存

Unicode::LineBreak オブジェクトはハッシュ参照としてふるまう。 任意の要素を、オブジェクトの存在期間中保存できる。

たとえば次のコードは、段落を空行で分ける。

    sub paraformat {
        my $self = shift;
        my $action = shift;
        my $str = shift;
        
        if ($action eq 'sot' or $action eq 'sop') {
            $self->{'line'} = '';
        } elsif ($action eq '') {
            $self->{'line'} = $str;
        } elsif ($action eq 'eol') {
            return "\n";
        } elsif ($action eq 'eop') {
            if (length $self->{'line'}) {
                return "\n\n";
            } else {
                return "\n";
            }
        } elsif ($action eq 'eot') {
            return "\n";
        }
        return undef;
    }
    my $lb = Unicode::LineBreak->new(Format => \&paraformat);
    $output = $lb->break($string);

文字列長の算出

"Sizing" オプションにサブルーチンへの参照を指定する場合、そのサブルーチンは 5 つの引数を取らなければならない。

    $桁数 = &サブルーチン(SELF, LEN, PRE, SPC, STR);

SELF は Unicode::LineBreak オブジェクト、LEN は先行する文字列の長さ、PRE は先行する Unicode 文字列、SPC は追加される空白文字、STR は処理する Unicode 文字列。

サブルーチンは PRE.SPC.STR の桁数を算出して返さなければならない。 桁数は整数でなくてもよい。桁数の単位は随意に選べるが、"ColMin" オプションおよび "ColMax" オプションのそれと一致させなければならない。

注意: 文字列の引数は実際には書記素クラスタ列である。 Unicode::GCString~[ja] 参照。

たとえば次のコードは、行に 8 桁ごとのタブストップがあるものとして処理する。

    sub tabbedsizing {
        my ($self, $cols, $pre, $spc, $str) = @_;
     
        my $spcstr = $spc.$str;
        while ($spcstr->lbc == LB_SP) {
            my $c = $spcstr->item(0);
            if ($c eq "\t") {
                $cols += 8 - $cols % 8;
            } else {
                $cols += $c->columns;
            }
            $spcstr = $spcstr->substr(1);
        }
        $cols += $spcstr->columns;
        return $cols;
    };
    my $lb = Unicode::LineBreak->new(LBClass => [ord("\t") => LB_SP],
                                     Sizing => \&tabbedsizing);
    $output = $lb->break($string);

文字の特性の手直し

"LBClass" オプションおよび "EAWidth" オプションで個々の文字の行分割特性 (分類) や East_Asian_Width 特性を手直しできる。その際に便利な定数をいくつか定義してある。

行分割特性

仮名などの行頭禁則文字

初期値では、若干の仮名や仮名に準ずるものを行頭禁則文字 (NS または CJ) と扱う。 以下の対を LBClass オプションに指定すれば、これらの文字を通常の表語文字的な文字 (ID) と扱える。

KANA_NONSTARTERS() => LB_ID

下記の文字すべて。

IDEOGRAPHIC_ITERATION_MARKS() => LB_ID

表語文字的な繰り返し記号。 U+3005 繰返し記号、U+303B ゆすり点、U+309D 平仮名繰返し記号、U+309E 平仮名繰返し記号 (濁点)、U+30FD 片仮名繰返し記号、U+30FE 片仮名繰返し記号 (濁点)。

注。仮名ではないものもある。

KANA_SMALL_LETTERS() => LB_ID
KANA_PROLONGED_SOUND_MARKS() => LB_ID

小書き仮名。 小書き平仮名 U+3041 ぁ, U+3043 ぃ, U+3045 ぅ, U+3047 ぇ, U+3049 ぉ, U+3063 っ, U+3083 ゃ, U+3085 ゅ, U+3087 ょ, U+308E ゎ, U+3095 ゕ, U+3096 ゖ。 小書き片仮名 U+30A1 ァ, U+30A3 ィ, U+30A5 ゥ, U+30A7 ェ, U+30A9 ォ, U+30C3 ッ, U+30E3 ャ, U+30E5 ュ, U+30E7 ョ, U+30EE ヮ, U+30F5 ヵ, U+30F6 ヶ。 片仮名表音拡張 U+31F0 ㇰ - U+31FF ㇿ。 小書き片仮名 (代替名称) U+FF67 ァ - U+FF6F ッ。

長音記号。 U+30FC 長音記号、U+FF70 長音記号 (代替名称)。

注。これらの文字は行頭禁則文字と扱われることも、通常の表語文字的な文字と扱われることもある。[JIS X 4051] 6.1.1、[JLREQ] 3.1.7 や [UAX14] を参照。

注。U+3095 ゕ, U+3096 ゖ, U+30F5 ヵ, U+30F6 ヶ は仮名ではないとされる。

MASU_MARK() => LB_ID

U+303C ます記号。

注。この文字は仮名ではないが、通常 "ます""マス" の略記として用いられる。

注。この文字は [UAX #14] では行頭禁則文字 (NS) に分類されるが、[JIS X 4051] や [JLREQ] では文字クラス (13) や cl-19 (ID に相当) に分類される。

曖昧な引用符

初期値では、若干の記号を曖昧な引用符 (QU) と扱う。

BACKWARD_QUOTES() => LB_OP, FORWARD_QUOTES() => LB_CL

ある言語 (オランダ語、英語、イタリア語、ポルトガル語、スペイン語、トルコ語、 および東アジアの多くの言語) では、開き記号に 9 が回転した形状の引用符 (‘ “) を、閉じ記号に 9 の形状の引用符 (’ ”) を用いる。

FORWARD_QUOTES() => LB_OP, BACKWARD_QUOTES() => LB_CL

ほかの言語 (チェコ語、ドイツ語、スロヴァク語) では、9 の形状の引用符 (’ ”) を開き記号に、9 が回転した形状の引用符 (‘ “) を閉じ記号に用いる。

BACKWARD_GUILLEMETS() => LB_OP, FORWARD_GUILLEMETS() => LB_CL

フランス語、ギリシャ語、ロシア語などでは、左向きのギュメ (« ‹) を開き記号に、右向きのギュメ (» ›) を閉じ記号に用いる。

FORWARD_GUILLEMETS() => LB_OP, BACKWARD_GUILLEMETS() => LB_CL

ドイツ語やスロヴァク語では、右向きのギュメ (» ›) を開き記号に、左向きのギュメ (« ‹) を閉じ記号に用いる。

デーン語、フィン語、ノルウェー語、スウェーデン語では、9 の形状の引用符や 右向きのギュメ (’ ” » ›) を開き記号にも閉じ記号にも用いる。

和字間隔

IDEOGRAPHIC_SPACE() => LB_BA

U+3000 和字間隔が行頭に来ないようにする。 これが初期の挙動である。

IDEOGRAPHIC_SPACE() => LB_ID

和字間隔が行頭に来ることがある。 Unicode 6.2以前はこれが初期の挙動であった。

IDEOGRAPHIC_SPACE() => LB_SP

和字間隔が行頭に来ず、行末でははみ出すようにする。

East_Asian_Width 特性

ラテン、ギリシア、キリルの各用字系では、特定の文字が曖昧 (A) の East_Asian_Width 特性を持っている。このため、こういった文字は "EASTASIAN" 文脈で広い文字と扱われる。 EAWidth => [ AMBIGUOUS_*() => EA_N ] と指定することで、そのような文字を常に狭い文字と扱う。

AMBIGUOUS_ALPHABETICS() => EA_N

下記の文字すべてを East_Asian_Width 特性 N (中立) の文字と扱う。

AMBIGUOUS_CYRILLIC() => EA_N
AMBIGUOUS_GREEK() => EA_N
AMBIGUOUS_LATIN() => EA_N

曖昧 (A) の幅を持つキリル、ギリシア、ラテン用字系の文字を中立 (N) の文字と扱う。

いっぽう、東アジアの符号化文字集合に対する多くの実装でたびたび広い文字に描画されてきたにもかかわらず、Unicode 標準では全角 (F) の互換文字を持つがゆえに狭い (Na) 文字とされている文字が若干ある。EAWidth オプションに以下のように指定することで、これらの文字を "EASTASIAN" 文脈で広い文字と扱える。

QUESTIONABLE_NARROW_SIGNS() => EA_A

U+00A2 セント記号、U+00A3 ポンド記号、U+00A5 円記号 (または元記号)、U+00A6 破断線、U+00AC 否定、U+00AF マクロン。

設定ファイル

"new" メソッドおよび "config" メソッドのオプション引数の組み込み初期値は、 設定ファイルで上書きできる。 Unicode/LineBreak/Defaults.pm。 詳細は Unicode/LineBreak/Defaults.pm.sample を読んでほしい。

BUGS ^

バグやバグのような動作は、開発者に教えてください。

CPAN Request Tracker: http://rt.cpan.org/Public/Dist/Display.html?Name=Unicode-LineBreak.

VERSION ^

$VERSION 変数を参照してほしい。

このモジュールの開発版が http://hatuka.nezumi.nu/repos/Unicode-LineBreak/ にある。

非互換な変更

2012.06

標準への適合性

このモジュールで用いている文字の特性値は、Unicode 標準 6.3.0版による。

このモジュールでは、実装水準 UAX14-C2 を実装しているつもり。

IMPLEMENTATION NOTES ^

REFERENCES ^

[CMOS]

The Chicago Manual of Style, 15th edition. University of Chicago Press, 2003.

[JIS X 4051]

JIS X 4051:2004 日本語文書の組版方法. 日本規格協会, 2004.

[JLREQ]

阿南康宏他. 日本語組版処理の要件, W3C 技術ノート 2012年4月3日. http://www.w3.org/TR/2012/NOTE-jlreq-20120403/ja/.

[UAX #11]

A. Freytag (ed.) (2008-2009). Unicode Standard Annex #11: East Asian Width, Revisions 17-19. http://unicode.org/reports/tr11/.

[UAX #14]

A. Freytag and A. Heninger (eds.) (2008-2013). Unicode Standard Annex #14: Unicode Line Breaking Algorithm, Revisions 22-32. http://unicode.org/reports/tr14/.

[UAX #29]

Mark Davis (ed.) (2009-2013). Unicode Standard Annex #29: Unicode Text Segmentation, Revisions 15-23. http://www.unicode.org/reports/tr29/.

SEE ALSO ^

Text::LineFold~[ja], Text::Wrap, Unicode::GCString~[ja].

AUTHOR ^

Copyright (C) 2009-2013 Hatuka*nezumi - IKEDA Soji <hatuka(at)nezumi.nu>.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

syntax highlighting: