1*efeef26fSAndrew Rist /**************************************************************
2cdf0e10cSrcweir *
3*efeef26fSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
4*efeef26fSAndrew Rist * or more contributor license agreements. See the NOTICE file
5*efeef26fSAndrew Rist * distributed with this work for additional information
6*efeef26fSAndrew Rist * regarding copyright ownership. The ASF licenses this file
7*efeef26fSAndrew Rist * to you under the Apache License, Version 2.0 (the
8*efeef26fSAndrew Rist * "License"); you may not use this file except in compliance
9*efeef26fSAndrew Rist * with the License. You may obtain a copy of the License at
10*efeef26fSAndrew Rist *
11*efeef26fSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
12*efeef26fSAndrew Rist *
13*efeef26fSAndrew Rist * Unless required by applicable law or agreed to in writing,
14*efeef26fSAndrew Rist * software distributed under the License is distributed on an
15*efeef26fSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*efeef26fSAndrew Rist * KIND, either express or implied. See the License for the
17*efeef26fSAndrew Rist * specific language governing permissions and limitations
18*efeef26fSAndrew Rist * under the License.
19*efeef26fSAndrew Rist *
20*efeef26fSAndrew Rist *************************************************************/
21*efeef26fSAndrew Rist
22*efeef26fSAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sw.hxx"
26cdf0e10cSrcweir
27cdf0e10cSrcweir
28cdf0e10cSrcweir #include <osl/endian.h>
29cdf0e10cSrcweir #include <hintids.hxx>
30cdf0e10cSrcweir #include <svl/urihelper.hxx>
31cdf0e10cSrcweir #include <tools/cachestr.hxx>
32cdf0e10cSrcweir #include <doc.hxx>
33cdf0e10cSrcweir #include <pam.hxx>
34cdf0e10cSrcweir #include <docary.hxx>
35cdf0e10cSrcweir #include <editsh.hxx>
36cdf0e10cSrcweir #include <edimp.hxx>
37cdf0e10cSrcweir #include <frmfmt.hxx>
38cdf0e10cSrcweir #include <swundo.hxx> // fuer die UndoIds
39cdf0e10cSrcweir #include <ndtxt.hxx>
40cdf0e10cSrcweir #include <swtable.hxx> // fuers kopieren von Tabellen
41cdf0e10cSrcweir #include <shellio.hxx> // SwTextBlocks
42cdf0e10cSrcweir #include <acorrect.hxx>
43cdf0e10cSrcweir #include <swerror.h> // SwTextBlocks
44cdf0e10cSrcweir
45cdf0e10cSrcweir /******************************************************************************
46cdf0e10cSrcweir * jetzt mit einem verkappten Reader/Writer/Dokument
47cdf0e10cSrcweir ******************************************************************************/
48cdf0e10cSrcweir
InsertGlossary(SwTextBlocks & rGlossary,const String & rStr)49cdf0e10cSrcweir void SwEditShell::InsertGlossary( SwTextBlocks& rGlossary, const String& rStr )
50cdf0e10cSrcweir {
51cdf0e10cSrcweir StartAllAction();
52cdf0e10cSrcweir GetDoc()->InsertGlossary( rGlossary, rStr, *GetCrsr(), this );
53cdf0e10cSrcweir EndAllAction();
54cdf0e10cSrcweir }
55cdf0e10cSrcweir
56cdf0e10cSrcweir
57cdf0e10cSrcweir /******************************************************************************
58cdf0e10cSrcweir * aktuelle Selektion zum Textbaustein machen und ins
59cdf0e10cSrcweir * Textbausteindokument einfuegen, einschliesslich Vorlagen
60cdf0e10cSrcweir ******************************************************************************/
61cdf0e10cSrcweir
62cdf0e10cSrcweir
MakeGlossary(SwTextBlocks & rBlks,const String & rName,const String & rShortName,sal_Bool bSaveRelFile,const String * pOnlyTxt)63cdf0e10cSrcweir sal_uInt16 SwEditShell::MakeGlossary( SwTextBlocks& rBlks, const String& rName, const String& rShortName,
64cdf0e10cSrcweir sal_Bool bSaveRelFile, const String* pOnlyTxt )
65cdf0e10cSrcweir {
66cdf0e10cSrcweir SwDoc* pGDoc = rBlks.GetDoc();
67cdf0e10cSrcweir
68cdf0e10cSrcweir String sBase;
69cdf0e10cSrcweir if(bSaveRelFile)
70cdf0e10cSrcweir {
71cdf0e10cSrcweir INetURLObject aURL( rBlks.GetFileName() );
72cdf0e10cSrcweir sBase = aURL.GetMainURL( INetURLObject::NO_DECODE );
73cdf0e10cSrcweir }
74cdf0e10cSrcweir rBlks.SetBaseURL( sBase );
75cdf0e10cSrcweir
76cdf0e10cSrcweir sal_uInt16 nRet;
77cdf0e10cSrcweir
78cdf0e10cSrcweir if( pOnlyTxt )
79cdf0e10cSrcweir nRet = rBlks.PutText( rShortName, rName, *pOnlyTxt );
80cdf0e10cSrcweir else
81cdf0e10cSrcweir {
82cdf0e10cSrcweir rBlks.ClearDoc();
83cdf0e10cSrcweir if( rBlks.BeginPutDoc( rShortName, rName ) )
84cdf0e10cSrcweir {
85cdf0e10cSrcweir rBlks.GetDoc()->SetRedlineMode_intern( nsRedlineMode_t::REDLINE_DELETE_REDLINES );
86cdf0e10cSrcweir _CopySelToDoc( pGDoc );
87cdf0e10cSrcweir rBlks.GetDoc()->SetRedlineMode_intern( (RedlineMode_t)0 );
88cdf0e10cSrcweir nRet = rBlks.PutDoc();
89cdf0e10cSrcweir }
90cdf0e10cSrcweir else
91cdf0e10cSrcweir nRet = (sal_uInt16) -1;
92cdf0e10cSrcweir }
93cdf0e10cSrcweir
94cdf0e10cSrcweir return nRet;
95cdf0e10cSrcweir }
96cdf0e10cSrcweir
SaveGlossaryDoc(SwTextBlocks & rBlock,const String & rName,const String & rShortName,sal_Bool bSaveRelFile,sal_Bool bOnlyTxt)97cdf0e10cSrcweir sal_uInt16 SwEditShell::SaveGlossaryDoc( SwTextBlocks& rBlock,
98cdf0e10cSrcweir const String& rName,
99cdf0e10cSrcweir const String& rShortName,
100cdf0e10cSrcweir sal_Bool bSaveRelFile,
101cdf0e10cSrcweir sal_Bool bOnlyTxt )
102cdf0e10cSrcweir {
103cdf0e10cSrcweir StartAllAction();
104cdf0e10cSrcweir
105cdf0e10cSrcweir SwDoc* pGDoc = rBlock.GetDoc();
106cdf0e10cSrcweir SwDoc* pMyDoc = GetDoc();
107cdf0e10cSrcweir
108cdf0e10cSrcweir String sBase;
109cdf0e10cSrcweir if(bSaveRelFile)
110cdf0e10cSrcweir {
111cdf0e10cSrcweir INetURLObject aURL( rBlock.GetFileName() );
112cdf0e10cSrcweir sBase = aURL.GetMainURL( INetURLObject::NO_DECODE );
113cdf0e10cSrcweir }
114cdf0e10cSrcweir rBlock.SetBaseURL( sBase );
115cdf0e10cSrcweir sal_uInt16 nRet = USHRT_MAX;
116cdf0e10cSrcweir
117cdf0e10cSrcweir if( bOnlyTxt )
118cdf0e10cSrcweir {
119cdf0e10cSrcweir KillPams();
120cdf0e10cSrcweir
121cdf0e10cSrcweir SwPaM* pCrsr = GetCrsr();
122cdf0e10cSrcweir
123cdf0e10cSrcweir SwNodeIndex aStt( pMyDoc->GetNodes().GetEndOfExtras(), 1 );
124cdf0e10cSrcweir SwCntntNode* pCntntNd = pMyDoc->GetNodes().GoNext( &aStt );
125cdf0e10cSrcweir const SwNode* pNd = pCntntNd->FindTableNode();
126cdf0e10cSrcweir if( !pNd )
127cdf0e10cSrcweir pNd = pCntntNd;
128cdf0e10cSrcweir
129cdf0e10cSrcweir pCrsr->GetPoint()->nNode = *pNd;
130cdf0e10cSrcweir if( pNd == pCntntNd )
131cdf0e10cSrcweir pCrsr->GetPoint()->nContent.Assign( pCntntNd, 0 );
132cdf0e10cSrcweir pCrsr->SetMark();
133cdf0e10cSrcweir
134cdf0e10cSrcweir // dann bis zum Ende vom Nodes Array
135cdf0e10cSrcweir pCrsr->GetPoint()->nNode = pMyDoc->GetNodes().GetEndOfContent().GetIndex()-1;
136cdf0e10cSrcweir pCntntNd = pCrsr->GetCntntNode();
137cdf0e10cSrcweir if( pCntntNd )
138cdf0e10cSrcweir pCrsr->GetPoint()->nContent.Assign( pCntntNd, pCntntNd->Len() );
139cdf0e10cSrcweir
140cdf0e10cSrcweir String sBuf;
141cdf0e10cSrcweir if( GetSelectedText( sBuf, GETSELTXT_PARABRK_TO_ONLYCR ) && sBuf.Len() )
142cdf0e10cSrcweir nRet = rBlock.PutText( rShortName, rName, sBuf );
143cdf0e10cSrcweir }
144cdf0e10cSrcweir else
145cdf0e10cSrcweir {
146cdf0e10cSrcweir rBlock.ClearDoc();
147cdf0e10cSrcweir if( rBlock.BeginPutDoc( rShortName, rName ) )
148cdf0e10cSrcweir {
149cdf0e10cSrcweir SwNodeIndex aStt( pMyDoc->GetNodes().GetEndOfExtras(), 1 );
150cdf0e10cSrcweir SwCntntNode* pCntntNd = pMyDoc->GetNodes().GoNext( &aStt );
151cdf0e10cSrcweir const SwNode* pNd = pCntntNd->FindTableNode();
152cdf0e10cSrcweir if( !pNd ) pNd = pCntntNd;
153cdf0e10cSrcweir SwPaM aCpyPam( *pNd );
154cdf0e10cSrcweir aCpyPam.SetMark();
155cdf0e10cSrcweir
156cdf0e10cSrcweir // dann bis zum Ende vom Nodes Array
157cdf0e10cSrcweir aCpyPam.GetPoint()->nNode = pMyDoc->GetNodes().GetEndOfContent().GetIndex()-1;
158cdf0e10cSrcweir pCntntNd = aCpyPam.GetCntntNode();
159cdf0e10cSrcweir aCpyPam.GetPoint()->nContent.Assign( pCntntNd, pCntntNd->Len() );
160cdf0e10cSrcweir
161cdf0e10cSrcweir aStt = pGDoc->GetNodes().GetEndOfExtras();
162cdf0e10cSrcweir pCntntNd = pGDoc->GetNodes().GoNext( &aStt );
163cdf0e10cSrcweir SwPosition aInsPos( aStt, SwIndex( pCntntNd ));
164cdf0e10cSrcweir pMyDoc->CopyRange( aCpyPam, aInsPos, false );
165cdf0e10cSrcweir
166cdf0e10cSrcweir nRet = rBlock.PutDoc();
167cdf0e10cSrcweir }
168cdf0e10cSrcweir }
169cdf0e10cSrcweir EndAllAction();
170cdf0e10cSrcweir return nRet;
171cdf0e10cSrcweir }
172cdf0e10cSrcweir
173cdf0e10cSrcweir /******************************************************************************
174cdf0e10cSrcweir * kopiere alle Selectionen und das Doc
175cdf0e10cSrcweir ******************************************************************************/
176cdf0e10cSrcweir
177cdf0e10cSrcweir
_CopySelToDoc(SwDoc * pInsDoc,SwNodeIndex * pSttNd)178cdf0e10cSrcweir sal_Bool SwEditShell::_CopySelToDoc( SwDoc* pInsDoc, SwNodeIndex* pSttNd )
179cdf0e10cSrcweir {
180cdf0e10cSrcweir ASSERT( pInsDoc, "kein Ins.Dokument" );
181cdf0e10cSrcweir
182cdf0e10cSrcweir SwNodes& rNds = pInsDoc->GetNodes();
183cdf0e10cSrcweir
184cdf0e10cSrcweir SwNodeIndex aIdx( rNds.GetEndOfContent(), -1 );
185cdf0e10cSrcweir SwCntntNode * pNd = aIdx.GetNode().GetCntntNode();
186cdf0e10cSrcweir SwPosition aPos( aIdx, SwIndex( pNd, pNd->Len() ));
187cdf0e10cSrcweir
188cdf0e10cSrcweir // soll der Index auf Anfang returnt werden ?
189cdf0e10cSrcweir if( pSttNd )
190cdf0e10cSrcweir {
191cdf0e10cSrcweir *pSttNd = aPos.nNode;
192cdf0e10cSrcweir (*pSttNd)--;
193cdf0e10cSrcweir }
194cdf0e10cSrcweir
195cdf0e10cSrcweir sal_Bool bRet = sal_False;
196cdf0e10cSrcweir SET_CURR_SHELL( this );
197cdf0e10cSrcweir
198cdf0e10cSrcweir pInsDoc->LockExpFlds();
199cdf0e10cSrcweir
200cdf0e10cSrcweir if( IsTableMode() )
201cdf0e10cSrcweir {
202cdf0e10cSrcweir // kopiere Teile aus einer Tabelle: lege eine Tabelle mit der Breite
203cdf0e10cSrcweir // von der Originalen an und kopiere die selectierten Boxen.
204cdf0e10cSrcweir // Die Groessen werden prozentual korrigiert.
205cdf0e10cSrcweir
206cdf0e10cSrcweir // lasse ueber das Layout die Boxen suchen
207cdf0e10cSrcweir SwTableNode* pTblNd;
208cdf0e10cSrcweir SwSelBoxes aBoxes;
209cdf0e10cSrcweir GetTblSel( *this, aBoxes );
210cdf0e10cSrcweir if( aBoxes.Count() && 0 != (pTblNd = (SwTableNode*)aBoxes[0]
211cdf0e10cSrcweir ->GetSttNd()->FindTableNode() ))
212cdf0e10cSrcweir {
213cdf0e10cSrcweir // teste ob der TabellenName kopiert werden kann
214cdf0e10cSrcweir sal_Bool bCpyTblNm = aBoxes.Count() == pTblNd->GetTable().GetTabSortBoxes().Count();
215cdf0e10cSrcweir if( bCpyTblNm )
216cdf0e10cSrcweir {
217cdf0e10cSrcweir const String& rTblName = pTblNd->GetTable().GetFrmFmt()->GetName();
218cdf0e10cSrcweir const SwFrmFmts& rTblFmts = *pInsDoc->GetTblFrmFmts();
219cdf0e10cSrcweir for( sal_uInt16 n = rTblFmts.Count(); n; )
220cdf0e10cSrcweir if( rTblFmts[ --n ]->GetName() == rTblName )
221cdf0e10cSrcweir {
222cdf0e10cSrcweir bCpyTblNm = sal_False;
223cdf0e10cSrcweir break;
224cdf0e10cSrcweir }
225cdf0e10cSrcweir }
226cdf0e10cSrcweir bRet = pInsDoc->InsCopyOfTbl( aPos, aBoxes, 0, bCpyTblNm, sal_False );
227cdf0e10cSrcweir }
228cdf0e10cSrcweir else
229cdf0e10cSrcweir bRet = sal_False;
230cdf0e10cSrcweir }
231cdf0e10cSrcweir else
232cdf0e10cSrcweir {
233cdf0e10cSrcweir bool bColSel = _GetCrsr()->IsColumnSelection();
234cdf0e10cSrcweir if( bColSel && pInsDoc->IsClipBoard() )
235cdf0e10cSrcweir pInsDoc->SetColumnSelection( true );
236cdf0e10cSrcweir {
237cdf0e10cSrcweir FOREACHPAM_START(this)
238cdf0e10cSrcweir
239cdf0e10cSrcweir if( !PCURCRSR->HasMark() )
240cdf0e10cSrcweir {
241cdf0e10cSrcweir if( 0 != (pNd = PCURCRSR->GetCntntNode()) &&
242cdf0e10cSrcweir ( bColSel || !pNd->GetTxtNode() ) )
243cdf0e10cSrcweir {
244cdf0e10cSrcweir PCURCRSR->SetMark();
245cdf0e10cSrcweir PCURCRSR->Move( fnMoveForward, fnGoCntnt );
246cdf0e10cSrcweir bRet = GetDoc()->CopyRange( *PCURCRSR, aPos, false )
247cdf0e10cSrcweir || bRet;
248cdf0e10cSrcweir PCURCRSR->Exchange();
249cdf0e10cSrcweir PCURCRSR->DeleteMark();
250cdf0e10cSrcweir }
251cdf0e10cSrcweir }
252cdf0e10cSrcweir else
253cdf0e10cSrcweir {
254cdf0e10cSrcweir bRet = GetDoc()->CopyRange( *PCURCRSR, aPos, false ) || bRet;
255cdf0e10cSrcweir }
256cdf0e10cSrcweir
257cdf0e10cSrcweir FOREACHPAM_END()
258cdf0e10cSrcweir }
259cdf0e10cSrcweir }
260cdf0e10cSrcweir
261cdf0e10cSrcweir pInsDoc->UnlockExpFlds();
262cdf0e10cSrcweir if( !pInsDoc->IsExpFldsLocked() )
263cdf0e10cSrcweir pInsDoc->UpdateExpFlds(NULL, true);
264cdf0e10cSrcweir
265cdf0e10cSrcweir // die gemerkte Node-Position wieder auf den richtigen Node
266cdf0e10cSrcweir if( bRet && pSttNd )
267cdf0e10cSrcweir (*pSttNd)++;
268cdf0e10cSrcweir
269cdf0e10cSrcweir
270cdf0e10cSrcweir return bRet;
271cdf0e10cSrcweir }
272cdf0e10cSrcweir
273cdf0e10cSrcweir /*------------------------------------------------------------------------
274cdf0e10cSrcweir Beschreibung: Text innerhalb der Selektion erfragen
275cdf0e10cSrcweir Returnwert: liefert sal_False, wenn der selektierte Bereich
276cdf0e10cSrcweir zu gross ist, um in den Stringpuffer kopiert zu werden.
277cdf0e10cSrcweir ------------------------------------------------------------------------*/
278cdf0e10cSrcweir
GetSelectedText(String & rBuf,int nHndlParaBrk)279cdf0e10cSrcweir sal_Bool SwEditShell::GetSelectedText( String &rBuf, int nHndlParaBrk )
280cdf0e10cSrcweir {
281cdf0e10cSrcweir sal_Bool bRet = sal_False;
282cdf0e10cSrcweir GetCrsr(); // ggfs. alle Cursor erzeugen lassen
283cdf0e10cSrcweir if( IsSelOnePara() )
284cdf0e10cSrcweir {
285cdf0e10cSrcweir rBuf = GetSelTxt();
286cdf0e10cSrcweir if( GETSELTXT_PARABRK_TO_BLANK == nHndlParaBrk )
287cdf0e10cSrcweir {
288cdf0e10cSrcweir xub_StrLen nPos = 0;
289cdf0e10cSrcweir while( STRING_NOTFOUND !=
290cdf0e10cSrcweir ( nPos = rBuf.SearchAndReplace( 0x0a, ' ', nPos )) )
291cdf0e10cSrcweir ;
292cdf0e10cSrcweir }
293cdf0e10cSrcweir else if( IsSelFullPara() &&
294cdf0e10cSrcweir GETSELTXT_PARABRK_TO_ONLYCR != nHndlParaBrk )
295cdf0e10cSrcweir {
296cdf0e10cSrcweir #if defined(UNX)
297cdf0e10cSrcweir rBuf += '\012';
298cdf0e10cSrcweir #else
299cdf0e10cSrcweir rBuf += String::CreateFromAscii(
300cdf0e10cSrcweir RTL_CONSTASCII_STRINGPARAM( "\015\012" ));
301cdf0e10cSrcweir #endif
302cdf0e10cSrcweir }
303cdf0e10cSrcweir bRet = sal_True;
304cdf0e10cSrcweir }
305cdf0e10cSrcweir else if( IsSelection() )
306cdf0e10cSrcweir {
307cdf0e10cSrcweir SvCacheStream aStream(20480);
308cdf0e10cSrcweir #ifdef OSL_BIGENDIAN
309cdf0e10cSrcweir aStream.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
310cdf0e10cSrcweir #else
311cdf0e10cSrcweir aStream.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
312cdf0e10cSrcweir #endif
313cdf0e10cSrcweir WriterRef xWrt;
314cdf0e10cSrcweir SwReaderWriter::GetWriter( String::CreateFromAscii( FILTER_TEXT ), String(), xWrt );
315cdf0e10cSrcweir if( xWrt.Is() )
316cdf0e10cSrcweir {
317cdf0e10cSrcweir // Selektierte Bereiche in ein ASCII Dokument schreiben
318cdf0e10cSrcweir SwWriter aWriter( aStream, *this);
319cdf0e10cSrcweir xWrt->SetShowProgress( sal_False );
320cdf0e10cSrcweir
321cdf0e10cSrcweir switch( nHndlParaBrk )
322cdf0e10cSrcweir {
323cdf0e10cSrcweir case GETSELTXT_PARABRK_TO_BLANK:
324cdf0e10cSrcweir xWrt->bASCII_ParaAsBlanc = sal_True;
325cdf0e10cSrcweir xWrt->bASCII_NoLastLineEnd = sal_True;
326cdf0e10cSrcweir break;
327cdf0e10cSrcweir
328cdf0e10cSrcweir case GETSELTXT_PARABRK_TO_ONLYCR:
329cdf0e10cSrcweir xWrt->bASCII_ParaAsCR = sal_True;
330cdf0e10cSrcweir xWrt->bASCII_NoLastLineEnd = sal_True;
331cdf0e10cSrcweir break;
332cdf0e10cSrcweir }
333cdf0e10cSrcweir
334cdf0e10cSrcweir //JP 09.05.00: write as UNICODE ! (and not as ANSI)
335cdf0e10cSrcweir SwAsciiOptions aAsciiOpt( xWrt->GetAsciiOptions() );
336cdf0e10cSrcweir aAsciiOpt.SetCharSet( RTL_TEXTENCODING_UCS2 );
337cdf0e10cSrcweir xWrt->SetAsciiOptions( aAsciiOpt );
338cdf0e10cSrcweir xWrt->bUCS2_WithStartChar = sal_False;
339cdf0e10cSrcweir
340cdf0e10cSrcweir long lLen;
341cdf0e10cSrcweir if( !IsError( aWriter.Write( xWrt ) ) &&
342cdf0e10cSrcweir STRING_MAXLEN > (( lLen = aStream.GetSize() )
343cdf0e10cSrcweir / sizeof( sal_Unicode )) + 1 )
344cdf0e10cSrcweir {
345cdf0e10cSrcweir aStream << (sal_Unicode)'\0';
346cdf0e10cSrcweir
347cdf0e10cSrcweir const sal_Unicode *p = (sal_Unicode*)aStream.GetBuffer();
348cdf0e10cSrcweir if( p )
349cdf0e10cSrcweir rBuf = p;
350cdf0e10cSrcweir else
351cdf0e10cSrcweir {
352cdf0e10cSrcweir sal_Unicode* pStrBuf = rBuf.AllocBuffer( xub_StrLen(
353cdf0e10cSrcweir ( lLen / sizeof( sal_Unicode ))) );
354cdf0e10cSrcweir aStream.Seek( 0 );
355cdf0e10cSrcweir aStream.ResetError();
356cdf0e10cSrcweir aStream.Read( pStrBuf, lLen );
357cdf0e10cSrcweir pStrBuf[ lLen / sizeof( sal_Unicode ) ] = '\0';
358cdf0e10cSrcweir }
359cdf0e10cSrcweir }
360cdf0e10cSrcweir }
361cdf0e10cSrcweir }
362cdf0e10cSrcweir
363cdf0e10cSrcweir return sal_True;
364cdf0e10cSrcweir }
365cdf0e10cSrcweir
366cdf0e10cSrcweir
367cdf0e10cSrcweir
368cdf0e10cSrcweir
369cdf0e10cSrcweir
370