source: tags/libIGCM_v2.0_rc1/AA_move-and-rename @ 1137

Last change on this file since 1137 was 731, checked in by sdipsl, 12 years ago
  • bugfix. Need to source libIGCM_config to have access to IGCM_config_CommonConfiguration
  • Property svn:keywords set to Revision Author Date
File size: 16.5 KB
Line 
1#!/bin/ksh
2
3#**************************************************************
4# Author: Martial Mancip
5# Contact: Martial.Mancip__at__ipsl.jussieu.fr
6# $Revision::                                          $ Revision of last commit
7# $Author::                                            $ Author of last commit
8# $Date::                                              $ Date of last commit
9# IPSL (2006)
10#  This software is governed by the CeCILL licence see libIGCM/libIGCM_CeCILL.LIC
11#
12#**************************************************************
13
14#D- Task type (computing or post-processing)
15TaskType=post-processing
16
17# Change SpaceName/ExperimentName/JobName names and path for a simulation during the run.
18# !! Be careful that the job is suspended before using this script !!
19# You may call this script with those four variables already defined, or modify directly
20# default values under here :
21
22# New Name Space of this experience
23NEW_SpaceName=${NEW_SpaceName:=DEVT}
24
25# New Expericence class of the run
26NEW_ExperimentName=${NEW_ExperimentName:=NEWExperimentName}
27
28# New JobName of the run
29NEW_JobName=${NEW_JobName:=NEWJobName}
30
31SUBMIT_DIR=${SUBMIT_DIR:=my_path_to_my_SUBMIT_DIR}
32
33# verbosity
34Verbosity=3
35
36########################################################################
37
38# Path to modipsl
39MODIPSL=${MODIPSL:=::modipsl::}
40
41#D- Path to libIGCM
42#D- Default : value from AA_job if any
43# WARNING For StandAlone use : To run this script on some machine (ulam and cesium)
44# WARNING you must check MirrorlibIGCM variable in sys library.
45# WARNING If this variable is true, you must use libIGCM_POST path instead
46# WARNING of your running libIGCM directory.
47libIGCM=${libIGCM:=::modipsl::/libIGCM}
48
49DEBUG_sys=false
50DEBUG_debug=false
51
52########################################################################
53
54. ${libIGCM}/libIGCM_debug/libIGCM_debug.ksh
55       ( ${DEBUG_debug} ) && IGCM_debug_Check
56. ${libIGCM}/libIGCM_card/libIGCM_card.ksh
57       ( ${DEBUG_debug} ) && IGCM_card_Check
58. ${libIGCM}/libIGCM_date/libIGCM_date.ksh
59       ( ${DEBUG_debug} ) && IGCM_date_Check
60#-------
61. ${libIGCM}/libIGCM_sys/libIGCM_sys.ksh
62. ${libIGCM}/libIGCM_config/libIGCM_config.ksh
63
64########################################################################
65# define local functions
66
67# Function to replace OLD JobName in file
68
69function REPLACE_sed
70{
71    IGCM_debug_PushStack "REPLACE_sed"
72    typeset RET
73   
74    FILEIN=${1}
75    FILEOUT=$( basename ${FILEIN} )
76
77    sed -e "s&${R_SAVE}&${NEW_R_SAVE}&g" -e "s/${config_UserChoices_JobName}/${NEW_JobName}/g" \
78        ${1} > ${RUN_DIR_PATH}/${FILEOUT}
79    RET=$?
80
81    touch --reference=${1} ${RUN_DIR_PATH}/${FILEOUT}
82    IGCM_sys_Mv ${RUN_DIR_PATH}/${FILEOUT} ${2}
83    chmod --reference=${1} ${2}/${FILEOUT}
84
85    IGCM_sys_Rm -f ${1}
86
87    IGCM_debug_Print 3 "REPLACE_sed : ${1} ${2}"
88   
89    IGCM_debug_PopStack "REPLACE_sed"
90    return $RET
91}
92
93function MOVE_and_RENAME_files
94{
95    IGCM_debug_PushStack "MOVE_and_RENAME_files"
96
97    typeset VAR_files FILE_OUT file i RET
98
99    VAR_files=${1}
100    eval VAR1=\${${VAR_files[0]}}
101
102    if [ X$( echo ${NEW_R_SAVE} | grep ${config_UserChoices_JobName} ) != X ]; then
103        set +A FILE_OUT -- $( eval echo \${${VAR_files}[*]} | sed -e "s&${R_SAVE}&${NEW_R_SAVE}&g" )
104        ((i=0))
105        for file in ${FILE_OUT[@]} ; do
106            FILE_OUT[$i]=$( dirname $file )/$( echo $( basename $file ) | sed -e "s/${config_UserChoices_JobName}/${NEW_JobName}/g" )
107            (( i = i + 1 ))
108        done
109    else
110        set +A FILE_OUT -- $( eval echo \${${VAR_files}[*]} | sed -e "s&${R_SAVE}&${NEW_R_SAVE}&g" -e "s/${config_UserChoices_JobName}/${NEW_JobName}/g" )
111    fi
112    IGCM_debug_Print 3 "MOVE_and_RENAME_files all : ${VAR1}"
113    IGCM_debug_Print 3 "    to     ${FILE_OUT}." 
114
115    (( ifile = 0 ))
116    for file_o in ${FILE_OUT[@]} ; do
117        eval IGCM_sys_Mv \${${VAR_files}[${ifile}]} ${file_o}
118        RET=$?
119        (( ifile = ifile + 1 ))
120    done   
121
122    IGCM_debug_PopStack "MOVE_and_RENAME_files"
123    return $RET
124}
125
126function MY_DODS_Cp
127{
128    IGCM_debug_PushStack "MY_DODS_Cp"
129
130    typeset old_JobName old_R_DODS
131    IGCM_sys_Cd ${NEW_R_SAVE}
132    old_JobName=${config_UserChoices_JobName}
133    old_R_DODS=${R_DODS}
134    old_R_SAVE=${R_SAVE}
135
136    config_UserChoices_JobName=${NEW_JobName}
137    R_DODS=${NEW_R_DODS}
138    R_SAVE=${NEW_R_SAVE}
139
140    IGCM_sys_Dods_Cp ${1}
141    IGCM_debug_Print 3 "MY_DODS_Cp : ${config_UserChoices_JobName}/${1}"
142    IGCM_sys_Cd ${RUN_DIR_PATH}
143
144    config_UserChoices_JobName=${old_JobName}
145    R_DODS=${old_R_DODS}
146    R_SAVE=${old_R_SAVE}
147
148    IGCM_debug_PopStack "MY_DODS_Cp"
149}
150
151function MY_DODS_Rm
152{
153    IGCM_debug_PushStack "MY_DODS_Rm"
154    DEBUG_debug=false
155
156    IGCM_sys_Cd ${R_SAVE}
157    IGCM_sys_Dods_Rm ${1}
158    IGCM_debug_Print 3 "MY_DODS_Rm : ${config_UserChoices_JobName}/${1}"
159    IGCM_sys_Cd ${RUN_DIR_PATH}
160
161    IGCM_debug_PopStack "MY_DODS_Rm"
162}
163########################################################################
164
165if [ ! -d ${SUBMIT_DIR} ]; then
166    IGCM_debug_Print 1 "No ${SUBMIT_DIR}, we stop here"
167    exit 1
168fi
169
170# We temporary change ${run_Configuration_PeriodState} to
171if [ -f ${SUBMIT_DIR}/run.card ] ; then
172    IGCM_card_DefineVariableFromOption ${SUBMIT_DIR}/run.card Configuration PeriodState
173    if ( [ ${run_Configuration_PeriodState} != "Start" ] && [ ${run_Configuration_PeriodState} != "Running" ] && [ ${run_Configuration_PeriodState} != "OnQueue" ] && [ ${run_Configuration_PeriodState} != "Continue" ] ) ; then
174        old_run_Configuration_PeriodState=${run_Configuration_PeriodState}
175        IGCM_debug_PrintVariables 2 old_run_Configuration_PeriodState
176        IGCM_card_WriteOption ${SUBMIT_DIR}/run.card Configuration PeriodState "OnQueue"
177    fi
178fi
179
180IGCM_config_Initialize
181
182if [ -f ${SUBMIT_DIR}/run.card ] ; then
183    IGCM_card_DefineVariableFromOption ${SUBMIT_DIR}/run.card Configuration OldPrefix
184    IGCM_debug_PrintVariables 2 run_Configuration_OldPrefix
185    if [ X${old_run_Configuration_PeriodState} != X"Completed" ] ; then
186        DateEnd=$( IGCM_date_ConvertFormatToGregorian $( echo ${run_Configuration_OldPrefix} | awk -F'_' '{print $2}' ) )
187    else
188        DateEnd=$( IGCM_date_ConvertFormatToGregorian ${config_UserChoices_DateEnd} )
189    fi
190else
191    DateEnd=$( IGCM_date_ConvertFormatToGregorian ${config_UserChoices_DateEnd} )
192fi
193
194IGCM_debug_Print 1 ""
195IGCM_debug_Print 1 "DateEnd for MoveJob_Checker : " ${DateEnd}
196IGCM_date_GetYearMonth ${DateEnd}   YearEnd   MonthEnd
197IGCM_debug_Print 1 "YearEnd MonthEnd for TimeSeries_Checker : " ${YearEnd} ${MonthEnd}
198IGCM_debug_Print 1 ""
199
200#set -vx
201
202#====================================================
203#DEFINE NEW_R_SAVE
204if [ X${config_UserChoices_SpaceName} != X ] ; then
205    NEW_SAVE=${config_UserChoices_TagName}/${NEW_SpaceName}
206else
207    NEW_SAVE=${config_UserChoices_TagName}
208fi
209if [ X${config_UserChoices_ExperimentName} != X ] ; then
210    NEW_SAVE=${NEW_SAVE}/${NEW_ExperimentName}
211fi
212
213NEW_R_SAVE=${R_OUT}/${NEW_SAVE}/${NEW_JobName}
214
215IGCM_debug_Print 1 "Move ${R_SAVE} to ${NEW_R_SAVE}"
216if [ -d ${NEW_R_SAVE} ] ; then
217    IGCM_debug_Print 1 "ERROR : ${NEW_R_SAVE} directory already exist !"
218    IGCM_debug_Print 1 "We won't try to  We stop here."
219    exit 1
220fi
221IGCM_sys_MkdirArchive ${NEW_R_SAVE}
222
223# ------------------------------------------------------------------
224# Test if all was right before proceeding further
225# ------------------------------------------------------------------
226IGCM_debug_Verif_Exit_Post
227
228#DEFINE NEW_R_DODS
229NEW_R_DODS=${NEW_SAVE}/${NEW_JobName}
230
231# Define NEW_REBUILD_DIR
232if [ -d ${REBUILD_DIR} ] ; then
233    if [ X${config_Post_RebuildFromArchive} = Xtrue ] ; then
234        NEW_REBUILD_DIR=${NEW_R_SAVE}/TMP
235        IGCM_sys_MkdirArchive ${NEW_REBUILD_DIR}
236    else
237        NEW_REBUILD_DIR=${BIG_DIR}/${config_UserChoices_TagName}/${NEW_JobName}
238        IGCM_sys_MkdirWork ${NEW_REBUILD_DIR}
239    fi
240fi
241
242#====================================================
243# SAVE LOCAL WORKING DIR
244IGCM_sys_Cd ${RUN_DIR_PATH}
245
246#====================================================
247#Exe
248IGCM_debug_Print 1 "Move Exe"
249set +A listfiles -- $( find ${R_SAVE}/Exe -type f )
250
251IGCM_sys_MkdirArchive ${NEW_R_SAVE}/Exe
252MOVE_and_RENAME_files "listfiles"
253
254#====================================================
255#Out
256IGCM_debug_Print 1 "Move Out"
257OutinDir=${R_SAVE}/Out
258OutNEWDir=${NEW_R_SAVE}/Out
259IGCM_sys_MkdirArchive ${OutNEWDir}
260
261# Change JobName and copy run.card
262if [ -f ${OutinDir}/run.card ] ; then
263    sed -e "s/OldPrefix=\ *${config_UserChoices_JobName}/OldPrefix= ${NEW_JobName}/g" \
264        ${OutinDir}/run.card > ${RUN_DIR_PATH}/run.card
265    RET=$?
266    if [ ${RET} = 0 ] ; then
267        IGCM_sys_Mv -f ${RUN_DIR_PATH}/run.card ${OutNEWDir}
268        IGCM_sys_Rm -f ${OutinDir}/run.card
269    fi
270fi
271
272# Just copy historical run.card
273unset listfiles
274set +A listfiles -- $( find ${OutinDir} -type f -name "run.card\.[0-9]*\.[0-9]*" )
275if [ ${#listfiles[*]} -gt 0 ] ; then
276    IGCM_sys_Cp ${listfiles[*]} ${OutNEWDir}
277    RET=$?
278    if [ ${RET} = 0 ] ; then
279        IGCM_sys_Rm -f ${listfiles[*]}
280    fi
281fi
282
283# Move and Rename OLD Script_Output
284unset listfiles
285set +A listfiles -- $( find ${OutinDir} -type f -name "Script_Output_*\.[0-9]*\.[0-9]*" )
286MOVE_and_RENAME_files "listfiles"
287
288# Move and Rename OLD Executable Output
289unset listfiles
290set +A listfiles -- $( find ${OutinDir} -type f -name "*_out_execution" )
291MOVE_and_RENAME_files "listfiles"
292
293#====================================================
294IGCM_debug_Print 1 "For components"
295IGCM_debug_Print 1 "=============="
296
297#====================================================
298#Output
299# loop over components and frequencies
300IGCM_debug_Print 1 "Move Output"
301for comp in ${config_ListOfComponents[*]} ; do
302    IGCM_debug_Print 2 "------------------"
303    IGCM_debug_Print 2 "for component ${comp}"
304
305    unset FREQDIR
306    set +A FREQDIR -- $( find ${R_SAVE}/${comp}/Output -type d -not -name "*Output" )
307
308    IGCM_debug_Print 3 "List of WriteFrequencies : ${FREQDIR[*]}"
309
310    for ThisfreqDir in ${FREQDIR[*]} ; do
311        freq=$( basename ${ThisfreqDir} )
312        IGCM_debug_Print 2 "${freq}."
313
314        NEW_freqDir=${NEW_R_SAVE}/${comp}/Output/${freq}
315        IGCM_sys_MkdirArchive ${NEW_freqDir}
316
317        unset listfiles
318        set +A listfiles -- $( find ${ThisfreqDir} -type f )
319       
320        MOVE_and_RENAME_files "listfiles"
321    done
322
323    unset COMPFILES
324    set +A COMPFILES -- $( find ${R_SAVE}/${comp}/Output -type f )
325   
326    if [ ${#COMPFILES[*]} -gt 0 ] ; then
327        IGCM_debug_Print 2 "simple Output FILES : ${COMPFILES[*]}."
328
329        MOVE_and_RENAME_files "COMPFILES"
330    fi
331done
332
333#====================================================
334#Restart
335# loop over components
336IGCM_debug_Print 1 "Move Restart"
337for comp in ${config_ListOfComponents[*]} ; do
338    IGCM_debug_Print 2 "------------------"
339    IGCM_debug_Print 2 "for component ${comp}"
340
341    ThisRestDir=${R_SAVE}/${comp}/Restart
342    NEW_RestDir=${NEW_R_SAVE}/${comp}/Restart
343    IGCM_sys_MkdirArchive ${NEW_RestDir}
344
345    unset listfiles
346    set +A listfiles -- $( find ${ThisRestDir} -type f )
347   
348    MOVE_and_RENAME_files "listfiles"
349done
350
351#====================================================
352#DEBUG
353# Move and Rename OLD Executable Output
354# loop over components
355IGCM_debug_Print 1 "Move Debug"
356for comp in ${config_ListOfComponents[*]} ; do
357    IGCM_debug_Print 2 "------------------"
358    IGCM_debug_Print 2 "for component ${comp}"
359
360    ThisDebugDir=${R_SAVE}/${comp}/Debug
361    NEW_DebugDir=${NEW_R_SAVE}/${comp}/Debug
362    IGCM_sys_MkdirArchive ${NEW_DebugDir}
363
364    unset listfiles
365    set +A listfiles -- $( find ${ThisDebugDir} -type f )
366   
367    MOVE_and_RENAME_files "listfiles"
368done
369
370#====================================================
371#POST
372# loop over components and frequencies
373IGCM_debug_Print 1 "Move Analyse"
374for comp in ${config_ListOfComponents[*]} ; do
375    IGCM_debug_Print 2 "------------------"
376    IGCM_debug_Print 2 "for component ${comp}"
377   
378    if [ -d ${R_SAVE}/${comp}/Analyse ] ; then
379        unset TSDIR
380        set +A TSDIR -- $( find ${R_SAVE}/${comp}/Analyse -name "TS_*" -type d )
381       
382        for ThisTSDir in ${TSDIR[*]} ; do
383            TS_Dir=$( basename ${ThisTSDir} )
384            IGCM_debug_Print 2 "${TS_Dir}."
385           
386            NEW_TSDir=${NEW_R_SAVE}/${comp}/Analyse/${TS_Dir}
387            IGCM_sys_MkdirArchive ${NEW_TSDir}
388           
389            MY_DODS_Rm ${comp}/Analyse/${TS_Dir}
390           
391            unset listfiles
392            set +A listfiles -- $( find ${ThisTSDir} -type f )
393           
394            MOVE_and_RENAME_files "listfiles"
395           
396            MY_DODS_Cp ${comp}/Analyse/${TS_Dir}
397        done
398
399        ThisSEDir=${R_SAVE}/${comp}/Analyse/SE
400        IGCM_sys_TestDirArchive ${ThisSEDir}
401        if [ $? = 0 ] ; then
402            IGCM_debug_Print 2 "SE."
403            NEW_SEDir=${NEW_R_SAVE}/${comp}/Analyse/SE
404            IGCM_sys_MkdirArchive ${NEW_SEDir}
405           
406            MY_DODS_Rm ${comp}/Analyse/SE
407           
408            unset listfiles
409            set +A listfiles -- $( find ${ThisSEDir} -type f )
410           
411            MOVE_and_RENAME_files "listfiles"
412           
413            MY_DODS_Cp ${comp}/Analyse/SE
414        fi
415
416        MY_DODS_Rm ${comp}/Analyse
417        MY_DODS_Rm ${comp}
418    else
419        IGCM_debug_Print 2 "nothing to do without Analyse."
420    fi
421
422done
423
424#====================================================
425#GRAPHS
426IGCM_debug_Print 1 "Move ATLAS"
427R_ATLAS=ATLAS
428IGCM_sys_TestDirArchive ${R_SAVE}/${R_ATLAS}
429if [ $? = 0 ] ; then
430#    REPLACE_sed ${NEW_R_SAVE}/${R_ATLAS}/*/*/index.html ${NEW_R_SAVE}/${R_ATLAS}
431
432    MY_DODS_Rm ${R_ATLAS}
433
434    IGCM_sys_Mv ${R_SAVE}/${R_ATLAS} ${NEW_R_SAVE}/${R_ATLAS}
435
436    MY_DODS_Cp ${R_ATLAS}
437fi
438
439IGCM_debug_Print 1 "Move MONITORING"
440R_MONITORING=MONITORING
441IGCM_sys_TestDirArchive ${R_SAVE}/${R_MONITORING}
442if [ $? = 0 ] ; then
443    IGCM_sys_MkdirArchive ${NEW_R_SAVE}/${R_MONITORING}
444    REPLACE_sed ${R_SAVE}/${R_MONITORING}/index.html ${NEW_R_SAVE}/${R_MONITORING}
445    sed -e "s/OldPrefix=\ *${config_UserChoices_JobName}/OldPrefix= ${NEW_JobName}/g" \
446        ${R_SAVE}/${R_MONITORING}/run.card > ${RUN_DIR_PATH}/run.card
447    IGCM_sys_Mv -f ${RUN_DIR_PATH}/run.card ${NEW_R_SAVE}/${R_MONITORING}
448    RET=$?
449    if [ ${RET} = 0 ] ; then
450        IGCM_sys_Rm -f ${R_SAVE}/${R_MONITORING}/run.card
451    fi
452    REPLACE_sed ${R_SAVE}/${R_MONITORING}/config.card ${NEW_R_SAVE}/${R_MONITORING}
453    IGCM_sys_Cp -rp ${R_SAVE}/${R_MONITORING} ${NEW_R_SAVE}
454
455    MY_DODS_Rm ${R_MONITORING}
456    IGCM_sys_Rm -rf ${R_SAVE}/${R_MONITORING}
457
458    MY_DODS_Cp ${R_MONITORING}
459fi
460
461
462#====================================================
463#REBUILD
464
465if [ -d ${REBUILD_DIR} ] ; then
466
467    IGCM_debug_Print 1 "Move REBUILD"
468    set +A LISTREBUILDS -- $( find ${REBUILD_DIR} -type d  -not -name "*${config_UserChoices_JobName}" -a -not -name "*TMP" )
469
470    for ThisREBDir in ${LISTREBUILDS[*]} ; do
471        rebdir=$( basename ${ThisREBDir} )
472        IGCM_debug_Print 2 "${rebdir}."
473        if [ X${config_Post_RebuildFromArchive} = Xtrue ] ; then
474            IGCM_sys_MkdirArchive ${NEW_REBUILD_DIR}/${rebdir}
475        else
476            IGCM_sys_MkdirWork ${NEW_REBUILD_DIR}/${rebdir}
477        fi
478        REPLACE_sed ${REBUILD_DIR}/${rebdir}/rebuild.ksh ${NEW_REBUILD_DIR}/${rebdir}
479        IGCM_sys_Mv -f ${REBUILD_DIR}/${rebdir}/* ${NEW_REBUILD_DIR}/${rebdir}/
480    done
481fi
482
483#====================================================
484#List OLD R_SAVE and Ask for erase it !
485
486IGCM_debug_Print 1 "ls of SAVE DIR :"
487ls --color -lR ${R_SAVE}
488
489echo "\033[1;31mPlease verify that ALL OLD DIRECTORY LISTED IS COMPLETLY EMPTY !"
490echo "\033[1;32mIf It is NOT EMPTY, you can TRY AGAIN this script."
491echo "\033[1;31mDo you REALLY want to erase all this directory ?"
492echo -n " Your answer (y/n) : \033[m"
493if [ X${reponse} = X ] ; then
494    read reponse
495fi
496case ${reponse} in
497           
498    oui|OUI|o|y|yes|YES)
499        echo "OK. It will be erased."
500        IGCM_sys_Rm -Rf ${R_SAVE}
501        echo "done."
502        ;;
503    non|NON|n|no|NO)
504        echo "Nothing to do !"
505        ;;
506esac
507
508
509#############################################################################################################
510# Edit config.card, run.card and Job_${NewJobName}
511
512IGCM_debug_Print 1 "edit config.card"
513if [ X${config_UserChoices_SpaceName} != X ] ; then
514    IGCM_card_WriteOption ${SUBMIT_DIR}/config.card UserChoices SpaceName ${NEW_SpaceName}
515fi
516if [ X${config_UserChoices_ExperimentName} != X ] ; then
517    IGCM_card_WriteOption ${SUBMIT_DIR}/config.card UserChoices ExperimentName ${NEW_ExperimentName}
518fi
519IGCM_card_WriteOption ${SUBMIT_DIR}/config.card UserChoices JobName ${NEW_JobName}
520
521if [ -f ${SUBMIT_DIR}/run.card ] ; then
522    IGCM_debug_Print 1 "edit run.card"
523    sed -e "s/OldPrefix=\ *${config_UserChoices_JobName}/OldPrefix= ${NEW_JobName}/g" \
524        ${SUBMIT_DIR}/run.card > ${RUN_DIR_PATH}/run.card
525    IGCM_sys_Mv -f ${RUN_DIR_PATH}/run.card ${SUBMIT_DIR}/run.card
526
527    if [ X${old_run_Configuration_PeriodState} != X ] ; then
528        IGCM_card_WriteOption ${SUBMIT_DIR}/run.card Configuration PeriodState ${old_run_Configuration_PeriodState}
529    fi
530fi
531
532if [ -f ${SUBMIT_DIR}/Job_${config_UserChoices_JobName} ] ; then
533    IGCM_debug_Print 1 "edit Job_${NEW_JobName}"
534    sed -e "s&${R_SAVE}&${NEW_R_SAVE}&g" -e "s/${config_UserChoices_JobName}/${NEW_JobName}/g" \
535        ${SUBMIT_DIR}/Job_${config_UserChoices_JobName} > ${SUBMIT_DIR}/Job_${NEW_JobName}
536    chmod --reference=${SUBMIT_DIR}/Job_${config_UserChoices_JobName} ${SUBMIT_DIR}/Job_${NEW_JobName}
537    ls -la ${SUBMIT_DIR}/Job_${NEW_JobName}
538fi
Note: See TracBrowser for help on using the repository browser.