Changeset 6676 for TOOLS/WATER_BUDGET/libIGCM_sys.py
- Timestamp:
- 11/15/23 16:41:21 (8 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
TOOLS/WATER_BUDGET/libIGCM_sys.py
r6652 r6676 24 24 ''' 25 25 26 import sys, os, subprocess, configparser, re, types26 import os, subprocess, configparser, types 27 27 from pathlib import Path 28 28 … … 30 30 SysName, NodeName, Release, Version, Machine = os.uname () 31 31 32 def unDefined (char) :33 '''Returns True if a variable is not defined, ot if it's set to None'''34 if char in globals () :35 if globals ()[char] == None or globals ()[char] == 'None': unDefined = True36 else : unDefined = False37 else : unDefined = True38 return unDefined39 40 def Mach ( Long=False) :32 # def unDefined (char) : 33 # '''Returns True if a variable is not defined, ot if it's set to None''' 34 # if char in globals () : 35 # if globals ()[char] == None or globals ()[char] == 'None': unDefined = True 36 # else : unDefined = False 37 # else : unDefined = True 38 # return unDefined 39 40 def Mach ( long=False) : 41 41 ''' 42 42 Find the computer we are on 43 43 44 On Irene, Mach returns Irene, Irene-Next, Rome or Rome-Prev if Long==True44 On Irene, Mach returns Irene, Irene-Next, Rome or Rome-Prev if long==True 45 45 ''' 46 47 Mach = 'unknown'48 49 if SysName == 'Darwin' and 'lsce5138' in NodeName : Mach = 'Spip'50 if 'obelix' in NodeName : Mach = 'Obelix'51 if 'forge' in NodeName : Mach = 'Forge'52 if 'ciclad' in NodeName : Mach = 'Ciclad'53 if 'climserv' in NodeName : Mach = 'SpiritX'54 if 'spirit' in NodeName : Mach = 'SpiritJ'55 if 'spiritj' in NodeName : Mach = 'SpiritJ'56 if 'spiritx' in NodeName : Mach = 'SpiritX'57 if 'irene' in NodeName : Mach = 'Irene'58 if 'jean-zay' in NodeName : Mach = 'Jean-Zay'59 60 if Long :61 MachFull = Mach62 63 if Mach == 'Irene' :46 47 zmach = None 48 49 if SysName == 'Darwin' and 'lsce5138' in NodeName : zmach = 'Spip' 50 if 'obelix' in NodeName : zmach = 'Obelix' 51 if 'forge' in NodeName : zmach = 'Forge' 52 if 'ciclad' in NodeName : zmach = 'Ciclad' 53 if 'climserv' in NodeName : zmach = 'SpiritX' 54 if 'spirit' in NodeName : zmach = 'SpiritJ' 55 if 'spiritj' in NodeName : zmach = 'SpiritJ' 56 if 'spiritx' in NodeName : zmach = 'SpiritX' 57 if 'irene' in NodeName : zmach = 'Irene' 58 if 'jean-zay' in NodeName : zmach = 'Jean-Zay' 59 60 if long : 61 zmachfull = zmach 62 63 if zmach == 'Irene' : 64 64 CPU = subprocess.getoutput ('lscpu') 65 65 ccc_os = subprocess.getoutput ('ccc_os') 66 66 67 67 if "Intel(R) Xeon(R) Platinum" in CPU : 68 if "Atos_7__x86_64" in ccc_os : MachFull = 'Irene-Prev' 69 if "Rhel_8__x86_64" in ccc_os : MachFull = 'Irene' 70 71 if "AMD" in CPU : 72 if "Atos_7__x86_64" in ccc_os : MachFull = 'Rome-Prev' 73 if "Rhel_8__x86_64" in ccc_os : MachFull = 'Rome' 74 75 Mach = MachFull 76 77 return Mach 68 zmachfull = 'Irene' 69 70 if "AMD" in CPU : 71 zmachfull = 'Rome' 72 73 zmach = zmachfull 74 75 return zmach 78 76 79 77 def config ( JobName=None , TagName=None , SpaceName=None, ExperimentName=None, … … 81 79 Source=None , Host=None , ConfigCard=None, User=None, Group=None, 82 80 TGCC_User='p86mart', TGCC_Group='gen12006', IDRIS_User='rces009', IDRIS_Group='ces', 83 ARCHIVE=None, SCRATCHDIR=None, STORAGE=None, R_IN=None, R_OUT=None, R_FIG=None, L_EXP=None, 84 R_SAVE=None , R_FIGR=None, R_BUF=None , R_BUFR=None, R_BUF_KSH=None, REBUILD_DIR=None, POST_DIR=None, 85 ThreddsPrefix=None, R_GRAF=None, DB=None, 81 ARCHIVE=None, SCRATCHDIR=None, STORAGE=None, R_IN=None, R_OUT=None, 82 R_FIG=None, L_EXP=None, 83 R_SAVE=None , R_FIGR=None, R_BUF=None , R_BUFR=None, R_BUF_KSH=None, 84 REBUILD_DIR=None, POST_DIR=None, 85 ThreddsPrefix=None, R_GRAF=None, DB=None, 86 86 IGCM_OUT=None, IGCM_OUT_name=None, rebuild=None, TmpDir=None, 87 87 Out='dict') : … … 90 90 91 91 Source : for Spip 92 Possibilities : 92 Possibilities : 93 93 Local : local (~/Data/IGCMG/...) 94 94 TGCC_sshfs : TGCC disks mounted via sshfs 95 TGCC_thredds : thredds TGCC via IPSL ('https://thredds-su.ipsl.fr/thredds/dodsC/tgcc_thredds/store/...) 95 TGCC_thredds : thredds TGCC via IPSL 96 ('https://thredds-su.ipsl.fr/thredds/dodsC/tgcc_thredds/store/...) 96 97 97 98 Exemple of use : … … 104 105 # else : IGCM_OUT_name = 'IGCM_OUT' 105 106 106 if not Host : Host = Mach ( Long=False)107 if not Host : Host = Mach (long=False) 107 108 108 109 LocalUser = os.environ ['USER'] 109 110 110 111 # =========================================================================================== 111 112 # Reads config.card if available … … 118 119 MyReader = configparser.ConfigParser (interpolation=configparser.ExtendedInterpolation() ) 119 120 MyReader.optionxform = str # To keep capitals 120 121 121 122 MyReader.read (ConfigCard) 122 123 123 124 JobName = MyReader['UserChoices']['JobName'] 124 125 #----- Short Name of Experiment … … 130 131 TagName = MyReader['UserChoices']['TagName'] 131 132 132 ### =========================================================================================== 133 ### =========================================================================================== 133 134 ## Part specific to access by OpenDAP/Thredds server 134 135 … … 138 139 if not Group and TGCC_Group : Group = TGCC_Group 139 140 140 if not ThreddsPrefix : ThreddsPrefix = 'https://thredds-su.ipsl.fr/thredds/dodsC/tgcc_thredds' 141 141 if not ThreddsPrefix : 142 ThreddsPrefix = 'https://thredds-su.ipsl.fr/thredds/dodsC/tgcc_thredds' 143 142 144 if not ARCHIVE : ARCHIVE = f'{ThreddsPrefix}/store/{TGCC_User}' 143 145 if not R_FIG : R_FIG = f'{ThreddsPrefix}/work/{TGCC_User}' … … 149 151 if not User and IDRIS_User : User = IDRIS_User 150 152 if not Group and IDRIS_Group : Group = IDRIS_Group 151 152 if not ThreddsPrefix : ThreddsPrefix = 'https://thredds-su.ipsl.fr/thredds/catalog/idris_thredds' 153 153 154 if not ThreddsPrefix : 155 ThreddsPrefix = 'https://thredds-su.ipsl.fr/thredds/catalog/idris_thredds' 156 154 157 if not ARCHIVE : ARCHIVE = f'{ThreddsPrefix}/store/{IDRIS_User}' 155 158 if not R_FIG : R_FIG = f'{ThreddsPrefix}/work/{IDRIS_User}' 156 159 if not R_IN : R_IN = f'{ThreddsPrefix}/work/igcmg/IGCM' 157 if not R_GRAF : R_GRAF = f'https://thredds-su.ipsl.fr/thredds/dodsC/tgcc_thredds/work/p86mart/GRAF/DATA' 158 159 ### =========================================================================================== 160 if not R_GRAF : R_GRAF = \ 161 'https://thredds-su.ipsl.fr/thredds/dodsC/tgcc_thredds/work/p86mart/GRAF/DATA' 162 163 ### =========================================================================================== 160 164 ## Machine dependant part 161 165 … … 177 181 # =========================================================================================== 178 182 if ( 'Irene' in Host ) or ( 'Rome' in Host ) : 179 LocalHome = subprocess.getoutput ( f'ccc_home --ccchome' ) 183 184 LocalHome = subprocess.getoutput ( 'ccc_home --ccchome' ) 180 185 LocalGroup = os.path.basename ( os.path.dirname (LocalHome)) 181 186 if not User or User == 'marti' : 182 187 if not TGCC_User : User = LocalUser 183 188 else : User = TGCC_User 184 189 185 190 if not Group : 186 191 if TGCC_Group : Group = TGCC_Group … … 188 193 189 194 IGCM_OUT_name = 'IGCM_OUT' 190 191 if not R_IN : R_IN = os.path.join ( subprocess.getoutput ( f'ccc_home --cccwork -d igcmg -u igcmg' ), 'IGCM') 192 if not ARCHIVE : ARCHIVE = subprocess.getoutput ( f'ccc_home --cccstore -u {User} -d {Group}' ) 193 if not STORAGE : STORAGE = subprocess.getoutput ( f'ccc_home --cccwork -u {User} -d {Group}' ) 194 if not SCRATCHDIR : SCRATCHDIR = subprocess.getoutput ( f'ccc_home --cccscratch -u {User} -d {Group}' ) 195 if not R_BUF : R_BUF = subprocess.getoutput ( f'ccc_home --cccscratch -u {User} -d {Group}' ) 196 if not R_FIG : R_FIG = subprocess.getoutput ( f'ccc_home --cccwork -u {User} -d {Group}' ) 197 if not R_GRAF : R_GRAF = os.path.join ( subprocess.getoutput ( f'ccc_home --cccwork -d drf -u p86mart'), 'GRAF', 'DATA' ) 198 if not DB : DB = os.path.join ( subprocess.getoutput ( f'ccc_home --cccwork -d igcmg -u igcmg'), 'database' ) 195 196 if not R_IN : 197 R_IN = os.path.join ( subprocess.getoutput ( 198 'ccc_home --cccwork -d igcmg -u igcmg' ), 'IGCM') 199 if not ARCHIVE : 200 ARCHIVE = subprocess.getoutput ( 201 f'ccc_home --cccstore -u {User} -d {Group}' ) 202 if not STORAGE : 203 STORAGE = subprocess.getoutput ( 204 f'ccc_home --cccwork -u {User} -d {Group}' ) 205 if not SCRATCHDIR : 206 SCRATCHDIR = subprocess.getoutput ( 207 f'ccc_home --cccscratch -u {User} -d {Group}' ) 208 if not R_BUF : 209 R_BUF = subprocess.getoutput ( 210 f'ccc_home --cccscratch -u {User} -d {Group}' ) 211 if not R_FIG : 212 R_FIG = subprocess.getoutput ( 213 f'ccc_home --cccwork -u {User} -d {Group}' ) 214 if not R_GRAF : 215 R_GRAF = os.path.join ( subprocess.getoutput ( 216 'ccc_home --cccwork -d drf -u p86mart'), 'GRAF', 'DATA' ) 217 if not DB : 218 DB = os.path.join ( subprocess.getoutput ( 219 'ccc_home --cccwork -d igcmg -u igcmg'), 'database' ) 199 220 if not rebuild : 200 rebuild = os.path.join ( subprocess.getoutput ( f'ccc_home --ccchome -d igcmg -u igcmg' ), 'Tools', Machine, 'rebuild_nemo', 'bin', 'rebuild_nemo' ) 221 rebuild = os.path.join ( 222 subprocess.getoutput ( 'ccc_home --ccchome -d igcmg -u igcmg' ), 223 'Tools', 'irene', 'rebuild_nemo', 'bin', 'rebuild_nemo' ) 224 201 225 if not TmpDir : TmpDir = subprocess.getoutput ( f'ccc_home --cccscratch' ) 202 226 203 227 # =========================================================================================== 204 228 if Host == 'SpiritJ' : … … 206 230 if TGCC_User : User = TGCC_User 207 231 else : User = LocalUser 208 if not ARCHIVE : ARCHIVE = os.path.join ( '/', 'thredds' , 'tgcc', 'store', User ) 209 if not STORAGE : STORAGE = os.path.join ( '/', 'thredds' , 'tgcc', 'work' , User ) 232 if not ARCHIVE : 233 ARCHIVE = os.path.join ( '/', 'thredds', 'tgcc', 'store', User ) 234 if not STORAGE : 235 STORAGE = os.path.join ( '/', 'thredds', 'tgcc', 'work' , User ) 210 236 #if not SCRATCHDIR : SCRATCHDIR = os.path.join ( '/', 'thredds' , 'tgcc', 'store', User ) 211 if not R_IN : R_IN = os.path.join ( '/', 'projsu', 'igcmg', 'IGCM' ) 237 if not R_IN : 238 R_IN = os.path.join ( '/', 'projsu', 'igcmg', 'IGCM' ) 212 239 #if not R_GRAF : R_GRAF = os.path.join ('/', 'data', 'omamce', 'GRAF', 'DATA' ) 213 if not R_GRAF : R_GRAF = os.path.join ( '/', 'thredds' , 'tgcc', 'work' , 'p86mart', 'GRAF', 'DATA' ) 214 if not DB : DB = os.path.join ( '/', 'data', 'igcmg', 'database' ) 215 if not TmpDir : TmpDir = os.path.join ( '/', 'data', LocalUser ) 216 240 if not R_GRAF : 241 R_GRAF = os.path.join ( '/', 'thredds', 'tgcc', 'work', 'p86mart', 'GRAF', 'DATA' ) 242 if not DB : 243 DB = os.path.join ( '/', 'data', 'igcmg', 'database' ) 244 if not TmpDir : 245 TmpDir = os.path.join ( '/', 'data', LocalUser ) 246 217 247 # =========================================================================================== 218 248 if Host == 'SpiritX' : … … 220 250 if TGCC_User : User = TGCC_User 221 251 else : User = os.environ ['USER'] 222 if not ARCHIVE : ARCHIVE = os.path.join ( '/', 'thredds' , 'tgcc', 'store', User ) 223 if not STORAGE : STORAGE = os.path.join ( '/', 'thredds' , 'tgcc', 'work' , User ) 224 #if not SCRATCHDIR : SCRATCHDIR = os.path.join ( '/', 'thredds' , 'tgcc', 'store', User ) 225 if not R_IN : R_IN = os.path.join ( '/', 'projsu', 'igcmg', 'IGCM' ) 226 #if not R_GRAF : R_GRAF = os.path.join ('/', 'data', 'omamce', 'GRAF', 'DATA' ) 227 if not R_GRAF : R_GRAF = os.path.join ( '/', 'thredds' , 'tgcc', 'work' , 'p86mart', 'GRAF', 'DATA' ) 228 if not DB : DB = os.path.join ( '/', 'data', 'igcmg', 'database' ) 252 if not ARCHIVE : 253 ARCHIVE = os.path.join ( '/', 'thredds', 'tgcc', 'store', User ) 254 if not STORAGE : 255 STORAGE = os.path.join ( '/', 'thredds', 'tgcc', 'work' , User ) 256 #if not SCRATCHDIR : 257 # SCRATCHDIR = os.path.join ( '/', 'thredds', 'tgcc', 'store', User ) 258 if not R_IN : 259 R_IN = os.path.join ( '/', 'projsu', 'igcmg', 'IGCM' ) 260 #if not R_GRAF : 261 # R_GRAF = os.path.join ('/', 'data', 'omamce', 'GRAF', 'DATA' ) 262 if not R_GRAF : 263 R_GRAF = os.path.join ( '/', 'thredds', 'tgcc', 'work' , 'p86mart', 'GRAF', 'DATA' ) 264 if not DB : 265 DB = os.path.join ( '/', 'data', 'igcmg', 'database' ) 229 266 230 267 # =========================================================================================== … … 233 270 LocalGroup = os.path.basename ( os.path.dirname ( Path.home () )) 234 271 if not Group : Group = LocalGroup 235 236 if not ARCHIVE : ARCHIVE = os.path.join ( '/', 'gpfsstore' , 'rech', Group, User ) 237 if not STORAGE : STORAGE = os.path.join ( '/', 'gpfswork' , 'rech', Group, User ) 238 if not SCRATCHDIR : SCRATCHDIR = os.path.join ( '/', 'gpfsscratch', 'rech', Group, User ) 239 if not R_FIG : R_FIG = os.path.join ( '/', 'cccwork' , 'rech', Group, User ) 240 if not R_BUF : R_BUF = os.path.join ( '/', 'gpfsscratch', 'rech', Group, User ) 241 if not R_IN : R_IN = os.path.join ( '/', 'gpfswork' , 'rech', 'psl', 'commun', 'IGCM' ) 242 if not R_GRAF : R_GRAF = os.path.join ( '/', 'gpfswork' , 'rech', Group, User, 'GRAF', 'DATA' ) 243 if not DB : DB = os.path.join ( '/', 'gpfswork' , 'rech', 'psl', 'commun', 'database' ) 272 273 if not ARCHIVE : 274 ARCHIVE = os.path.join ( '/', 'gpfsstore' , 'rech', Group, User ) 275 if not STORAGE : 276 STORAGE = os.path.join ( '/', 'gpfswork' , 'rech', Group, User ) 277 if not SCRATCHDIR : 278 SCRATCHDIR = os.path.join ( '/', 'gpfsscratch', 'rech', Group, User ) 279 if not R_FIG : 280 R_FIG = os.path.join ( '/', 'cccwork' , 'rech', Group, User ) 281 if not R_BUF : 282 R_BUF = os.path.join ( '/', 'gpfsscratch', 'rech', Group, User ) 283 if not R_IN : 284 R_IN = os.path.join ( '/', 'gpfswork' , 'rech', 'psl', 'commun', 'IGCM' ) 285 if not R_GRAF : 286 R_GRAF = os.path.join ( '/', 'gpfswork' , 'rech', Group, User, 'GRAF', 'DATA' ) 287 if not DB : 288 DB = os.path.join ( '/', 'gpfswork' , 'rech', 'psl', 'commun', 'database' ) 244 289 if not rebuild : 245 rebuild = os.path.join ( '/', 'gpfswork', 'rech', 'psl', 'commun', 'Tools', 'rebuild', 'modipsl_IOIPSL_PLUS_v2_2_4', 'bin', 'rebuild' ) 246 if not TmpDir : TmpDir = os.path.join ( '/', 'gpfsscratch', 'rech', os.path.basename ( os.path.dirname ( Path.home () )), LocalUser ) 247 248 ### =========================================================================================== 290 rebuild = os.path.join ( '/', 'gpfswork', 'rech', 'psl', 'commun', 'Tools', 291 'rebuild', 'modipsl_IOIPSL_PLUS_v2_2_4', 'bin', 'rebuild' ) 292 if not TmpDir : TmpDir = os.path.join ( '/', 'gpfsscratch', 'rech', 293 os.path.basename ( os.path.dirname ( Path.home () )), LocalUser ) 294 295 ### =========================================================================================== 249 296 ### The construction of the following variables is not machine dependant 250 ### =========================================================================================== 297 ### =========================================================================================== 251 298 if SpaceName == 'TEST' : 252 if SCRATCHDIR and not R_OUT : SCRATCHDIR253 if SCRATCHDIR and not R_FIG : SCRATCHDIR299 if SCRATCHDIR and not R_OUT : R_OUT = SCRATCHDIR 300 if SCRATCHDIR and not R_FIG : R_FIG = SCRATCHDIR 254 301 else : 255 302 if ARCHIVE and not R_OUT : R_OUT = ARCHIVE 256 303 if STORAGE and not R_FIG : R_FIG = STORAGE 257 304 if IGCM_OUT_name : 258 259 260 305 R_OUT = os.path.join ( R_OUT, IGCM_OUT_name ) 306 R_FIG = os.path.join ( R_FIG, IGCM_OUT_name ) 307 261 308 if SCRATCHDIR and not R_BUF : R_BUF = os.path.join ( SCRATCHDIR, IGCM_OUT_name ) 262 309 if not IGCM_OUT : IGCM_OUT = R_OUT 263 310 264 311 if TagName and SpaceName and ExperimentName and JobName : 265 L_EXP = os.path.join ( TagName, SpaceName, ExperimentName, JobName )266 312 if not L_EXP : L_EXP = os.path.join ( TagName, SpaceName, ExperimentName, JobName ) 313 267 314 if R_OUT and not R_SAVE : R_SAVE = os.path.join ( R_OUT , L_EXP ) 268 if IGCM_OUT_name : 315 if IGCM_OUT_name : 269 316 if STORAGE and not R_FIGR : R_FIGR = os.path.join ( STORAGE, IGCM_OUT_name, L_EXP ) 270 317 else : 271 if STORAGE and not R_FIGR : R_FIGR = os.path.join ( STORAGE, L_EXP )318 if STORAGE and not R_FIGR : R_FIGR = os.path.join ( STORAGE, L_EXP ) 272 319 if R_BUF and not R_BUFR : R_BUFR = os.path.join ( R_BUF , L_EXP ) 273 320 if R_BUFR and not R_BUF_KSH : R_BUF_KSH = os.path.join ( R_BUFR , 'Out' ) … … 275 322 if R_BUF and not POST_DIR : POST_DIR = os.path.join ( R_BUF , L_EXP, 'Out' ) 276 323 277 ### =========================================================================================== 324 ### =========================================================================================== 278 325 ## Builds the final dictionnary 279 326 280 libIGCM = { 'TagName' : TagName , 'SpaceName' : SpaceName, 'ExperimentName': ExperimentName, 'JobName':JobName, 281 'LongName': LongName, 'ModelName' : ModelName, 'ShortName' : ShortName , 'ConfigCard' : ConfigCard, 282 'ARCHIVE' : ARCHIVE , 'STORAGE' : STORAGE , 'SCRATCHDIR' : SCRATCHDIR , 283 'R_OUT' : R_OUT , 'R_BUF' : R_BUFR , 'R_GRAF' : R_GRAF , 'DB' : DB, 284 'IGCM_OUT': IGCM_OUT, 'R_SAVE' : R_SAVE , 'R_FIGR' : R_FIGR , 'R_BUFR': R_BUFR, 'REBUILD_DIR': REBUILD_DIR, 285 'POST_DIR': POST_DIR, 'R_IN' : R_IN , 'Mach' : Host , 'Source': Source, 286 'User' : User , 'Group' : Group , 'IGCM_OUT_name' : IGCM_OUT_name, 'rebuild':rebuild, 'TmpDir':TmpDir, 287 'TGCC_User':TGCC_User, 'TGCC_Group':TGCC_Group, 'Thredds' : ThreddsPrefix, 288 'IDRIS_User':IDRIS_User, 'IDRIS_Group':IDRIS_Group } 327 libIGCM = { 'TagName' : TagName , 328 'SpaceName' : SpaceName , 329 'ExperimentName': ExperimentName, 330 'JobName' : JobName , 331 'LongName' : LongName , 332 'ModelName' : ModelName , 333 'ShortName' : ShortName, 334 'ConfigCard' : ConfigCard, 335 'ARCHIVE' : ARCHIVE , 336 'STORAGE' : STORAGE , 337 'SCRATCHDIR' : SCRATCHDIR , 338 'R_OUT' : R_OUT , 339 'R_BUF' : R_BUFR , 340 'R_GRAF' : R_GRAF , 341 'DB' : DB , 342 'IGCM_OUT' : IGCM_OUT , 343 'R_SAVE' : R_SAVE , 344 'R_FIGR' : R_FIGR , 345 'R_BUFR' : R_BUFR, 346 'REBUILD_DIR' : REBUILD_DIR, 347 'POST_DIR' : POST_DIR , 348 'R_IN' : R_IN , 349 'Mach' : Host , 350 'Source' : Source , 351 'User' : User , 352 'Group' : Group, 353 'IGCM_OUT_name' : IGCM_OUT_name, 354 'rebuild' : rebuild, 355 'TmpDir' : TmpDir, 356 'TGCC_User' : TGCC_User, 357 'TGCC_Group' : TGCC_Group, 358 'Thredds' : ThreddsPrefix, 359 'IDRIS_User' : IDRIS_User, 360 'IDRIS_Group' : IDRIS_Group } 289 361 290 362 if Out in ['namespace', 'space', 'name', 'Space', 'Name', 'Names', 'NameSpace'] : 291 363 libIGCM = types.SimpleNamespace (**libIGCM) 292 364 293 365 return libIGCM 294
Note: See TracChangeset
for help on using the changeset viewer.