Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
vig
Sublinear Algorithms for VA
pseudo
Commits
b41c932e
Commit
b41c932e
authored
Sep 01, 2020
by
Kruyff,D.L.W. (Dylan)
Browse files
Redo lost changes
parent
8d4ead19
Changes
322
Expand all
Hide whitespace changes
Inline
Side-by-side
.gitignore
View file @
b41c932e
Documents/
AngularApp/prototype/node_modules
\ No newline at end of file
AngularApp/prototype/node_modules
Flaskserver/venv/*
\ No newline at end of file
AngularApp/prototype/package-lock.json
View file @
b41c932e
...
...
@@ -16420,6 +16420,25 @@
"cwise-compiler": "^1.0.0"
}
},
"zingchart": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/zingchart/-/zingchart-2.9.1.tgz",
"integrity": "sha512-LYCiqkzdDn5OxPqShfvUNcTtXxVgZDVqEztGINBb0EA9a1b1TOrLbW/BdJPpeobBahXSxvHYLO6NV/Dbw309Vw=="
},
"zingchart-angular": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/zingchart-angular/-/zingchart-angular-1.0.0.tgz",
"integrity": "sha512-T55KMk/1k5pcQ5sxTx0RTzIElbkJKWbvfgLTLiqaLz7kobrGLHxuNNS9Oya36p2Oaq/CxtoYFnCpM2V+zFd9Wg==",
"requires": {
"tslib": "^1.9.0",
"zingchart": "^2.9.1",
"zingchart-constants": "github:zingchart/zingchart-constants#master"
}
},
"zingchart-constants": {
"version": "github:zingchart/zingchart-constants#2cb0b3a55bbae8ee6fb943161fdd5b71618bc95f",
"from": "github:zingchart/zingchart-constants#master"
},
"zone.js": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz",
...
...
AngularApp/prototype/package.json
View file @
b41c932e
...
...
@@ -25,6 +25,7 @@
"plotly.js"
:
"^1.54.6"
,
"rxjs"
:
"~6.5.4"
,
"tslib"
:
"^1.10.0"
,
"zingchart-angular"
:
"^1.0.0"
,
"zone.js"
:
"~0.10.2"
},
"devDependencies"
:
{
...
...
AngularApp/prototype/src/app/api.service.ts
View file @
b41c932e
...
...
@@ -32,19 +32,21 @@ export class ApiService {
},
body
:
JSON
.
stringify
(
postData
)
});
return
(
await
response
.
json
()
).
data
;
return
await
response
.
json
();
}
// Generate LSH-tables by hashing each window
async
createTables
(
windows
,
parameters
):
Promise
<
any
>
{
console
.
log
(
"
creating tables
"
);
const
postData
=
{
windows
,
parameters
};
console
.
log
(
"
ahh
"
);
const
response
=
await
fetch
(
'
http://127.0.0.1:5000/create-tables
'
,
{
method
:
'
POST
'
,
headers
:
{
'
Accept
'
:
'
application/json
'
,
'
Content-Type
'
:
'
application/json
'
},
body
:
JSON
.
stringify
(
postData
)
body
:
new
Blob
(
[
JSON
.
stringify
(
postData
)
],
{
type
:
'
text/plain
'
}
)
});
return
await
response
.
json
();
}
...
...
@@ -70,7 +72,7 @@ export class ApiService {
'
Accept
'
:
'
application/json
'
,
'
Content-Type
'
:
'
application/json
'
},
body
:
JSON
.
stringify
(
postData
)
body
:
new
Blob
(
[
JSON
.
stringify
(
postData
)
],
{
type
:
'
text/plain
'
}
)
});
return
await
response
.
json
();
}
...
...
AngularApp/prototype/src/app/app.module.ts
View file @
b41c932e
...
...
@@ -14,6 +14,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import
{
MatTabsModule
}
from
'
@angular/material/tabs
'
;
import
{
LabelsComponent
}
from
'
./labels/labels.component
'
;
import
{
QueryWindowComponent
}
from
'
./query-window/query-window.component
'
;
import
{
ZingchartAngularModule
}
from
'
zingchart-angular
'
;
PlotlyModule
.
plotlyjs
=
PlotlyJS
;
...
...
@@ -32,7 +33,8 @@ PlotlyModule.plotlyjs = PlotlyJS;
FormsModule
,
PlotlyModule
,
BrowserAnimationsModule
,
MatTabsModule
MatTabsModule
,
ZingchartAngularModule
],
providers
:
[],
bootstrap
:
[
AppComponent
]
...
...
AngularApp/prototype/src/app/cache.service.ts
View file @
b41c932e
...
...
@@ -15,9 +15,10 @@ export class CacheService {
private
_tables
;
private
_windowSimilarity
;
public
windowSize
=
6
0
;
public
windowSize
=
20
0
;
public
nrOfTables
=
10
;
public
hashSize
=
10
;
public
hashSize
=
5
;
public
stepSize
=
1
;
public
onNewSimilarity
:
EventEmitter
<
void
>
=
new
EventEmitter
<
void
>
();
public
onNewLabels
:
EventEmitter
<
void
>
=
new
EventEmitter
<
void
>
();
...
...
@@ -130,7 +131,8 @@ export class CacheService {
return
{
windowsize
:
this
.
windowSize
,
hashsize
:
this
.
hashSize
,
tablesize
:
this
.
nrOfTables
tablesize
:
this
.
nrOfTables
,
stepsize
:
this
.
stepSize
};
}
}
AngularApp/prototype/src/app/labeling-window/labeling-window.component.ts
View file @
b41c932e
...
...
@@ -94,6 +94,9 @@ export class LabelingWindowComponent implements OnInit {
titlefont
:
{
size
:
9
},
xaxis
:
{
showticklabels
:
false
,
}
}
}
);
...
...
AngularApp/prototype/src/app/overview-window/overview-window.component.html
View file @
b41c932e
<div
style=
"overflow: auto"
>
<plotly-plot
*ngIf=
"showPlot"
[data]=
"data"
[layout]=
"layout"
(plotly_click)=
"clicked($event)"
></plotly-plot>
<!--
<plotly-plot *ngIf="showPlot" [data]="data" [layout]="layout" (plotly_click)="clicked($event)"></plotly-plot>
-->
</div>
<zingchart-angular
[config]=
"config"
[height]=
"500"
[series]=
"series"
(node_click)=
"clicked($event)"
></zingchart-angular>
AngularApp/prototype/src/app/overview-window/overview-window.component.ts
View file @
b41c932e
import
{
ChangeDetectorRef
,
Component
,
OnInit
}
from
'
@angular/core
'
;
import
{
Component
}
from
'
@angular/core
'
;
import
{
CacheService
}
from
'
../cache.service
'
;
import
{
throwError
}
from
'
rxjs
'
;
@
Component
({
selector
:
'
app-overview-window
'
,
templateUrl
:
'
./overview-window.component.html
'
,
styleUrls
:
[
'
./overview-window.component.css
'
]
})
export
class
OverviewWindowComponent
implements
OnInit
{
public
defaultColors
:
string
[];
public
defaultSizes
:
number
[];
public
defaultOpacity
:
number
[];
export
class
OverviewWindowComponent
{
public
config
;
public
series
;
public
showPlot
=
false
;
public
data
;
public
layout
;
constructor
(
private
service
:
CacheService
)
{
}
constructor
(
private
service
:
CacheService
)
{
}
async
ngOnInit
():
Promise
<
void
>
{
this
.
service
.
onNewWindows
.
subscribe
(()
=>
{
this
.
initializePlot
();
});
...
...
@@ -29,46 +28,73 @@ export class OverviewWindowComponent implements OnInit {
async
initializePlot
()
{
this
.
service
.
query
=
undefined
;
const
size
=
this
.
service
.
raw
Values
.
length
;
this
.
defaultColors
=
Array
(
size
).
fill
(
'
#a3a7e4
'
)
;
this
.
defaultSizes
=
Array
(
size
).
fill
(
5
);
this
.
d
efaultOpacity
=
Array
(
size
).
fill
(
1
)
;
this
.
data
=
[
{
x
:
this
.
service
.
raw
Indices
,
y
:
this
.
service
.
rawValues
,
type
:
'
scattergl
'
,
// mode: 'markers'
,
// marker
: {
// size: this.defaultSizes.slice()
,
// color: this.defaultColors.slice()}
}];
this
.
layout
=
{
hovermode
:
'
closest
'
,
autosize
:
true
,
margin
:
{
l
:
40
,
r
:
0
,
b
:
40
,
t
:
0
,
pad
:
4
// this.data
= this.service.raw
Indices.map((e, i) => {
// return [e, values[i]]
;
// }
);
this
.
d
ata
=
[]
;
for
(
let
i
=
0
;
i
<
this
.
service
.
rawValues
.
length
;
i
++
)
{
this
.
data
.
push
([
i
,
this
.
service
.
raw
Values
[
i
]]);
}
this
.
config
=
{
type
:
"
mixed
"
,
preview
:
{
'
auto-fit
'
:
true
,
handleTop
:
{
alpha
:
0.0
},
handleBottom
:
{
alpha
:
0.0
}
}
,
'
scale-x
'
:
{
zooming
:
true
,
zoomTo
:
[
0
,
this
.
service
.
windowSize
],
'
auto-fit
'
:
true
},
height
:
200
,
xaxis
:
{
showticklabels
:
false
,
// rangeslider: {}
'
scale-y
'
:
{
zooming
:
true
,
'
auto-fit
'
:
true
},
series
:
[
{
type
:
'
line
'
,
values
:
this
.
data
,
text
:
'
Raw Values
'
,
zIndex
:
5
,
marker
:
{
alpha
:
0.0
,
zIndex
:
10
}
},
{
type
:
'
scatter
'
,
values
:
[],
text
:
'
Good labels
'
,
marker
:
{
backgroundColor
:
'
#4caf50
'
},
zIndex
:
20
,
},
{
type
:
'
scatter
'
,
values
:
[],
text
:
'
Bad labels
'
,
marker
:
{
backgroundColor
:
'
#f44336
'
},
zIndex
:
20
,
}]
};
this
.
showPlot
=
true
;
console
.
log
(
"
showing plot
"
);
}
async
clicked
(
clickData
)
{
for
(
const
point
of
clickData
.
points
)
{
this
.
service
.
query
=
point
.
pointNumber
;
const
temp
=
{}
;
temp
[
point
.
pointNumber
]
=
true
;
this
.
service
.
labels
=
t
emp
;
}
console
.
log
(
'
clicked node
'
);
const
index
=
Math
.
floor
(
clickData
.
nodeindex
/
this
.
service
.
stepSize
)
;
this
.
service
.
query
=
index
;
const
temp
=
{}
;
temp
[
index
]
=
t
rue
;
this
.
service
.
labels
=
temp
;
await
this
.
updatePlot
();
}
...
...
@@ -79,29 +105,71 @@ export class OverviewWindowComponent implements OnInit {
// Similarity
const
windowSimilarity
=
await
this
.
service
.
getSimilarWindows
(
this
.
service
.
windows
[
this
.
service
.
query
]);
for
(
const
frequency
in
windowSimilarity
){
for
(
const
index
of
windowSimilarity
[
frequency
])
{
colors
[
index
]
=
this
.
getColor
(
Number
(
frequency
)
/
this
.
service
.
nrOfTables
);
sizes
[
index
]
=
5
;
opacity
[
index
]
=
Math
.
max
(
Number
(
frequency
)
/
this
.
service
.
nrOfTables
,
0.5
);
}
}
// Labeled
console
.
log
(
windowSimilarity
);
// for (const frequency in windowSimilarity){
// for (const index of windowSimilarity[frequency]) {
// colors[index] = this.getColor(Number(frequency) / this.service.nrOfTables);
// sizes[index] = 5;
// opacity[index] = Math.max(Number(frequency) / this.service.nrOfTables, 0.5);
// }
// }
let
goodLabels
=
[];
let
badLabels
=
[];
for
(
const
index
in
this
.
service
.
labels
)
{
colors
[
Number
(
index
)]
=
this
.
service
.
labels
[
index
]
?
'
#4caf50
'
:
'
#f44336
'
;
sizes
[
Number
(
index
)]
=
10
;
opacity
[
Number
(
index
)]
=
1
;
console
.
log
(
index
);
if
(
this
.
service
.
labels
[
index
])
{
goodLabels
.
push
(
this
.
data
[
index
]);
}
else
{
badLabels
.
push
(
this
.
data
[
index
]);
}
}
console
.
log
(
goodLabels
);
console
.
log
(
badLabels
);
this
.
series
=
[
{
type
:
'
line
'
,
values
:
this
.
data
,
text
:
'
Raw Values
'
,
zIndex
:
5
,
marker
:
{
alpha
:
0.0
,
zIndex
:
10
}
},
{
type
:
'
scatter
'
,
values
:
goodLabels
,
text
:
'
Good labels
'
,
marker
:
{
backgroundColor
:
'
#4caf50
'
},
zIndex
:
20
,
},
{
type
:
'
scatter
'
,
values
:
badLabels
,
text
:
'
Bad labels
'
,
marker
:
{
backgroundColor
:
'
#f44336
'
},
zIndex
:
20
,
}
];
// // Labeled
// for (const index in this.service.labels) {
// colors[Number(index)] = this.service.labels[index] ? '#4caf50' : '#f44336';
// sizes[Number(index)] = 10;
// opacity[Number(index)] = 1;
// }
//
// // Query
// colors[this.service.query] = '#cf00ff';
// sizes[this.service.query] = 10;
// opacity[this.service.query] = 1;
// Query
colors
[
this
.
service
.
query
]
=
'
#cf00ff
'
;
sizes
[
this
.
service
.
query
]
=
10
;
opacity
[
this
.
service
.
query
]
=
1
;
this
.
data
[
0
].
marker
.
color
=
colors
;
this
.
data
[
0
].
marker
.
size
=
sizes
;
this
.
data
[
0
].
marker
.
opacity
=
opacity
;
// this.data[0].marker.color = colors;
// this.data[0].marker.size = sizes;
// this.data[0].marker.opacity = opacity;
}
public
getColor
(
value
:
number
)
{
...
...
AngularApp/prototype/src/app/query-window/query-window.component.ts
View file @
b41c932e
...
...
@@ -44,6 +44,9 @@ export class QueryWindowComponent implements OnInit {
titlefont
:
{
size
:
9
},
xaxis
:
{
showticklabels
:
false
,
}
}
};
}
...
...
Flaskserver/.idea/workspace.xml
View file @
b41c932e
This diff is collapsed.
Click to expand it.
Flaskserver/__pycache__/main.cpython-38.pyc
View file @
b41c932e
No preview for this file type
Flaskserver/main.py
View file @
b41c932e
...
...
@@ -4,7 +4,6 @@ import numpy as np
from
flask_cors
import
CORS
from
collections
import
defaultdict
,
Counter
from
time
import
time
import
dask.dataframe
as
dd
import
os.path
import
json
from
sklearn
import
preprocessing
...
...
@@ -20,15 +19,15 @@ def index():
@
app
.
route
(
'/read-data'
,
methods
=
[
'GET'
])
def
read_data
():
filename
=
'processed-data.pkl'
if
(
not
os
.
path
.
isfile
(
filename
)):
print
(
"start"
)
df
=
dd
.
read_csv
(
"NW_Ground_Stations_2016.csv"
,
usecols
=
[
'number_sta'
,
'date'
,
't'
])
print
(
"read file"
)
df
=
df
.
loc
[
df
[
'number_sta'
]
==
14066001
]
print
(
"split rows"
)
df
=
df
.
compute
()
df
.
to_pickle
(
filename
)
print
(
"to_pandas"
)
#
if (not os.path.isfile(filename)):
#
print("start")
#
df = dd.read_csv("NW_Ground_Stations_2016.csv", usecols=['number_sta', 'date', 't'])
#
print("read file")
#
df = df.loc[df['number_sta'] == 14066001]
#
print("split rows")
#
df = df.compute()
#
df.to_pickle(filename)
#
print("to_pandas")
df
=
pd
.
read_pickle
(
filename
)
df
.
dropna
(
subset
=
[
't'
],
inplace
=
True
)
response
=
{
...
...
@@ -113,15 +112,13 @@ def query():
tables
=
raw_data
[
"tables"
]
neighbours
=
[]
output
=
{}
output
=
defaultdict
(
list
)
for
t
in
tables
.
values
():
signature
=
''
.
join
((
np
.
dot
(
window
,
t
[
"hash"
])
>
0
).
astype
(
'int'
).
astype
(
'str'
))
neighbours
.
extend
(
t
[
"entries"
][
signature
])
neighbours_with_frequency
=
dict
(
Counter
(
neighbours
))
for
index
,
frequency
in
neighbours_with_frequency
.
items
():
if
not
frequency
in
output
:
output
[
str
(
frequency
)]
=
[]
output
[
str
(
frequency
)].
append
(
index
)
response
=
orjson
.
dumps
(
output
)
return
response
...
...
Flaskserver/venv/Lib/site-packages/dask-2.21.0.dist-info/INSTALLER
deleted
100644 → 0
View file @
8d4ead19
pip
Flaskserver/venv/Lib/site-packages/dask-2.21.0.dist-info/LICENSE.txt
deleted
100644 → 0
View file @
8d4ead19
Copyright (c) 2014-2018, Anaconda, Inc. and contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
Neither the name of Anaconda nor the names of any contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
Flaskserver/venv/Lib/site-packages/dask-2.21.0.dist-info/METADATA
deleted
100644 → 0
View file @
8d4ead19
Metadata-Version: 2.1
Name: dask
Version: 2.21.0
Summary: Parallel PyData with Task Scheduling
Home-page: https://github.com/dask/dask/
Maintainer: Matthew Rocklin
Maintainer-email: mrocklin@gmail.com
License: BSD
Keywords: task-scheduling parallel numpy pandas pydata
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Requires-Python: >=3.6
Requires-Dist: pyyaml
Provides-Extra: array
Requires-Dist: numpy (>=1.13.0) ; extra == 'array'
Requires-Dist: toolz (>=0.8.2) ; extra == 'array'
Provides-Extra: bag
Requires-Dist: cloudpickle (>=0.2.2) ; extra == 'bag'
Requires-Dist: fsspec (>=0.6.0) ; extra == 'bag'
Requires-Dist: toolz (>=0.8.2) ; extra == 'bag'
Requires-Dist: partd (>=0.3.10) ; extra == 'bag'
Provides-Extra: complete
Requires-Dist: bokeh (>=1.0.0) ; extra == 'complete'
Requires-Dist: cloudpickle (>=0.2.2) ; extra == 'complete'
Requires-Dist: distributed (>=2.0) ; extra == 'complete'
Requires-Dist: fsspec (>=0.6.0) ; extra == 'complete'
Requires-Dist: numpy (>=1.13.0) ; extra == 'complete'
Requires-Dist: pandas (>=0.23.0) ; extra == 'complete'
Requires-Dist: partd (>=0.3.10) ; extra == 'complete'
Requires-Dist: toolz (>=0.8.2) ; extra == 'complete'
Provides-Extra: dataframe
Requires-Dist: numpy (>=1.13.0) ; extra == 'dataframe'
Requires-Dist: pandas (>=0.23.0) ; extra == 'dataframe'
Requires-Dist: toolz (>=0.8.2) ; extra == 'dataframe'
Requires-Dist: partd (>=0.3.10) ; extra == 'dataframe'
Requires-Dist: fsspec (>=0.6.0) ; extra == 'dataframe'
Provides-Extra: delayed
Requires-Dist: cloudpickle (>=0.2.2) ; extra == 'delayed'
Requires-Dist: toolz (>=0.8.2) ; extra == 'delayed'
Provides-Extra: diagnostics
Requires-Dist: bokeh (>=1.0.0) ; extra == 'diagnostics'
Provides-Extra: distributed
Requires-Dist: distributed (>=2.0) ; extra == 'distributed'
Dask
====
|Linux Build Status| |Windows Build Status| |Coverage| |Doc Status| |Gitter| |Version Status| |NumFOCUS|
Dask is a flexible parallel computing library for analytics. See
documentation_ for more information.
LICENSE
-------
New BSD. See `License File <https://github.com/dask/dask/blob/master/LICENSE.txt>`__.
.. _documentation: https://dask.org
.. |Linux Build Status| image:: https://travis-ci.org/dask/dask.svg?branch=master
:target: https://travis-ci.org/dask/dask
.. |Windows Build Status| image:: https://github.com/dask/dask/workflows/Windows%20CI/badge.svg?branch=master
:target: https://github.com/dask/dask/actions?query=workflow%3A%22Windows+CI%22
.. |Coverage| image:: https://coveralls.io/repos/dask/dask/badge.svg
:target: https://coveralls.io/r/dask/dask
:alt: Coverage status
.. |Doc Status| image:: https://readthedocs.org/projects/dask/badge/?version=latest
:target: https://dask.org
:alt: Documentation Status
.. |Gitter| image:: https://badges.gitter.im/Join%20Chat.svg
:alt: Join the chat at https://gitter.im/dask/dask
:target: https://gitter.im/dask/dask?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
.. |Version Status| image:: https://img.shields.io/pypi/v/dask.svg
:target: https://pypi.python.org/pypi/dask/
.. |NumFOCUS| image:: https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat&colorA=E1523D&colorB=007D8A
:target: https://www.numfocus.org/
Flaskserver/venv/Lib/site-packages/dask-2.21.0.dist-info/RECORD
deleted
100644 → 0
View file @
8d4ead19
This diff is collapsed.
Click to expand it.
Flaskserver/venv/Lib/site-packages/dask-2.21.0.dist-info/WHEEL
deleted
100644 → 0
View file @
8d4ead19
Wheel-Version: 1.0
Generator: bdist_wheel (0.34.2)
Root-Is-Purelib: true
Tag: py3-none-any
Flaskserver/venv/Lib/site-packages/dask-2.21.0.dist-info/top_level.txt
deleted
100644 → 0
View file @
8d4ead19
dask
Flaskserver/venv/Lib/site-packages/dask/__pycache__/__init__.cpython-38.pyc
View file @
b41c932e
No preview for this file type
Prev
1
2
3
4
5
…
17
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment