Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Mukhtar
stoekach3d
Commits
a34b5f3c
Commit
a34b5f3c
authored
Jun 01, 2024
by
Mukhtar
Browse files
Upload New File
parent
5fd8f08e
Changes
1
Hide whitespace changes
Inline
Side-by-side
index.html
0 → 100644
View file @
a34b5f3c
<html
lang=
"en"
>
<head>
<meta
charset=
"utf-8"
/>
<script
src=
"https://cesium.com/downloads/cesiumjs/releases/1.80/Build/Cesium/Cesium.js"
></script>
<link
href=
"https://cesium.com/downloads/cesiumjs/releases/1.80/Build/Cesium/Widgets/widgets.css"
rel=
"stylesheet"
/>
<link
rel=
"stylesheet"
href=
"https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css"
integrity=
"sha384-4LISF5TTJX/fLmGSxO53rV4miRxdg84mZsxmO8Rx5jGtp/LbrixFETvWa5a6sESd"
crossorigin=
"anonymous"
>
<script
src=
"https://cdn.jsdelivr.net/npm/chart.js"
></script>
<link
rel=
"stylesheet"
href=
"style.css"
/>
</head>
<body>
<div
class=
"webmap"
>
<div
id=
"cesiumContainer"
></div>
<div
class=
"menu"
>
<div
class=
"menubuttons"
>
<div
class=
"menuDiv"
>
<div>
<b>
Select the Attribute to Visualize Statistics
</b>
</div>
<div>
<div
class=
"options"
>
<input
type=
"radio"
id=
"yearOfCo"
name=
"attribute"
value=
"Year_of_co"
checked
/>
<label
for=
"yearOfCo"
>
Year of Construction
</label>
</div>
<div
class=
"options"
>
<input
type=
"radio"
id=
"primaryUsa"
name=
"attribute"
value=
"PrimaryUsa"
/>
<label
for=
"primaryUsa"
>
Primary Usage
</label>
</div>
<div
class=
"options"
>
<input
type=
"radio"
id=
"specificS"
name=
"attribute"
value=
"Specific_s"
/>
<label
for=
"specificS"
>
Heating demand in [kWh/m².year]
</label>
</div>
</div>
</div>
</div>
<div
class=
"chartContainer"
>
<div
class=
"chartCanvas"
>
<canvas
id=
"quant-chart"
></canvas>
</div>
</div>
<div
id=
"individualStatsChart"
class=
"individualStatsChart"
>
<p
id=
"stats-tag"
>
Select a building to show statistics...
</p>
<canvas
id=
"buildingStats"
></canvas>
</div>
</div>
</div>
<div
class=
"backdrop"
id=
"menu"
>
<h3>
Stoeckach Energy Dashboard
</h3>
<div
id=
"legend"
"
>
<div
class=
" my-legend"
id=
"legendcontainer"
>
<div
class=
"legend-title"
>
Sp. Heating Demand (kWh/m
<sup>
2
</sup>
.a)
</div>
<div
class=
"legend-scale"
>
<ul
class=
"legend-labels"
>
<li><span
style=
"background: #771f02"
></span>
Demand >= 250
</li>
<li><span
style=
"background: #be4400"
></span>
Demand >= 200
</li>
<li><span
style=
"background: #ee5c00"
></span>
Demand >= 150
</li>
<li><span
style=
"background: #ef8d00"
></span>
Demand >= 125
</li>
<li><span
style=
"background: #f0ba00"
></span>
Demand >= 100
</li>
<li><span
style=
"background: #f1d700"
></span>
Demand >= 75
</li>
<li><span
style=
"background: #e4f200"
></span>
Demand >= 50
</li>
<li><span
style=
"background: #b8fe00"
></span>
Demand >= 25
</li>
<li><span
style=
"background: #4cbb00"
></span>
Demand
<
25
</
li
>
<li><span
style=
"background: #000000"
></span>
None Heated / No Data
</li>
</ul>
</div>
</div>
</div>
</div>
<i
class=
"bi bi-info-circle-fill icon"
id=
"toggleIcon"
></i>
<script>
Cesium
.
Ion
.
defaultAccessToken
=
"
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIwNTg4NmUwZS0wZTk5LTQ0MTMtYTcwMS05OTU4NzcxZGIyZTMiLCJpZCI6MjE3MzI3LCJpYXQiOjE3MTY0NzAyMjB9.DxT60vd_gLj7WGPyNbsNP8mKOy40UKMe-av2z5mvE1E
"
;
var
viewer
=
new
Cesium
.
Viewer
(
"
cesiumContainer
"
,
{
baseLayerPicker
:
true
,
vrButton
:
true
,
geocoder
:
true
,
navigationHelpButton
:
false
,
selectionIndicator
:
true
,
shadows
:
true
,
timeline
:
true
,
sceneModePicker
:
true
,
});
var
tileset
=
viewer
.
scene
.
primitives
.
add
(
new
Cesium
.
Cesium3DTileset
({
url
:
"
./tileset.json
"
,
})
);
tileset
.
style
=
new
Cesium
.
Cesium3DTileStyle
({
color
:
{
conditions
:
[
[
"
Number(${Specific_s}) >= 250
"
,
"
color('#771f02')
"
],
[
"
Number(${Specific_s}) >= 200
"
,
"
color('#be4400')
"
],
[
"
Number(${Specific_s}) >= 150
"
,
"
color('#ee5c00')
"
],
[
"
Number(${Specific_s}) >= 125
"
,
"
color('#ef8d00')
"
],
[
"
Number(${Specific_s}) >= 100
"
,
"
color('#4cbb00')
"
],
[
"
Number(${Specific_s}) >= 75
"
,
"
color('#f0ba00')
"
],
[
"
Number(${Specific_s}) >= 50
"
,
"
color('#f1d700')
"
],
[
"
Number(${Specific_s}) >= 25
"
,
"
color('#e4f200')
"
],
[
"
true
"
,
"
color('#000000')
"
],
],
},
});
let
lineChartInstance
;
//Selecting a Building
var
Pickers_3DTile_Activated
=
true
;
function
active3DTilePicker
()
{
var
element
=
document
.
getElementById
(
'
individualStatsChart
'
);
if
(
element
)
{
element
.
style
.
display
=
'
block
'
;
}
var
highlighted
=
{
feature
:
undefined
,
originalColor
:
new
Cesium
.
Color
()
};
// Information about the currently selected feature
var
selected
=
{
feature
:
undefined
,
originalColor
:
new
Cesium
.
Color
()
};
// An entity object which will hold info about the currently selected feature for infobox display
var
selectedEntity
=
new
Cesium
.
Entity
();
// Get default left click handler for when a feature is not picked on left click
var
clickHandler
=
viewer
.
screenSpaceEventHandler
.
getInputAction
(
Cesium
.
ScreenSpaceEventType
.
LEFT_CLICK
);
// Color a feature GREY on hover.
viewer
.
screenSpaceEventHandler
.
setInputAction
(
function
onMouseMove
(
movement
)
{
if
(
Pickers_3DTile_Activated
)
{
// If a feature was previously highlighted, undo the highlight
if
(
Cesium
.
defined
(
highlighted
.
feature
))
{
highlighted
.
feature
.
color
=
highlighted
.
originalColor
;
highlighted
.
feature
=
undefined
;
}
// Pick a new feature
var
picked3DtileFeature
=
viewer
.
scene
.
pick
(
movement
.
endPosition
);
if
(
!
Cesium
.
defined
(
picked3DtileFeature
))
{
return
;
}
// Highlight the feature if it's not already selected.
if
(
picked3DtileFeature
!==
selected
.
feature
)
{
highlighted
.
feature
=
picked3DtileFeature
;
Cesium
.
Color
.
clone
(
picked3DtileFeature
.
color
,
highlighted
.
originalColor
);
picked3DtileFeature
.
color
=
Cesium
.
Color
.
GREY
;
}
}
},
Cesium
.
ScreenSpaceEventType
.
MOUSE_MOVE
);
// Color a feature AQUA on selection and show info in the InfoBox.
viewer
.
screenSpaceEventHandler
.
setInputAction
(
function
onLeftClick
(
movement
)
{
if
(
Pickers_3DTile_Activated
)
{
// If a feature was previously selected, undo the highlight
if
(
Cesium
.
defined
(
selected
.
feature
))
{
selected
.
feature
.
color
=
selected
.
originalColor
;
selected
.
feature
=
undefined
;
var
options
=
null
;
lineChartInstance
.
destroy
();
lineChartInstance
=
null
;
document
.
getElementById
(
'
stats-tag
'
).
style
.
display
=
'
block
'
;
}
// Pick a new feature
var
picked3DtileFeature
=
viewer
.
scene
.
pick
(
movement
.
position
);
if
(
!
Cesium
.
defined
(
picked3DtileFeature
))
{
clickHandler
(
movement
);
return
;
}
// Select the feature if it's not already selected
if
(
selected
.
feature
===
picked3DtileFeature
)
{
return
;
}
selected
.
feature
=
picked3DtileFeature
;
// Save the selected feature's original color
if
(
picked3DtileFeature
===
highlighted
.
feature
)
{
Cesium
.
Color
.
clone
(
highlighted
.
originalColor
,
selected
.
originalColor
);
highlighted
.
feature
=
undefined
;
}
else
{
Cesium
.
Color
.
clone
(
picked3DtileFeature
.
color
,
selected
.
originalColor
);
}
// Highlight newly selected feature
picked3DtileFeature
.
color
=
Cesium
.
Color
.
AQUA
;
// Set feature infobox description
var
featureName
=
"
Building Attributes
"
;
selectedEntity
.
name
=
featureName
;
selectedEntity
.
description
=
'
Loading <div class="cesium-infoBox-loading"></div>
'
;
viewer
.
selectedEntity
=
selectedEntity
;
selectedEntity
.
description
=
'
<table class="cesium-infoBox-defaultTable"><tbody>
'
+
'
<tr><th>GML ID</th><td>
'
+
picked3DtileFeature
.
getProperty
(
'
gml_id
'
)
+
'
</td></tr>
'
+
'
<tr><th>GML Parent ID</th><td>
'
+
picked3DtileFeature
.
getProperty
(
'
gml_parent_id
'
)
+
'
</td></tr>
'
+
'
<tr><th>Sp. Heating Demand</th><td>
'
+
picked3DtileFeature
.
getProperty
(
'
Specific_s
'
)
+
'
'
+
'
kWh/m²
'
+
'
</td></tr>
'
+
'
</tbody></table>
'
;
document
.
getElementById
(
'
stats-tag
'
).
style
.
display
=
'
none
'
;
}
else
{
document
.
getElementById
(
'
stats-tag
'
).
style
.
display
=
'
block
'
;
}
// Fetch GeoJSON data - please install CORS plugin otherwise this will not work
fetch
(
'
https://ugl.hft-stuttgart.de/leaflet-stoeckach-heatdemand/building_data.json
'
)
.
then
(
response
=>
response
.
json
())
.
then
(
data
=>
{
// var picked3DtileFeature = viewer.scene.pick(movement.position);
var
gml_id
=
picked3DtileFeature
.
getProperty
(
'
gml_id
'
);
var
buildingData
=
data
.
features
.
find
(
feature
=>
feature
.
properties
.
gml_id
==
gml_id
)
if
(
buildingData
)
{
var
properties
=
buildingData
.
properties
;
var
months
=
[
'
January_He
'
,
'
February_H
'
,
'
March_Heat
'
,
'
April_Heat
'
,
'
May_Heatin
'
,
'
June_Heati
'
,
'
July_Heati
'
,
'
August_Hea
'
,
'
September_
'
,
'
October_He
'
,
'
November_H
'
,
'
December_H
'
];
var
monthlyValues
=
months
.
map
(
month
=>
{
// Handle potential formatting issues
var
value
=
properties
[
month
];
if
(
typeof
value
===
'
string
'
)
{
value
=
parseFloat
(
value
.
replace
(
'
,
'
,
'
.
'
));
}
return
value
;
});
// Create the building year of construction distribution chart using Chart.js
var
ctx1
=
document
.
getElementById
(
'
buildingStats
'
).
getContext
(
'
2d
'
);
// Destroy the previous chart instance if it exists
if
(
lineChartInstance
)
{
lineChartInstance
.
destroy
();
}
lineChartInstance
=
new
Chart
(
ctx1
,
{
type
:
'
line
'
,
data
:
{
labels
:
[
'
January
'
,
'
February
'
,
'
March
'
,
'
April
'
,
'
May
'
,
'
June
'
,
'
July
'
,
'
August
'
,
'
September
'
,
'
October
'
,
'
November
'
,
'
December
'
],
datasets
:
[{
label
:
'
Heat Demand Per Month
'
,
data
:
monthlyValues
,
backgroundColor
:
'
rgba(75, 192, 192, 0.5)
'
,
borderColor
:
'
rgba(75, 192, 192, 1)
'
,
borderWidth
:
1
}]
},
options
:
{
responsive
:
true
,
scales
:
{
x
:
{
title
:
{
display
:
true
,
text
:
"
Month
"
,
font
:
{
size
:
8
,
family
:
"
Inter
"
,
weight
:
600
,
},
},
grid
:
{
color
:
"
#edf2f4
"
,
lineWidth
:
0.5
,
// Change grid line color to light shade
},
ticks
:
{
font
:
{
size
:
7
,
family
:
"
Inter
"
,
weight
:
500
,
},
color
:
"
#2C2C2C
"
,
},
},
y
:
{
title
:
{
display
:
true
,
text
:
"
Heating demand in [kWh/m².month]
"
,
font
:
{
size
:
8
,
family
:
"
Inter
"
,
weight
:
600
,
},
},
grid
:
{
color
:
"
#edf2f4
"
,
lineWidth
:
0.5
,
// Change grid line color to light shade
},
beginAtZero
:
true
,
ticks
:
{
font
:
{
size
:
8
,
family
:
"
Inter
"
,
weight
:
500
,
},
color
:
"
#2C2C2C
"
,
},
},
},
plugins
:
{
legend
:
{
labels
:
{
font
:
{
size
:
9
,
// Font size for legend labels
family
:
"
Inter
"
,
weight
:
500
,
},
color
:
"
#2C2C2C
"
,
},
display
:
false
,
},
title
:
{
font
:
{
size
:
13
,
family
:
"
Inter
"
,
weight
:
600
,
},
display
:
true
,
text
:
'
Heating Demand for Building (GML_ID:
'
+
gml_id
+
'
)
'
},
},
},
});
}
})
},
Cesium
.
ScreenSpaceEventType
.
LEFT_CLICK
);
}
active3DTilePicker
();
document
.
addEventListener
(
'
DOMContentLoaded
'
,
function
()
{
// Get the element and close button by their IDs
var
element
=
document
.
getElementById
(
'
individualStatsChart
'
);
var
closeButton
=
document
.
getElementById
(
'
closeStats
'
);
// Check if the elements exist
if
(
element
&&
closeButton
)
{
// Add click event listener to the close button
closeButton
.
addEventListener
(
'
click
'
,
function
()
{
// Hide the element
element
.
style
.
display
=
'
none
'
;
});
}
});
// Charts and Visualization
let
chart
;
Cesium
.
when
(
tileset
.
readyPromise
).
then
(
function
(
tileset
)
{
viewer
.
flyTo
(
tileset
);
var
processedTiles
=
new
Set
();
var
yearFrequency
=
{};
var
primaryUsaFrequency
=
{};
var
specificSFrequency
=
{
"
0-25
"
:
0
,
"
26-50
"
:
0
,
"
51-75
"
:
0
,
"
76-100
"
:
0
,
"
101-125
"
:
0
,
"
126-150
"
:
0
,
"
151-200
"
:
0
,
"
201-250
"
:
0
,
"
251+
"
:
0
,
};
tileset
.
tileVisible
.
addEventListener
(
function
(
tile
)
{
if
(
!
processedTiles
.
has
(
tile
))
{
processedTiles
.
add
(
tile
);
var
content
=
tile
.
content
;
var
featuresLength
=
content
.
featuresLength
;
for
(
var
i
=
0
;
i
<
featuresLength
;
i
++
)
{
var
feature
=
content
.
getFeature
(
i
);
var
year
=
feature
.
getProperty
(
"
Year_of_co
"
);
if
(
year
)
{
if
(
yearFrequency
[
year
])
{
yearFrequency
[
year
]
++
;
}
else
{
yearFrequency
[
year
]
=
1
;
}
}
var
primaryUsa
=
feature
.
getProperty
(
"
PrimaryUsa
"
);
if
(
primaryUsa
)
{
if
(
primaryUsaFrequency
[
primaryUsa
])
{
primaryUsaFrequency
[
primaryUsa
]
++
;
}
else
{
primaryUsaFrequency
[
primaryUsa
]
=
1
;
}
}
var
specific_s
=
feature
.
getProperty
(
"
Specific_s
"
);
if
(
specific_s
)
{
specific_s
=
Number
(
specific_s
);
if
(
specific_s
>=
0
&&
specific_s
<=
25
)
{
specificSFrequency
[
"
0-25
"
]
++
;
}
else
if
(
specific_s
>
25
&&
specific_s
<=
50
)
{
specificSFrequency
[
"
26-50
"
]
++
;
}
else
if
(
specific_s
>
50
&&
specific_s
<=
75
)
{
specificSFrequency
[
"
51-75
"
]
++
;
}
else
if
(
specific_s
>
75
&&
specific_s
<=
100
)
{
specificSFrequency
[
"
76-100
"
]
++
;
}
else
if
(
specific_s
>
100
&&
specific_s
<=
125
)
{
specificSFrequency
[
"
101-125
"
]
++
;
}
else
if
(
specific_s
>
125
&&
specific_s
<=
150
)
{
specificSFrequency
[
"
126-150
"
]
++
;
}
else
if
(
specific_s
>
150
&&
specific_s
<=
200
)
{
specificSFrequency
[
"
151-200
"
]
++
;
}
else
if
(
specific_s
>
200
&&
specific_s
<=
250
)
{
specificSFrequency
[
"
201-250
"
]
++
;
}
else
if
(
specific_s
>
250
)
{
specificSFrequency
[
"
251+
"
]
++
;
}
}
}
// Draw initial chart based on the default selection
updateChart
();
}
});
const
drawChart
=
(
labels
,
data
,
type
,
label
)
=>
{
var
ctx
=
document
.
getElementById
(
"
quant-chart
"
).
getContext
(
"
2d
"
);
// Destroy existing chart instance if it exists
if
(
chart
)
{
chart
.
destroy
();
}
var
options
=
{
responsive
:
true
,
plugins
:
{
legend
:
{
labels
:
{
font
:
{
family
:
"
Inter
"
,
// Set font family
size
:
11
,
// Set font size
weight
:
"
bold
"
,
// Set font weight
},
},
},
},
scales
:
{
x
:
{
ticks
:
{
font
:
{
family
:
"
Inter
"
,
// Set font family
size
:
9
,
// Set font size
weight
:
"
normal
"
,
// Set font weight
},
},
},
y
:
{
ticks
:
{
font
:
{
family
:
"
Inter
"
,
// Set font family
size
:
9
,
// Set font size
weight
:
"
normal
"
,
// Set font weight
},
},
},
},
};
var
backgroundColors
=
"
rgba(75, 192, 192, 0.2)
"
;
var
borderColors
=
"
rgba(75, 192, 192, 1)
"
;
if
(
type
===
"
doughnut
"
)
{
// Custom colors for doughnut chart
backgroundColors
=
[
"
#FF6384
"
,
"
#36A2EB
"
,
"
#FFCE56
"
,
"
#FF9F40
"
,
"
#4BC0C0
"
,
"
#9966FF
"
,
"
#FF6384
"
,
"
#36A2EB
"
,
];
// Convert labels to Init Case
labels
=
labels
.
map
((
label
)
=>
label
.
replace
(
/
\b\w
/g
,
(
char
)
=>
char
.
toUpperCase
())
);
options
=
{
...
options
,
plugins
:
{
tooltip
:
{
callbacks
:
{
label
:
function
(
tooltipItem
)
{
let
value
=
data
[
tooltipItem
.
dataIndex
];
let
total
=
data
.
reduce
((
acc
,
val
)
=>
acc
+
val
,
0
);
let
percentage
=
((
value
/
total
)
*
100
).
toFixed
(
2
);
return
`
${
labels
[
tooltipItem
.
dataIndex
]
}
:
${
percentage
}
% (
${
value
}
)`
;
},
},
},
legend
:
{
labels
:
{
generateLabels
:
function
(
chart
)
{
var
data
=
chart
.
data
;
if
(
data
.
labels
.
length
&&
data
.
datasets
.
length
)
{
return
data
.
labels
.
map
((
label
,
i
)
=>
{
var
value
=
data
.
datasets
[
0
].
data
[
i
];
var
total
=
data
.
datasets
[
0
].
data
.
reduce
(
(
acc
,
val
)
=>
acc
+
val
,
0
);
var
percentage
=
((
value
/
total
)
*
100
).
toFixed
(
2
);
return
{
text
:
`
${
label
}
(
${
percentage
}
%)`
,
fillStyle
:
data
.
datasets
[
0
].
backgroundColor
[
i
],
hidden
:
false
,
lineCap
:
"
butt
"
,
lineDash
:
[],
lineDashOffset
:
0
,
lineJoin
:
"
miter
"
,
strokeStyle
:
"
rgba(0,0,0,0.1)
"
,
pointStyle
:
"
circle
"
,
rotation
:
0
,
};
});
}
return
[];
},
},
},
},
};
}
else
if
(
type
===
"
bar
"
&&
label
===
"
Heating demand in [kWh/m².year]
"
)
{
// Custom colors for specific_s bar chart
backgroundColors
=
[
"
#4cbb00
"
,
"
#b8fe00
"
,
"
#e4f200
"
,
"
#f1d700
"
,
"
#f0ba00
"
,
"
#ef8d00
"
,
"
#ee5c00
"
,
"
#be4400
"
,
];
borderColors
=
backgroundColors
;
options
.
plugins
=
{
legend
:
{
display
:
true
,
},
};
}
chart
=
new
Chart
(
ctx
,
{
type
:
type
,
data
:
{
labels
:
labels
,
datasets
:
[
{
label
:
label
,
data
:
data
,
backgroundColor
:
Array
.
isArray
(
backgroundColors
)
?
backgroundColors
:
[
backgroundColors
],
borderColor
:
type
===
"
doughnut
"
?
"
transparent
"
:
Array
.
isArray
(
borderColors
)
?
borderColors
:
[
borderColors
],
borderWidth
:
1
,
},
],
},
options
:
options
,
});
};
const
updateChart
=
()
=>
{
var
selectedAttribute
=
document
.
querySelector
(
'
input[name="attribute"]:checked
'
).
value
;
if
(
selectedAttribute
===
"
Year_of_co
"
)
{
var
labels
=
Object
.
keys
(
yearFrequency
);
var
data
=
Object
.
values
(
yearFrequency
);
drawChart
(
labels
,
data
,
"
bar
"
,
"
Building Count
"
);
}
else
if
(
selectedAttribute
===
"
PrimaryUsa
"
)
{
var
labels
=
Object
.
keys
(
primaryUsaFrequency
);
var
data
=
Object
.
values
(
primaryUsaFrequency
);
drawChart
(
labels
,
data
,
"
doughnut
"
,
"
Primary Use Percentage
"
);
}
else
if
(
selectedAttribute
===
"
Specific_s
"
)
{
var
labels
=
Object
.
keys
(
specificSFrequency
);
var
data
=
Object
.
values
(
specificSFrequency
);
drawChart
(
labels
,
data
,
"
bar
"
,
"
Heating demand in [kWh/m².year]
"
);
}
};
// Add event listeners to radio buttons
document
.
querySelectorAll
(
'
input[name="attribute"]
'
)
.
forEach
((
radio
)
=>
{
radio
.
addEventListener
(
"
change
"
,
updateChart
);
});
});
document
.
getElementById
(
'
toggleIcon
'
).
addEventListener
(
'
click
'
,
function
()
{
var
menu
=
document
.
getElementById
(
'
menu
'
);
var
icon
=
document
.
getElementById
(
'
toggleIcon
'
);
// Toggle the menu display
if
(
menu
.
style
.
display
===
'
none
'
||
menu
.
style
.
display
===
''
)
{
menu
.
style
.
display
=
'
block
'
;
}
else
{
menu
.
style
.
display
=
'
none
'
;
}
// Toggle the icon position
icon
.
classList
.
toggle
(
'
moved
'
);
});
</script>
</body>
</html>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a 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