@@ -634,8 +634,9 class Spectra(JROData): | |||||
634 | return freqrange |
|
634 | return freqrange | |
635 |
|
635 | |||
636 | def getAcfRange(self, extrapoints=0): |
|
636 | def getAcfRange(self, extrapoints=0): | |
637 |
|
637 | #print "miay",self.ippFactor | ||
638 | deltafreq = 10. / (self.getFmax() / (self.nFFTPoints * self.ippFactor)) |
|
638 | deltafreq = 10. / (self.getFmax() / (self.nFFTPoints * self.ippFactor)) | |
|
639 | #print deltafreq | |||
639 | freqrange = deltafreq * \ |
|
640 | freqrange = deltafreq * \ | |
640 | (numpy.arange(self.nFFTPoints + extrapoints) - |
|
641 | (numpy.arange(self.nFFTPoints + extrapoints) - | |
641 | self.nFFTPoints / 2.) - deltafreq / 2 |
|
642 | self.nFFTPoints / 2.) - deltafreq / 2 |
@@ -234,10 +234,10 class ACFPlot(Figure): | |||||
234 | self.isConfig = False |
|
234 | self.isConfig = False | |
235 | self.__nsubplots = 1 |
|
235 | self.__nsubplots = 1 | |
236 |
|
236 | |||
237 |
self.PLOT_CODE = |
|
237 | self.PLOT_CODE = ACF_CODE | |
238 |
|
238 | |||
239 |
self.WIDTH = |
|
239 | self.WIDTH = 900 | |
240 |
self.HEIGHT = |
|
240 | self.HEIGHT = 700 | |
241 | self.counter_imagwr = 0 |
|
241 | self.counter_imagwr = 0 | |
242 |
|
242 | |||
243 | def getSubplots(self): |
|
243 | def getSubplots(self): | |
@@ -266,7 +266,8 class ACFPlot(Figure): | |||||
266 | for x in range(ncol): |
|
266 | for x in range(ncol): | |
267 | self.addAxes(nrow, ncol*ncolspan, y, x*ncolspan, colspan, 1) |
|
267 | self.addAxes(nrow, ncol*ncolspan, y, x*ncolspan, colspan, 1) | |
268 |
|
268 | |||
269 | def run(self, dataOut, id, wintitle="", channelList=None, |
|
269 | def run(self, dataOut, id, wintitle="", channelList=None,channel=None,nSamples=None, | |
|
270 | nSampleList= None,resolutionFactor=None, | |||
270 | xmin=None, xmax=None, ymin=None, ymax=None, |
|
271 | xmin=None, xmax=None, ymin=None, ymax=None, | |
271 | save=False, figpath='./', figfile=None, show=True, |
|
272 | save=False, figpath='./', figfile=None, show=True, | |
272 | ftp=False, wr_period=1, server=None, |
|
273 | ftp=False, wr_period=1, server=None, | |
@@ -274,6 +275,25 class ACFPlot(Figure): | |||||
274 | xaxis="frequency"): |
|
275 | xaxis="frequency"): | |
275 |
|
276 | |||
276 |
|
277 | |||
|
278 | channel0 = channel | |||
|
279 | nSamples = nSamples | |||
|
280 | resFactor = resolutionFactor | |||
|
281 | ||||
|
282 | if nSamples == None: | |||
|
283 | nSamples = 20 | |||
|
284 | ||||
|
285 | if resFactor == None: | |||
|
286 | resFactor = 5 | |||
|
287 | #else: | |||
|
288 | # if nSamples not in dataOut.channelList: | |||
|
289 | # raise ValueError, "Channel %d is not in %s dataOut.channelList"%(channel0, dataOut.channelList) | |||
|
290 | ||||
|
291 | if channel0 == None: | |||
|
292 | channel0 = 0 | |||
|
293 | else: | |||
|
294 | if channel0 not in dataOut.channelList: | |||
|
295 | raise ValueError, "Channel %d is not in %s dataOut.channelList"%(channel0, dataOut.channelList) | |||
|
296 | ||||
277 | if channelList == None: |
|
297 | if channelList == None: | |
278 | channelIndexList = dataOut.channelIndexList |
|
298 | channelIndexList = dataOut.channelIndexList | |
279 | channelList = dataOut.channelList |
|
299 | channelList = dataOut.channelList | |
@@ -284,53 +304,70 class ACFPlot(Figure): | |||||
284 | raise ValueError, "Channel %d is not in dataOut.channelList" |
|
304 | raise ValueError, "Channel %d is not in dataOut.channelList" | |
285 | channelIndexList.append(dataOut.channelList.index(channel)) |
|
305 | channelIndexList.append(dataOut.channelList.index(channel)) | |
286 |
|
306 | |||
|
307 | #z = dataOut.data_spc/factor | |||
287 | factor = dataOut.normFactor |
|
308 | factor = dataOut.normFactor | |
288 |
|
||||
289 | y = dataOut.getHeiRange() |
|
309 | y = dataOut.getHeiRange() | |
290 |
|
||||
291 | #z = dataOut.data_spc/factor |
|
|||
292 |
deltaHeight = dataOut.heightList[1] |
|
310 | deltaHeight = dataOut.heightList[1]-dataOut.heightList[0] | |
293 | print deltaHeight |
|
311 | z = dataOut.data_acf | |
294 | z = dataOut.data_spc |
|
|||
295 |
|
||||
296 | #z = numpy.where(numpy.isfinite(z), z, numpy.NAN) |
|
312 | #z = numpy.where(numpy.isfinite(z), z, numpy.NAN) | |
297 |
shape |
|
313 | shape = dataOut.data_acf.shape | |
|
314 | hei_index = numpy.arange(shape[2]) | |||
|
315 | hei_plot = numpy.arange(nSamples)*resFactor | |||
|
316 | #print hei_plot | |||
|
317 | #import matplotlib.pyplot as plt | |||
|
318 | #c=z[0,:,0]*15+15 | |||
|
319 | #plt.plot(c) | |||
|
320 | #plt.show() | |||
|
321 | #print "HOLA# | |||
|
322 | ||||
|
323 | if nSampleList is not None: | |||
|
324 | for nsample in nSampleList: | |||
|
325 | if nsample not in dataOut.heightList/deltaHeight: | |||
|
326 | raise ValueError, "nsample %d is not in %s dataOut.heightList"%(nsample,dataOut.heightList) | |||
|
327 | ||||
|
328 | if nSampleList is not None: | |||
|
329 | hei_plot = numpy.array(nSampleList)*resFactor | |||
|
330 | ||||
|
331 | if hei_plot[-1] >= hei_index[-1]: | |||
|
332 | print ("La cantidad de puntos en altura es %d y la resolucion es %d Km"%(hei_plot.shape[0],deltaHeight*resFactor )) | |||
|
333 | raise ValueError, "resFactor %d multiplicado por el valor de %d nSamples es mayor a %d cantidad total de puntos"%(resFactor,nSamples,hei_index[-1]) | |||
|
334 | ||||
|
335 | #escalamiento -1 a 1 a resolucion (factor de resolucion en altura)* deltaHeight | |||
|
336 | min = numpy.min(z[0,:,0]) | |||
|
337 | max =numpy.max(z[0,:,0]) | |||
|
338 | ||||
298 | for i in range(shape[0]): |
|
339 | for i in range(shape[0]): | |
299 | for j in range(shape[2]): |
|
340 | for j in range(shape[2]): | |
300 |
z[i,:,j]= (z[i,:,j] |
|
341 | z[i,:,j]= (((z[i,:,j]-min)/(max-min))*deltaHeight*resFactor + j*deltaHeight) | |
301 | #z[i,:,j]= (z[i,:,j]+1.0)*deltaHeight*dataOut.step/2.0 + j*deltaHeight*dataOut.step |
|
342 | #z[i,:,j]= (z[i,:,j]+1.0)*deltaHeight*dataOut.step/2.0 + j*deltaHeight*dataOut.step | |
302 |
|
343 | |||
303 | hei_index = numpy.arange(shape[2]) |
|
344 | #print deltaHeight | |
304 |
#print |
|
345 | #print resFactor | |
305 | #b = [] |
|
346 | #print numpy.max(z[0,:,0]) | |
306 | #for i in range(hei_index.shape[0]): |
|
347 | #import matplotlib.pyplot as plt | |
307 | # if hei_index[i]%30 == 0: |
|
348 | #plt.plot((z[0,:,0])*deltaHeight) | |
308 | # b.append(hei_index[i]) |
|
349 | #plt.show() | |
309 |
|
350 | |||
310 | #hei_index= numpy.array(b) |
|
|||
311 | hei_index = hei_index[300:320] |
|
|||
312 | #hei_index = numpy.arange(20)*30+80 |
|
|||
313 | hei_index= numpy.arange(20)*5 |
|
|||
314 | if xaxis == "frequency": |
|
351 | if xaxis == "frequency": | |
315 | x = dataOut.getFreqRange()/1000. |
|
352 | x = dataOut.getFreqRange()/1000. | |
316 |
zdB = 10*numpy.log10(z[0,:,hei_ |
|
353 | zdB = 10*numpy.log10(z[channel0,:,hei_plot]) | |
317 | xlabel = "Frequency (kHz)" |
|
354 | xlabel = "Frequency (kHz)" | |
318 | ylabel = "Power (dB)" |
|
355 | ylabel = "Power (dB)" | |
319 |
|
356 | |||
320 | elif xaxis == "time": |
|
357 | elif xaxis == "time": | |
321 | x = dataOut.getAcfRange() |
|
358 | x = dataOut.getAcfRange() | |
322 |
zdB = z[0,:,hei_ |
|
359 | zdB = z[channel0,:,hei_plot] | |
323 | xlabel = "Time (ms)" |
|
360 | xlabel = "Time (ms)" | |
324 | ylabel = "ACF" |
|
361 | ylabel = "ACF" | |
325 |
|
362 | |||
326 | else: |
|
363 | else: | |
327 | x = dataOut.getVelRange() |
|
364 | x = dataOut.getVelRange() | |
328 |
zdB = 10*numpy.log10(z[0,:,hei_ |
|
365 | zdB = 10*numpy.log10(z[channel0,:,hei_plot]) | |
329 | xlabel = "Velocity (m/s)" |
|
366 | xlabel = "Velocity (m/s)" | |
330 | ylabel = "Power (dB)" |
|
367 | ylabel = "Power (dB)" | |
331 |
|
368 | |||
332 | thisDatetime = datetime.datetime.utcfromtimestamp(dataOut.getTimeRange()[0]) |
|
369 | thisDatetime = datetime.datetime.utcfromtimestamp(dataOut.getTimeRange()[0]) | |
333 | title = wintitle + " ACF Plot %s" %(thisDatetime.strftime("%d-%b-%Y")) |
|
370 | title = wintitle + " ACF Plot Ch %s %s" %(channel0,thisDatetime.strftime("%d-%b-%Y")) | |
334 |
|
371 | |||
335 | if not self.isConfig: |
|
372 | if not self.isConfig: | |
336 |
|
373 | |||
@@ -346,14 +383,18 class ACFPlot(Figure): | |||||
346 | if ymin == None: ymin = numpy.nanmin(zdB) |
|
383 | if ymin == None: ymin = numpy.nanmin(zdB) | |
347 | if ymax == None: ymax = numpy.nanmax(zdB) |
|
384 | if ymax == None: ymax = numpy.nanmax(zdB) | |
348 |
|
385 | |||
|
386 | print ("El parametro resFactor es %d y la resolucion en altura es %d"%(resFactor,deltaHeight )) | |||
|
387 | print ("La cantidad de puntos en altura es %d y la nueva resolucion es %d Km"%(hei_plot.shape[0],deltaHeight*resFactor )) | |||
|
388 | print ("La altura maxima es %d Km"%(hei_plot[-1]*deltaHeight )) | |||
|
389 | ||||
349 | self.isConfig = True |
|
390 | self.isConfig = True | |
350 |
|
391 | |||
351 | self.setWinTitle(title) |
|
392 | self.setWinTitle(title) | |
352 |
|
393 | |||
353 |
title = " |
|
394 | title = "ACF Plot: %s" %(thisDatetime.strftime("%d-%b-%Y %H:%M:%S")) | |
354 | axes = self.axesList[0] |
|
395 | axes = self.axesList[0] | |
355 |
|
396 | |||
356 |
legendlabels = ["Range = %dKm" %y[i] for i in hei_ |
|
397 | legendlabels = ["Range = %dKm" %y[i] for i in hei_plot] | |
357 |
|
398 | |||
358 | axes.pmultilineyaxis( x, zdB, |
|
399 | axes.pmultilineyaxis( x, zdB, | |
359 | xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, |
|
400 | xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, | |
@@ -363,6 +404,13 class ACFPlot(Figure): | |||||
363 |
|
404 | |||
364 | self.draw() |
|
405 | self.draw() | |
365 |
|
406 | |||
|
407 | if figfile == None: | |||
|
408 | str_datetime = thisDatetime.strftime("%Y%m%d_%H%M%S") | |||
|
409 | name = str_datetime | |||
|
410 | if ((dataOut.azimuth!=None) and (dataOut.zenith!=None)): | |||
|
411 | name = name + '_az' + '_%2.2f'%(dataOut.azimuth) + '_zn' + '_%2.2f'%(dataOut.zenith) | |||
|
412 | figfile = self.getFilename(name) | |||
|
413 | ||||
366 | self.save(figpath=figpath, |
|
414 | self.save(figpath=figpath, | |
367 | figfile=figfile, |
|
415 | figfile=figfile, | |
368 | save=save, |
|
416 | save=save, |
@@ -12,7 +12,7 TOTAL_CODE = 6 #Total Power. | |||||
12 | DRIFT_CODE = 7 #Drifts graphics. |
|
12 | DRIFT_CODE = 7 #Drifts graphics. | |
13 | HEIGHT_CODE = 8 #Height profile. |
|
13 | HEIGHT_CODE = 8 #Height profile. | |
14 | PHASE_CODE = 9 #Signal Phase. |
|
14 | PHASE_CODE = 9 #Signal Phase. | |
15 |
A |
|
15 | ACF_CODE = 10 #Autocorrelation function. | |
16 |
|
16 | |||
17 | POWER_CODE = 16 |
|
17 | POWER_CODE = 16 | |
18 | NOISE_CODE = 17 |
|
18 | NOISE_CODE = 17 |
@@ -65,7 +65,7 class SpectraProc(ProcessingUnit): | |||||
65 | self.dataOut.beam.azimuthList = self.dataIn.beam.azimuthList |
|
65 | self.dataOut.beam.azimuthList = self.dataIn.beam.azimuthList | |
66 | self.dataOut.beam.zenithList = self.dataIn.beam.zenithList |
|
66 | self.dataOut.beam.zenithList = self.dataIn.beam.zenithList | |
67 |
|
67 | |||
68 | self.dataOut.step = self.dataIn.step |
|
68 | self.dataOut.step = self.dataIn.step # | |
69 |
|
69 | |||
70 | def __getFft(self): |
|
70 | def __getFft(self): | |
71 | """ |
|
71 | """ | |
@@ -87,10 +87,8 class SpectraProc(ProcessingUnit): | |||||
87 |
|
87 | |||
88 | # calculo de self-spectra |
|
88 | # calculo de self-spectra | |
89 | fft_volt = numpy.fft.fftshift(fft_volt, axes=(1,)) |
|
89 | fft_volt = numpy.fft.fftshift(fft_volt, axes=(1,)) | |
90 | #print "spec dtype 0",fft_volt.dtype |
|
|||
91 | spc = fft_volt * numpy.conjugate(fft_volt) |
|
90 | spc = fft_volt * numpy.conjugate(fft_volt) | |
92 | spc = spc.real |
|
91 | spc = spc.real | |
93 | #print "spec dtype 1",spc.dtype |
|
|||
94 |
|
92 | |||
95 | blocksize = 0 |
|
93 | blocksize = 0 | |
96 | blocksize += dc.size |
|
94 | blocksize += dc.size | |
@@ -127,10 +125,7 class SpectraProc(ProcessingUnit): | |||||
127 |
|
125 | |||
128 | if self.dataIn.type == "Spectra": |
|
126 | if self.dataIn.type == "Spectra": | |
129 | self.dataOut.copy(self.dataIn) |
|
127 | self.dataOut.copy(self.dataIn) | |
130 | # if not pairsList: |
|
128 | print "hi",self.dataOut.ippSeconds | |
131 | # pairsList = itertools.combinations(self.dataOut.channelList, 2) |
|
|||
132 | # if self.dataOut.data_cspc is not None: |
|
|||
133 | # self.__selectPairs(pairsList) |
|
|||
134 | if shift_fft: |
|
129 | if shift_fft: | |
135 | #desplaza a la derecha en el eje 2 determinadas posiciones |
|
130 | #desplaza a la derecha en el eje 2 determinadas posiciones | |
136 | shift = int(self.dataOut.nFFTPoints/2) |
|
131 | shift = int(self.dataOut.nFFTPoints/2) | |
@@ -164,16 +159,11 class SpectraProc(ProcessingUnit): | |||||
164 | self.dataIn.heightList.shape[0]), |
|
159 | self.dataIn.heightList.shape[0]), | |
165 | dtype='complex') |
|
160 | dtype='complex') | |
166 |
|
161 | |||
167 | #print self.buffer.shape,"spec2" |
|
162 | ||
168 | #print self.dataIn.heightList.shape[0],"spec3" |
|
|||
169 |
|
163 | |||
170 | if self.dataIn.flagDataAsBlock: |
|
164 | if self.dataIn.flagDataAsBlock: | |
171 | # data dimension: [nChannels, nProfiles, nSamples] |
|
|||
172 | nVoltProfiles = self.dataIn.data.shape[1] |
|
165 | nVoltProfiles = self.dataIn.data.shape[1] | |
173 | # nVoltProfiles = self.dataIn.nProfiles |
|
|||
174 |
|
166 | |||
175 | #print nVoltProfiles,"spec1" |
|
|||
176 | #print nProfiles |
|
|||
177 | if nVoltProfiles == nProfiles: |
|
167 | if nVoltProfiles == nProfiles: | |
178 | self.buffer = self.dataIn.data.copy() |
|
168 | self.buffer = self.dataIn.data.copy() | |
179 | self.profIndex = nVoltProfiles |
|
169 | self.profIndex = nVoltProfiles | |
@@ -196,7 +186,6 class SpectraProc(ProcessingUnit): | |||||
196 | else: |
|
186 | else: | |
197 | self.buffer[:, self.profIndex, :] = self.dataIn.data.copy() |
|
187 | self.buffer[:, self.profIndex, :] = self.dataIn.data.copy() | |
198 | self.profIndex += 1 |
|
188 | self.profIndex += 1 | |
199 | #print self.profIndex,"spectra D" |
|
|||
200 |
|
189 | |||
201 | if self.firstdatatime == None: |
|
190 | if self.firstdatatime == None: | |
202 | self.firstdatatime = self.dataIn.utctime |
|
191 | self.firstdatatime = self.dataIn.utctime |
@@ -99,16 +99,11 class SpectraAFCProc(ProcessingUnit): | |||||
99 | dc = fft_volt[:,0,:] |
|
99 | dc = fft_volt[:,0,:] | |
100 |
|
100 | |||
101 | #calculo de self-spectra |
|
101 | #calculo de self-spectra | |
102 | # fft_volt = numpy.fft.fftshift(fft_volt, axes=(1,)) |
|
|||
103 | spc = fft_volt * numpy.conjugate(fft_volt) |
|
102 | spc = fft_volt * numpy.conjugate(fft_volt) | |
104 |
|
||||
105 |
|
||||
106 | data = numpy.fft.ifft(spc, axis=1) |
|
103 | data = numpy.fft.ifft(spc, axis=1) | |
107 | data = numpy.fft.fftshift(data, axes=(1,)) |
|
104 | data = numpy.fft.fftshift(data, axes=(1,)) | |
108 |
|
105 | |||
109 |
spc = data |
|
106 | spc = data | |
110 |
|
||||
111 |
|
||||
112 |
|
107 | |||
113 | blocksize = 0 |
|
108 | blocksize = 0 | |
114 | blocksize += dc.size |
|
109 | blocksize += dc.size | |
@@ -145,29 +140,31 class SpectraAFCProc(ProcessingUnit): | |||||
145 |
|
140 | |||
146 | if self.dataIn.type == "Spectra": |
|
141 | if self.dataIn.type == "Spectra": | |
147 | self.dataOut.copy(self.dataIn) |
|
142 | self.dataOut.copy(self.dataIn) | |
|
143 | #print "hi",self.dataOut.ippSeconds | |||
|
144 | ||||
148 | spc= self.dataOut.data_spc |
|
145 | spc = self.dataOut.data_spc | |
149 | data = numpy.fft.ifft(spc, axis=1) |
|
146 | data = numpy.fft.ifft(spc, axis=1) | |
150 | data = numpy.fft.fftshift(data, axes=(1,)) |
|
147 | data = numpy.fft.fftshift(data, axes=(1,)) | |
151 | spc = data.real |
|
148 | acf = numpy.abs(data) # Autocorrelacion LLAMAR A ESTE VALOR ACF | |
152 | shape = spc.shape #nchannels, nprofiles, nsamples |
|
149 | #acf = data.imag | |
|
150 | shape = acf.shape #nchannels, nprofiles, nsamples | |||
153 |
|
151 | |||
154 | #print spc.shape |
|
|||
155 | for i in range(shape[0]): |
|
|||
156 | for j in range(shape[2]): |
|
|||
157 | spc[i,:,j]= spc[i,:,j] / numpy.max(numpy.abs(spc[i,:,j])) |
|
|||
158 | #spc = spc[0,:,250] / numpy.max(numpy.abs(spc[0,:,250])) |
|
|||
159 | #print spc.shape |
|
|||
160 | #import matplotlib.pyplot as plt |
|
152 | #import matplotlib.pyplot as plt | |
161 | #print spc[0:10] |
|
153 | #plt.plot(acf[0,:,0] / numpy.max(numpy.abs(acf[0,:,0]))) | |
162 | #plt.plot(spc[0,:,350]) |
|
|||
163 | #plt.show() |
|
154 | #plt.show() | |
164 |
|
155 | |||
|
156 | # Normalizando | |||
|
157 | for i in range(shape[0]): | |||
|
158 | for j in range(shape[2]): | |||
|
159 | acf[i,:,j]= acf[i,:,j] / numpy.max(numpy.abs(acf[i,:,j])) | |||
165 |
|
160 | |||
166 | self.dataOut.data_spc = spc |
|
161 | #import matplotlib.pyplot as plt | |
|
162 | #plt.plot(acf[0,:,0]) | |||
|
163 | #plt.show() | |||
167 |
|
164 | |||
|
165 | self.dataOut.data_acf = acf | |||
168 | return True |
|
166 | return True | |
169 |
|
167 | |||
170 |
|
||||
171 | if code is not None: |
|
168 | if code is not None: | |
172 | self.code = numpy.array(code).reshape(nCode,nBaud) |
|
169 | self.code = numpy.array(code).reshape(nCode,nBaud) | |
173 | else: |
|
170 | else: |
@@ -1248,8 +1248,8 class SSheightProfiles(Operation): | |||||
1248 | deltaHeight = dataOut.heightList[1] - dataOut.heightList[0] |
|
1248 | deltaHeight = dataOut.heightList[1] - dataOut.heightList[0] | |
1249 | ippSeconds = (deltaHeight*1.0e-6)/(0.15) |
|
1249 | ippSeconds = (deltaHeight*1.0e-6)/(0.15) | |
1250 |
|
1250 | |||
1251 |
|
1251 | #print "hi",dataOut.ippSeconds | ||
1252 |
|
1252 | #print ippSeconds | ||
1253 | dataOut.data = self.sshProfiles |
|
1253 | dataOut.data = self.sshProfiles | |
1254 | dataOut.flagNoData = False |
|
1254 | dataOut.flagNoData = False | |
1255 | dataOut.heightList = numpy.arange(self.buffer.shape[1]) *self.step*deltaHeight + dataOut.heightList[0] |
|
1255 | dataOut.heightList = numpy.arange(self.buffer.shape[1]) *self.step*deltaHeight + dataOut.heightList[0] | |
@@ -1258,6 +1258,7 class SSheightProfiles(Operation): | |||||
1258 | dataOut.flagDataAsBlock = True |
|
1258 | dataOut.flagDataAsBlock = True | |
1259 | dataOut.ippSeconds = ippSeconds |
|
1259 | dataOut.ippSeconds = ippSeconds | |
1260 | dataOut.step = self.step |
|
1260 | dataOut.step = self.step | |
|
1261 | #print dataOut.ippSeconds | |||
1261 |
|
1262 | |||
1262 |
|
1263 | |||
1263 | # import collections |
|
1264 | # import collections |
General Comments 0
You need to be logged in to leave comments.
Login now