710 lines
14 KiB
C
710 lines
14 KiB
C
/************************************************************/
|
||
/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
|
||
/************************************************************/
|
||
|
||
/* Select2.c -- Less-frequently-used selection routines */
|
||
|
||
#define NOCLIPBOARD
|
||
#define NOGDICAPMASKS
|
||
#define NOCTLMGR
|
||
#define NOVIRTUALKEYCODES
|
||
#define NOWINMESSAGES
|
||
#define NOWINSTYLES
|
||
#define NOSYSMETRICS
|
||
#define NOMENUS
|
||
#define NOSOUND
|
||
#define NOCOMM
|
||
#define NOPEN
|
||
#define NOWNDCLASS
|
||
#define NOICON
|
||
#define NORASTEROPS
|
||
#define NOSHOWWINDOW
|
||
#define NOATOM
|
||
#define NOKEYSTATE
|
||
#define NOSYSCOMMANDS
|
||
#define NOBITMAP
|
||
#define NOBRUSH
|
||
#define NOCOLOR
|
||
#define NODRAWTEXT
|
||
#define NOMB
|
||
#define NOPOINT
|
||
#define NOMSG
|
||
#include <windows.h>
|
||
#include "mw.h"
|
||
#include "toolbox.h"
|
||
#include "docdefs.h"
|
||
#include "editdefs.h"
|
||
#include "dispdefs.h"
|
||
#include "cmddefs.h"
|
||
#include "wwdefs.h"
|
||
#include "ch.h"
|
||
#include "fmtdefs.h"
|
||
#include "propdefs.h"
|
||
|
||
#ifdef DBCS
|
||
#include "kanji.h"
|
||
#endif
|
||
|
||
extern int vfSeeSel;
|
||
extern typeCP vcpFirstParaCache;
|
||
extern typeCP vcpLimParaCache;
|
||
extern typeCP vcpFetch;
|
||
extern CHAR *vpchFetch;
|
||
extern int vccpFetch;
|
||
extern typeCP cpMinCur;
|
||
extern typeCP cpMacCur;
|
||
extern struct SEL selCur;
|
||
extern int docCur;
|
||
extern struct FLI vfli;
|
||
extern struct WWD rgwwd[];
|
||
extern int vfSelHidden;
|
||
extern int wwCur;
|
||
extern struct CHP vchpFetch;
|
||
extern struct PAP vpapAbs;
|
||
extern struct WWD *pwwdCur;
|
||
extern int vfInsEnd;
|
||
extern typeCP CpBeginLine();
|
||
extern int vfPictSel;
|
||
extern int vfSizeMode;
|
||
extern struct CHP vchpNormal;
|
||
extern int vfInsertOn;
|
||
extern struct CHP vchpSel; /* Holds the props when the selection
|
||
is an insert point */
|
||
extern int vfMakeInsEnd;
|
||
extern typeCP vcpSelect;
|
||
extern int vfSelAtPara;
|
||
/* true iff the last selection was made by an Up/Down cursor key */
|
||
extern int vfLastCursor;
|
||
|
||
|
||
#ifndef DBCS /* US version */
|
||
/* C P L I M S T Y S P E C I A L */
|
||
typeCP CpLimStySpecial(cp, sty)
|
||
typeCP cp;
|
||
int sty;
|
||
{ /* Return the first cp which is not part of the same sty unit */
|
||
int wb, ch, ich;
|
||
struct EDL *pedl;
|
||
|
||
/* Other cases covered in CpLimSty, our only caller */
|
||
|
||
Assert( cp < cpMacCur );
|
||
Assert( cp >= cpMinCur );
|
||
Assert( sty == styWord || sty == stySent );
|
||
|
||
/* Special kludge for picture paragraphs */
|
||
CachePara(docCur, cp);
|
||
if (vpapAbs.fGraphics)
|
||
return vcpLimParaCache;
|
||
|
||
FetchCp(docCur, cp, 0, fcmChars + fcmNoExpand);
|
||
|
||
Assert(vccpFetch != 0);
|
||
|
||
/* Must be word or sentence */
|
||
wb = WbFromCh(ch = vpchFetch[ich = 0]);
|
||
#ifdef CRLF
|
||
if (ch == chReturn)
|
||
return vcpFetch + 2;
|
||
#endif
|
||
if (ch == chEol || ch == chSect || ch == chNewLine || ch == chTab)
|
||
/* EOL is its own unit */
|
||
return vcpFetch + 1;
|
||
|
||
if (wb == wbWhite && sty == stySent)
|
||
{ /* Might be between sentences; go back to text */
|
||
FetchCp(docCur, CpFirstSty(cp, styWord), 0, fcmChars + fcmNoExpand);
|
||
wb = WbFromCh(ch = vpchFetch[ich = 0]);
|
||
}
|
||
|
||
for (;;)
|
||
{
|
||
if (++ich >= vccpFetch)
|
||
{ /* Get next line and set up */
|
||
FetchCp(docNil, cpNil, 0, fcmChars);
|
||
if (vcpFetch == cpMacCur)
|
||
return cpMacCur; /* End of doc */
|
||
ich = 0;
|
||
}
|
||
if (sty == stySent)
|
||
switch (ch)
|
||
{
|
||
case chDot:
|
||
case chBang:
|
||
case chQMark:
|
||
sty = styWord;
|
||
wb = wbPunct;
|
||
}
|
||
switch (ch = vpchFetch[ich])
|
||
{
|
||
case chTab:
|
||
case chEol:
|
||
case chSect:
|
||
case chNewLine:
|
||
#ifdef CRLF
|
||
case chReturn:
|
||
#endif
|
||
goto BreakFor;
|
||
}
|
||
if (sty == styWord)
|
||
{ /* Word ends after white space or on text/punct break */
|
||
int wbT = WbFromCh(ch);
|
||
if (wb != wbT && (wb = wbT) != wbWhite)
|
||
break;
|
||
}
|
||
}
|
||
BreakFor:
|
||
return vcpFetch + ich;
|
||
}
|
||
|
||
|
||
|
||
/* C P F I R S T S T Y S P E C I A L */
|
||
typeCP CpFirstStySpecial(cp, sty)
|
||
typeCP cp;
|
||
int sty;
|
||
{ /* Return the first cp of this sty unit. */
|
||
typeCP cpBegin;
|
||
int wb, ch, dcpChunk;
|
||
typeCP cpSent;
|
||
CHAR rgch[dcpAvgSent];
|
||
int ich;
|
||
typeCP cpT;
|
||
|
||
/* Other cases were covered by CpFirstSty, our only caller */
|
||
|
||
Assert( cp > cpMinCur );
|
||
Assert( sty == stySent || sty == styWord );
|
||
|
||
if (cp >= cpMacCur)
|
||
cpT = cp = cpMacCur;
|
||
else
|
||
cpT = cp++;
|
||
|
||
CachePara(docCur, cpT );
|
||
if ((vcpFirstParaCache == cpT) || vpapAbs.fGraphics)
|
||
return vcpFirstParaCache;
|
||
|
||
dcpChunk = (sty == styWord) ? dcpAvgWord : dcpAvgSent;
|
||
cpBegin = (cp > dcpChunk) ? cp - dcpChunk : cp0;
|
||
|
||
FetchRgch(&ich, rgch, docCur, cpBegin, cp, dcpChunk);
|
||
wb = WbFromCh(ch = rgch[--ich]);
|
||
|
||
#ifdef CRLF
|
||
if(cpBegin + ich == 0)
|
||
return cp0;
|
||
|
||
if (ch == chEol && rgch[ich-1] == chReturn) /* EOL is its own unit */
|
||
return cpBegin + ich - 1;
|
||
if (ch == chEol || ch == chReturn || ch == chSect || ch == chNewLine || ch == chTab)
|
||
return cpBegin + ich;
|
||
#else /* not CRLF */
|
||
if (ch == chEol || ch == chSect || ch == chNewLine || ch == chTab) /* EOL is its own unit */
|
||
return cpBegin + ich;
|
||
#endif /* CRLF */
|
||
|
||
if (wb == wbText)
|
||
cpSent = cpBegin + ich;
|
||
else
|
||
cpSent = cpNil;
|
||
|
||
for (;;)
|
||
{
|
||
if (ich == 0)
|
||
{
|
||
if (cpBegin == cpMinCur)
|
||
return cpMinCur; /* beginning of doc */
|
||
cpBegin = (cpBegin > dcpChunk) ? cpBegin - dcpChunk : cp0;
|
||
FetchRgch(&ich, rgch, docCur, cpBegin, cp, dcpChunk);
|
||
}
|
||
ch = rgch[--ich];
|
||
CachePara( docCur, cpBegin + ich ); /* Needed for pictures */
|
||
if (ch == chEol || ch == chSect || ch == chNewLine ||
|
||
ch == chTab || vpapAbs.fGraphics )
|
||
break; /* EOL Always ends a unit */
|
||
if (sty == styWord)
|
||
{
|
||
if (wb != wbWhite)
|
||
{
|
||
if (WbFromCh(ch) != wb)
|
||
break;
|
||
}
|
||
else
|
||
wb = WbFromCh(ch);
|
||
}
|
||
else
|
||
{ /* Test for sentence. */
|
||
switch (ch)
|
||
{
|
||
case chDot:
|
||
case chBang:
|
||
case chQMark:
|
||
if (cpSent != cpNil)
|
||
return cpSent;
|
||
}
|
||
switch (WbFromCh(ch))
|
||
{
|
||
case wbText:
|
||
cpSent = cpBegin + ich;
|
||
wb = wbText;
|
||
break;
|
||
case wbPunct:
|
||
switch (wb)
|
||
{
|
||
case wbWhite:
|
||
wb = wbPunct;
|
||
break;
|
||
case wbText:
|
||
cpSent = cpBegin + ich;
|
||
}
|
||
break;
|
||
case wbWhite:
|
||
if (wb == wbPunct)
|
||
cpSent = cpBegin + ich + 1;
|
||
wb = wbWhite;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return cpBegin + ich + 1;
|
||
}
|
||
|
||
#else /* DBCS version */
|
||
|
||
typeCP CpLimStySpecial(cp, sty)
|
||
typeCP cp;
|
||
int sty;
|
||
{
|
||
CHAR rgch[cchKanji];
|
||
int ch, ch2;
|
||
int ich, wb;
|
||
typeCP cpLim, cpT;
|
||
|
||
/* Other cases covered in CpLimSty, our only caller */
|
||
Assert(cp < cpMacCur);
|
||
Assert(cp >= cpMinCur);
|
||
Assert(sty == styWord || sty == stySent);
|
||
|
||
/* Picture paragraph? */
|
||
CachePara(docCur, cp);
|
||
if (vpapAbs.fGraphics) {
|
||
return vcpLimParaCache;
|
||
}
|
||
|
||
cpLim = vcpLimParaCache;
|
||
if (vcpLimParaCache > cpMacCur) {
|
||
/* No EOL at end of doc */
|
||
cpLim = cpMacCur;
|
||
}
|
||
|
||
FetchRgch(&ich, rgch, docCur, cp,
|
||
((cpT = cp + cchKanji) < cpLim) ? cpT : cpLim, cchKanji);
|
||
ch = rgch[0];
|
||
#ifdef CRLF
|
||
if (ch == chReturn) {
|
||
return (cp + 2);
|
||
}
|
||
#endif /* CRLF */
|
||
if (ch == chEol || ch == chSect || ch == chNewLine || ch == chTab) {
|
||
/* EOL is its own unit. */
|
||
return (cp + 1);
|
||
}
|
||
#ifdef KOREA
|
||
wb=WbFromCh(ch);
|
||
#else
|
||
|
||
if (FKanji1(ch)) {
|
||
wb = WbFromKanjiChCh(ch, (int) rgch[1]);
|
||
if (sty == styWord && wb == wbKanjiText) {
|
||
return (CpLimSty(cp, styChar));
|
||
}
|
||
else {
|
||
if (wb == wbKanjiText) {
|
||
wb = wbKanjiTextFirst;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
if (sty == styWord && FKanaText(ch)) {
|
||
return (CpLimSty(cp, styChar));
|
||
}
|
||
wb = WbFromCh(ch);
|
||
}
|
||
#endif
|
||
|
||
for (; cp < cpLim;) {
|
||
int wbT;
|
||
|
||
if (sty == stySent) {
|
||
if (FKanji1(ch)) {
|
||
CHAR ch2;
|
||
|
||
ch2 = rgch[1];
|
||
if (FKanjiKuten(ch, ch2) ||
|
||
FKanjiQMark(ch, ch2) ||
|
||
FKanjiBang(ch, ch2) ||
|
||
FKanjiPeriod(ch, ch2)) {
|
||
sty = styWord;
|
||
wb = wbPunct;
|
||
goto lblNextFetch;
|
||
}
|
||
}
|
||
else {
|
||
switch (ch) {
|
||
#ifndef KOREA
|
||
case bKanjiKuten:
|
||
#endif
|
||
case chDot:
|
||
case chBang:
|
||
case chQMark:
|
||
sty = styWord;
|
||
wb = wbPunct;
|
||
goto lblNextFetch;
|
||
}
|
||
}
|
||
}
|
||
|
||
switch (ch) {
|
||
case chTab:
|
||
case chEol:
|
||
case chSect:
|
||
case chNewLine:
|
||
#ifdef CRLF
|
||
case chReturn:
|
||
#endif /* CRLF */
|
||
return cp;
|
||
}
|
||
|
||
if (sty == styWord) {
|
||
#ifdef KOREA
|
||
wbT = WbFromCh(ch);
|
||
#else
|
||
if (FKanji1(ch)) {
|
||
wbT = WbFromKanjiChCh(ch, (int) rgch[1]);
|
||
}
|
||
else {
|
||
wbT = WbFromCh(ch);
|
||
}
|
||
#endif
|
||
|
||
if (wb != wbT && (wb = wbT) != wbWhite) {
|
||
return (cp);
|
||
}
|
||
}
|
||
|
||
lblNextFetch:
|
||
cp = CpLimSty(cp, styChar);
|
||
if (cp < cpLim) {
|
||
/* Save some time and an untimely demise.... */
|
||
FetchRgch(&ich, rgch, docCur, cp,
|
||
((cpT = cp + cchKanji) < cpLim) ? cpT : cpLim, cchKanji);
|
||
ch = rgch[0];
|
||
}
|
||
}
|
||
return (cpLim);
|
||
}
|
||
|
||
typeCP CpFirstStySpecial(cp, sty)
|
||
typeCP cp;
|
||
int sty;
|
||
{ /* Return the first cp of this sty unit. */
|
||
typeCP cpT, cpLim, cpFirstPara,
|
||
cpFirstLastSent; /* cpFirst of the last possible sentence boundary */
|
||
CHAR rgch[cchKanji];
|
||
int ch;
|
||
int wb;
|
||
int ich;
|
||
|
||
/* Other cases were covered by CpFirstSty, our only caller */
|
||
|
||
Assert( cp > cpMinCur );
|
||
Assert(CpFirstSty(cp, styChar) == cp); /* cp is on a char boundary */
|
||
Assert( sty == stySent || sty == styWord );
|
||
|
||
cpT = cp;
|
||
if (cp >= cpMacCur) {
|
||
cpT = cp = cpMacCur;
|
||
}
|
||
|
||
CachePara(docCur, cpT );
|
||
cpFirstPara = vcpFirstParaCache;
|
||
if ((vcpFirstParaCache == cpT) || vpapAbs.fGraphics) {
|
||
return vcpFirstParaCache;
|
||
}
|
||
|
||
|
||
#ifdef CRLF
|
||
/* CR-LF is assumed. */
|
||
Assert(TRUE);
|
||
#else
|
||
Assert(FALSE);
|
||
#endif /* CRLF */
|
||
FetchRgch(&ich, rgch, docCur, cp,
|
||
((cpT = cp + cchKanji) < cpMacCur) ? cpT : cpMacCur, cchKanji);
|
||
ch = rgch[0];
|
||
if (ich == cchKanji && ch == chReturn && rgch[1] == chEol) {
|
||
/* EOL is its own unit */
|
||
return cp;
|
||
}
|
||
if (ch == chEol || ch == chReturn || ch == chSect ||
|
||
ch == chNewLine || ch == chTab) {
|
||
return cp;
|
||
}
|
||
|
||
cpFirstLastSent = cpNil;
|
||
|
||
#ifdef KOREA
|
||
wb = WbFromCh(ch);
|
||
#else
|
||
if (FKanji1(ch)) {
|
||
wb = WbFromKanjiChCh(ch, (int) rgch[1]);
|
||
if (sty == styWord && wb == wbKanjiText) {
|
||
return (CpFirstSty(cp, styChar));
|
||
}
|
||
else {
|
||
if (wb == wbKanjiText) {
|
||
wb = wbKanjiTextFirst;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
if (sty == styWord && FKanaText(ch)) {
|
||
return (CpFirstSty(cp, styChar));
|
||
}
|
||
wb = WbFromCh(ch);
|
||
}
|
||
#endif
|
||
|
||
for (; cpFirstPara < cp; ) {
|
||
typeCP cpTemp;
|
||
int wbT;
|
||
|
||
cpTemp = CpFirstSty(cp - 1, styChar);
|
||
FetchRgch(&ich, rgch, docCur, cpTemp,
|
||
((cpT = cpTemp + cchKanji) < cpMacCur) ? cpT : cpMacCur, cchKanji);
|
||
ch = rgch[0];
|
||
#ifdef KOREA
|
||
wbT = WbFromCh(ch);
|
||
#else
|
||
if (FKanji1(ch)) {
|
||
wbT = WbFromKanjiChCh(ch, (int) rgch[1]);
|
||
}
|
||
else {
|
||
wbT = WbFromCh(ch);
|
||
}
|
||
#endif
|
||
if (wb == wbWhite) {
|
||
#ifdef KOREA
|
||
wb=wbT;
|
||
#else
|
||
wb = (wbT == wbKanjiText) ? wbKanjiTextFirst : wbT;
|
||
#endif
|
||
}
|
||
else if (wb != wbT) {
|
||
if (sty == styWord) {
|
||
return (cp);
|
||
}
|
||
else /* sty == stySent */ {
|
||
/* wb != wbWhite */
|
||
/* wb != wbT */
|
||
if (wbT == wbWhite || wbT == wbPunct) {
|
||
cpFirstLastSent = cp;
|
||
wb = wbWhite;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (sty == stySent) { /* for the sentence */
|
||
if (FKanji1(ch)) {
|
||
int ch2;
|
||
ch2 = rgch[1];
|
||
if (FKanjiKuten(ch, ch2) ||
|
||
FKanjiQMark(ch, ch2) ||
|
||
FKanjiBang(ch, ch2) ||
|
||
FKanjiPeriod(ch, ch2)) {
|
||
if (cpFirstLastSent != cpNil) {
|
||
return (cpFirstLastSent);
|
||
}
|
||
else {
|
||
cpFirstLastSent = cp;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
switch(ch) {
|
||
#ifndef KOREA
|
||
case bKanjiKuten:
|
||
#endif
|
||
case chDot:
|
||
case chBang:
|
||
case chQMark:
|
||
if (cpFirstLastSent != cpNil) {
|
||
return (cpFirstLastSent);
|
||
}
|
||
else {
|
||
cpFirstLastSent = cp;
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
cp = cpTemp;
|
||
}
|
||
return (cpFirstPara);
|
||
}
|
||
#endif /* DBCS */
|
||
|
||
/* W B F R O M C H */
|
||
int WbFromCh(ch)
|
||
int ch;
|
||
{ /* Return word-breakness of ch */
|
||
|
||
#if defined(DBCS) & !defined(KOREA) /* was in JAPAN; KenjiK '90-10-29 */
|
||
/* Brought from WIN2 source. */
|
||
if (FKanaPunct(ch)) {
|
||
return wbPunct;
|
||
}
|
||
else if (FKanaText(ch)) {
|
||
return wbKanjiText;
|
||
}
|
||
#endif
|
||
|
||
switch (ch)
|
||
{
|
||
case chSpace:
|
||
case chEol:
|
||
#ifdef CRLF
|
||
case chReturn:
|
||
#endif
|
||
case chSect:
|
||
case chTab:
|
||
case chNewLine:
|
||
case chNBSFile:
|
||
return wbWhite;
|
||
case chNRHFile:
|
||
return wbText;
|
||
default: /* we are using the ANSI char set that windows used */
|
||
#ifdef KOREA
|
||
return ((isalpha(ch) || isdigit(ch) || ((ch>0x81)&&(ch<0xfe)))? wbText : wbPunct);
|
||
#else
|
||
return ((isalpha(ch) || isdigit(ch))? wbText : wbPunct);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
#ifdef DBCS /* was in JAPAN; KenjiK '90-10-29 */
|
||
/* Brought from WIN2 source. */
|
||
int WbFromKanjiChCh(ch1, ch2)
|
||
int ch1, ch2;
|
||
{
|
||
if (ch1 == chReturn && ch2 == chEol) {
|
||
return wbWhite;
|
||
}
|
||
else if (FKanjiSpace(ch1, ch2)) {
|
||
return wbWhite;
|
||
}
|
||
else
|
||
|
||
#ifdef JAPAN
|
||
{
|
||
switch (ch1) {
|
||
case 0x81:
|
||
if (0x57 <= ch2 && ch2 <= 0x59) {
|
||
return wbKanjiText;
|
||
}
|
||
else {
|
||
return wbPunct;
|
||
}
|
||
case 0x85:
|
||
if ((0x40 <= ch2 && ch2 <= 0x4E) ||
|
||
(0x59 <= ch2 && ch2 <= 0x5F) ||
|
||
(0x7A <= ch2 && ch2 <= 0x7E) ||
|
||
(0x9B <= ch2 && ch2 <= 0xA3) ||
|
||
(0xDC <= ch2 && ch2 <= 0xDD)) {
|
||
return wbPunct;
|
||
}
|
||
else {
|
||
return wbKanjiText;
|
||
}
|
||
case 0x86:
|
||
return wbPunct;
|
||
case 0x87:
|
||
return ((ch2 >= 0x90) ? wbPunct : wbKanjiText);
|
||
default:
|
||
return wbKanjiText;
|
||
}
|
||
}
|
||
#endif
|
||
#ifdef KOREA
|
||
{
|
||
switch (ch1) {
|
||
case 0xa2:
|
||
if (0xde <= ch2 && ch2 <= 0xe5) {
|
||
return wbText; // wbKanjiText; MSCH bklee 01/26/95
|
||
}
|
||
else {
|
||
return wbPunct;
|
||
}
|
||
case 0xa3:
|
||
if ((0xa1 <= ch2 && ch2 <= 0xaf) ||
|
||
(0xba <= ch2 && ch2 <= 0xc0) ||
|
||
(0xdb <= ch2 && ch2 <= 0xe0) ||
|
||
(0xfb <= ch2 && ch2 <= 0xfe)) {
|
||
return wbPunct;
|
||
}
|
||
else {
|
||
return wbText; //wbKanjiText; MSCH bklee 01/26/95
|
||
}
|
||
default:
|
||
return wbText; //wbKanjiText; MSCH bklee 01/26/95
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#ifdef PRC // brucere 11/16/95
|
||
{
|
||
switch (ch1) {
|
||
case 0xA1:
|
||
return wbPunct;
|
||
|
||
case 0xA3:
|
||
if ((0xA1 <= ch2 && ch2 <= 0xAF) ||
|
||
(0xBA <= ch2 && ch2 <= 0xC0) ||
|
||
(0xDB <= ch2 && ch2 <= 0xE0) ||
|
||
(0xFB <= ch2 && ch2 <= 0xFE))
|
||
return wbPunct;
|
||
else
|
||
return wbKanjiText;
|
||
|
||
case 0xA4:
|
||
if (ch2 == 0x92)
|
||
return wbPunct;
|
||
else
|
||
return wbKanjiText;
|
||
|
||
default:
|
||
return wbKanjiText;
|
||
}
|
||
}
|
||
#elif TAIWAN
|
||
{
|
||
switch (ch1) {
|
||
case 0xA1:
|
||
if (0x41 <= ch2 && ch2 <= 0xAC)
|
||
return wbPunct;
|
||
else
|
||
return wbKanjiText;
|
||
|
||
default:
|
||
return wbKanjiText;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
}
|
||
#endif
|
||
|
||
|
||
|