Spaces:
Runtime error
Runtime error
add app
Browse files- Procfile +1 -0
- README.md +2 -1
- apps/__init__.py +12 -0
- apps/cheat_app.py +266 -0
- apps/cookie_cutter.py +47 -0
- apps/extras/__init__.py +0 -0
- apps/extras/backmapping.py +347 -0
- apps/extras/models.json +23 -0
- apps/extras/selected_bodies.py +26 -0
- apps/home_app.py +78 -0
- apps/load_app.py +93 -0
- apps/login_app.py +101 -0
- apps/myloading_app.py +66 -0
- apps/signup.py +113 -0
- apps/solar_mach.py +178 -0
- apps/spacy_nlp.py +44 -0
- apps/uber_app.py +148 -0
- apps/walsh_app.py +200 -0
- apps/walsh_app_secure.py +210 -0
- docs/images/hydra.png +0 -0
- js/exscripts.js +9 -0
- requirements.txt +18 -0
- resources/belgium.png +0 -0
- resources/brain.png +0 -0
- resources/classroom.png +0 -0
- resources/dart.png +0 -0
- resources/data.png +0 -0
- resources/denoise.png +0 -0
- resources/exchange.png +0 -0
- resources/failure.png +0 -0
- resources/hydra.png +0 -0
- resources/jquery.js +1 -0
- resources/lock.png +0 -0
- resources/satellite.png +0 -0
- resources/search.png +0 -0
- resources/taxi.png +0 -0
- resources/vessel.png +0 -0
- runtime.txt +1 -0
- secure_app.py +119 -0
- setup.sh +11 -0
Procfile
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
web: sh setup.sh && streamlit run secure_app.py
|
README.md
CHANGED
@@ -4,8 +4,9 @@ emoji: π¦
|
|
4 |
colorFrom: blue
|
5 |
colorTo: purple
|
6 |
sdk: streamlit
|
7 |
-
app_file:
|
8 |
pinned: false
|
|
|
9 |
---
|
10 |
|
11 |
# Configuration
|
|
|
4 |
colorFrom: blue
|
5 |
colorTo: purple
|
6 |
sdk: streamlit
|
7 |
+
app_file: secure_app.py
|
8 |
pinned: false
|
9 |
+
sdk_version : 1.0.0
|
10 |
---
|
11 |
|
12 |
# Configuration
|
apps/__init__.py
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from apps.home_app import HomeApp
|
2 |
+
from apps.walsh_app import WalshApp
|
3 |
+
from apps.walsh_app_secure import WalshAppSecure
|
4 |
+
from apps.login_app import LoginApp
|
5 |
+
from apps.solar_mach import SolarMach
|
6 |
+
from apps.spacy_nlp import SpacyNLP
|
7 |
+
from apps.uber_app import UberNYC
|
8 |
+
from apps.cheat_app import CheatApp
|
9 |
+
from apps.myloading_app import MyLoadingApp
|
10 |
+
from apps.signup import SignUpApp
|
11 |
+
from apps.cookie_cutter import CookieCutterApp
|
12 |
+
from apps.load_app import LoaderTestApp
|
apps/cheat_app.py
ADDED
@@ -0,0 +1,266 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Streamlit Cheat Sheet
|
3 |
+
App to summarise streamlit docs v0.81.0 for quick reference
|
4 |
+
There is also an accompanying png version
|
5 |
+
https://github.com/daniellewisDL/streamlit-cheat-sheet
|
6 |
+
v0.71.0 November 2020 Daniel Lewis and Austin Chen
|
7 |
+
"""
|
8 |
+
|
9 |
+
import streamlit as st
|
10 |
+
from pathlib import Path
|
11 |
+
import base64
|
12 |
+
from hydralit import HydraHeadApp
|
13 |
+
|
14 |
+
|
15 |
+
# Thanks to streamlitopedia for the following code snippet
|
16 |
+
def img_to_bytes(img_path):
|
17 |
+
img_bytes = Path(img_path).read_bytes()
|
18 |
+
encoded = base64.b64encode(img_bytes).decode()
|
19 |
+
return encoded
|
20 |
+
|
21 |
+
|
22 |
+
|
23 |
+
class CheatApp(HydraHeadApp):
|
24 |
+
|
25 |
+
def __init__(self, title = '', **kwargs):
|
26 |
+
self.__dict__.update(kwargs)
|
27 |
+
self.title = title
|
28 |
+
|
29 |
+
def run(self):
|
30 |
+
|
31 |
+
self._cs_sidebar()
|
32 |
+
self._cs_body()
|
33 |
+
|
34 |
+
|
35 |
+
# sidebar
|
36 |
+
|
37 |
+
def _cs_sidebar(self):
|
38 |
+
|
39 |
+
st.sidebar.header('Streamlit cheat sheet')
|
40 |
+
|
41 |
+
st.sidebar.markdown('''
|
42 |
+
<small>Summary of the [docs](https://docs.streamlit.io/en/stable/api.html), as of [Streamlit v0.81.0](https://www.streamlit.io/).</small>
|
43 |
+
''', unsafe_allow_html=True)
|
44 |
+
|
45 |
+
st.sidebar.markdown('__How to install and import__')
|
46 |
+
|
47 |
+
st.sidebar.code('$ pip install streamlit')
|
48 |
+
|
49 |
+
st.sidebar.markdown('Import convention')
|
50 |
+
st.sidebar.code('>>> import streamlit as st')
|
51 |
+
|
52 |
+
st.sidebar.markdown('__Add widgets to sidebar__')
|
53 |
+
st.sidebar.code('''
|
54 |
+
st.sidebar.<widget>
|
55 |
+
>>> a = st.sidebar.radio(\'R:\',[1,2])
|
56 |
+
''')
|
57 |
+
|
58 |
+
st.sidebar.markdown('__Command line__')
|
59 |
+
st.sidebar.code('''
|
60 |
+
$ streamlit --help
|
61 |
+
$ streamlit run your_script.py
|
62 |
+
$ streamlit hello
|
63 |
+
$ streamlit config show
|
64 |
+
$ streamlit cache clear
|
65 |
+
$ streamlit docs
|
66 |
+
$ streamlit --version
|
67 |
+
''')
|
68 |
+
|
69 |
+
st.sidebar.markdown('__Pre-release features__')
|
70 |
+
st.sidebar.markdown('[Beta and experimental features](https://docs.streamlit.io/en/0.70.0/api.html#beta-and-experimental-features)')
|
71 |
+
st.sidebar.code('''
|
72 |
+
pip uninstall streamlit
|
73 |
+
pip install streamlit-nightly --upgrade
|
74 |
+
''')
|
75 |
+
|
76 |
+
st.sidebar.markdown('''[<img src='data:image/png;base64,{}' class='img-fluid' width=32 height=32>](https://github.com/daniellewisDL/streamlit-cheat-sheet) <small>st.cheat_sheet v0.81.0 | May 2021</small>'''.format(img_to_bytes("./resources/brain.png")), unsafe_allow_html=True)
|
77 |
+
|
78 |
+
return None
|
79 |
+
|
80 |
+
##########################
|
81 |
+
# Main body of cheat sheet
|
82 |
+
##########################
|
83 |
+
|
84 |
+
def _cs_body(self):
|
85 |
+
# Magic commands
|
86 |
+
|
87 |
+
st.subheader('Source for this great app is from the Streamlit gallery [Streamlit Cheat Sheet](https://github.com/daniellewisDL/streamlit-cheat-sheet). An example of how easy it is to convert an existing application and use within a Hydralit multi-page application, see the secret saurce [here] (https://github.com/TangleSpace/hydralit).')
|
88 |
+
st.markdown('<br><br>',unsafe_allow_html=True)
|
89 |
+
|
90 |
+
col1, col2, col3 = st.columns(3)
|
91 |
+
|
92 |
+
col1.subheader('Magic commands')
|
93 |
+
col1.code('''# Magic commands implicitly `st.write()`
|
94 |
+
\'\'\' _This_ is some __Markdown__ \'\'\'
|
95 |
+
a=3
|
96 |
+
'dataframe:', data
|
97 |
+
''')
|
98 |
+
|
99 |
+
# Display text
|
100 |
+
|
101 |
+
col1.subheader('Display text')
|
102 |
+
col1.code('''
|
103 |
+
st.text('Fixed width text')
|
104 |
+
st.markdown('_Markdown_') # see *
|
105 |
+
st.latex(r\'\'\' e^{i\pi} + 1 = 0 \'\'\')
|
106 |
+
st.write('Most objects') # df, err, func, keras!
|
107 |
+
st.write(['st', 'is <', 3]) # see *
|
108 |
+
st.title('My title')
|
109 |
+
st.header('My header')
|
110 |
+
st.subheader('My sub')
|
111 |
+
st.code('for i in range(8): foo()')
|
112 |
+
* optional kwarg unsafe_allow_html = True
|
113 |
+
''')
|
114 |
+
|
115 |
+
# Display data
|
116 |
+
|
117 |
+
col1.subheader('Display data')
|
118 |
+
col1.code('''
|
119 |
+
st.dataframe(my_dataframe)
|
120 |
+
st.table(data.iloc[0:10])
|
121 |
+
st.json({'foo':'bar','fu':'ba'})
|
122 |
+
''')
|
123 |
+
|
124 |
+
# Display charts
|
125 |
+
|
126 |
+
col1.subheader('Display charts')
|
127 |
+
col1.code('''
|
128 |
+
st.line_chart(data)
|
129 |
+
st.area_chart(data)
|
130 |
+
st.bar_chart(data)
|
131 |
+
st.pyplot(fig)
|
132 |
+
st.altair_chart(data)
|
133 |
+
st.vega_lite_chart(data)
|
134 |
+
st.plotly_chart(data)
|
135 |
+
st.bokeh_chart(data)
|
136 |
+
st.pydeck_chart(data)
|
137 |
+
st.deck_gl_chart(data)
|
138 |
+
st.graphviz_chart(data)
|
139 |
+
st.map(data)
|
140 |
+
''')
|
141 |
+
|
142 |
+
# Display media
|
143 |
+
|
144 |
+
col1.subheader('Display media')
|
145 |
+
col1.code('''
|
146 |
+
st.image('./header.png')
|
147 |
+
st.audio(data)
|
148 |
+
st.video(data)
|
149 |
+
''')
|
150 |
+
|
151 |
+
# Display interactive widgets
|
152 |
+
|
153 |
+
col2.subheader('Display interactive widgets')
|
154 |
+
col2.code('''
|
155 |
+
st.button('Hit me')
|
156 |
+
st.checkbox('Check me out')
|
157 |
+
st.radio('Radio', [1,2,3])
|
158 |
+
st.selectbox('Select', [1,2,3])
|
159 |
+
st.multiselect('Multiselect', [1,2,3])
|
160 |
+
st.slider('Slide me', min_value=0, max_value=10)
|
161 |
+
st.select_slider('Slide to select', options=[1,'2'])
|
162 |
+
st.text_input('Enter some text')
|
163 |
+
st.number_input('Enter a number')
|
164 |
+
st.text_area('Area for textual entry')
|
165 |
+
st.date_input('Date input')
|
166 |
+
st.time_input('Time entry')
|
167 |
+
st.file_uploader('File uploader')
|
168 |
+
st.color_picker('Pick a color')
|
169 |
+
''')
|
170 |
+
col2.write('Use widgets\' returned values in variables:')
|
171 |
+
col2.code('''
|
172 |
+
>>> for i in range(int(st.number_input('Num:'))): foo()
|
173 |
+
>>> if st.sidebar.selectbox('I:',['f']) == 'f': b()
|
174 |
+
>>> my_slider_val = st.slider('Quinn Mallory', 1, 88)
|
175 |
+
>>> st.write(slider_val)
|
176 |
+
''')
|
177 |
+
|
178 |
+
# Control flow
|
179 |
+
|
180 |
+
col2.subheader('Control flow')
|
181 |
+
col2.code('''
|
182 |
+
st.stop()
|
183 |
+
''')
|
184 |
+
|
185 |
+
# Lay out your app
|
186 |
+
|
187 |
+
col2.subheader('Lay out your app')
|
188 |
+
col2.code('''
|
189 |
+
st.container()
|
190 |
+
st.columns(spec)
|
191 |
+
>>> col1, col2 = st.columns(2)
|
192 |
+
>>> col1.subheader('Columnisation')
|
193 |
+
st.expander('Expander')
|
194 |
+
>>> with st.expander('Expand'):
|
195 |
+
>>> st.write('Juicy deets')
|
196 |
+
''')
|
197 |
+
|
198 |
+
|
199 |
+
# Display code
|
200 |
+
|
201 |
+
col2.subheader('Display code')
|
202 |
+
col2.code('''
|
203 |
+
st.echo()
|
204 |
+
>>> with st.echo():
|
205 |
+
>>> st.write('Code will be executed and printed')
|
206 |
+
''')
|
207 |
+
|
208 |
+
# Display progress and status
|
209 |
+
|
210 |
+
col3.subheader('Display progress and status')
|
211 |
+
col3.code('''
|
212 |
+
st.progress(progress_variable_1_to_100)
|
213 |
+
st.spinner()
|
214 |
+
>>> with st.spinner(text='In progress'):
|
215 |
+
>>> time.sleep(5)
|
216 |
+
>>> st.success('Done')
|
217 |
+
st.balloons()
|
218 |
+
st.error('Error message')
|
219 |
+
st.warning('Warning message')
|
220 |
+
st.info('Info message')
|
221 |
+
st.success('Success message')
|
222 |
+
st.exception(e)
|
223 |
+
''')
|
224 |
+
|
225 |
+
# Placeholders, help, and options
|
226 |
+
|
227 |
+
col3.subheader('Placeholders, help, and options')
|
228 |
+
col3.code('''
|
229 |
+
st.empty()
|
230 |
+
>>> my_placeholder = st.empty()
|
231 |
+
>>> my_placeholder.text('Replaced!')
|
232 |
+
st.help(pandas.DataFrame)
|
233 |
+
st.get_option(key)
|
234 |
+
st.set_option(key, value)
|
235 |
+
st.set_page_config(layout='wide')
|
236 |
+
''')
|
237 |
+
|
238 |
+
# Mutate data
|
239 |
+
|
240 |
+
col3.subheader('Mutate data')
|
241 |
+
col3.code('''
|
242 |
+
DeltaGenerator.add_rows(data)
|
243 |
+
>>> my_table = st.table(df1)
|
244 |
+
>>> my_table.add_rows(df2)
|
245 |
+
>>> my_chart = st.line_chart(df1)
|
246 |
+
>>> my_chart.add_rows(df2)
|
247 |
+
''')
|
248 |
+
|
249 |
+
# Optimize performance
|
250 |
+
|
251 |
+
col3.subheader('Optimize performance')
|
252 |
+
col3.code('''
|
253 |
+
@st.cache
|
254 |
+
>>> @st.cache
|
255 |
+
... def foo(bar):
|
256 |
+
... # Mutate bar
|
257 |
+
... return data
|
258 |
+
>>> # Executes d1 as first time
|
259 |
+
>>> d1 = foo(ref1)
|
260 |
+
>>> # Does not execute d1; returns cached value, d1==d2
|
261 |
+
>>> d2 = foo(ref1)
|
262 |
+
>>> # Different arg, so function d1 executes
|
263 |
+
>>> d3 = foo(ref2)
|
264 |
+
''')
|
265 |
+
|
266 |
+
return None
|
apps/cookie_cutter.py
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from hydralit import HydraHeadApp
|
3 |
+
from hydralit_components import CookieManager
|
4 |
+
|
5 |
+
|
6 |
+
class CookieCutterApp(HydraHeadApp):
|
7 |
+
|
8 |
+
def __init__(self, title = 'Loader', delay=0, **kwargs):
|
9 |
+
self.__dict__.update(kwargs)
|
10 |
+
self.title = title
|
11 |
+
self.delay = delay
|
12 |
+
|
13 |
+
def run(self):
|
14 |
+
|
15 |
+
try:
|
16 |
+
#cookie_manager = stx.CookieManager(key='1234')
|
17 |
+
cookie_manager = CookieManager(key='REDKI')
|
18 |
+
|
19 |
+
st.subheader("All Cookies:")
|
20 |
+
cookies = cookie_manager.get_all()
|
21 |
+
st.write(cookies)
|
22 |
+
|
23 |
+
c1, c2, c3 = st.columns(3)
|
24 |
+
with c1:
|
25 |
+
st.subheader("Get Cookie:")
|
26 |
+
cookie = st.text_input("Cookie", key="0")
|
27 |
+
clicked = st.button("Get")
|
28 |
+
if clicked:
|
29 |
+
value = cookie_manager.get(cookie)
|
30 |
+
st.write(value)
|
31 |
+
with c2:
|
32 |
+
st.subheader("Set Cookie:")
|
33 |
+
cookie = st.text_input("Cookie", key="1")
|
34 |
+
val = st.text_input("Value")
|
35 |
+
if st.button("Add"):
|
36 |
+
cookie_manager.set(cookie, val)
|
37 |
+
with c3:
|
38 |
+
st.subheader("Delete Cookie:")
|
39 |
+
cookie = st.text_input("Cookie", key="2")
|
40 |
+
if st.button("Delete"):
|
41 |
+
cookie_manager.delete(cookie)
|
42 |
+
|
43 |
+
|
44 |
+
except Exception as e:
|
45 |
+
st.image("./resources/failure.png",width=100,)
|
46 |
+
st.error('An error has occurred, someone will be punished for your inconvenience, we humbly request you try again.')
|
47 |
+
st.error('Error details: {}'.format(e))
|
apps/extras/__init__.py
ADDED
File without changes
|
apps/extras/backmapping.py
ADDED
@@ -0,0 +1,347 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# backmapping.py
|
2 |
+
import streamlit as st
|
3 |
+
import math
|
4 |
+
from copy import deepcopy
|
5 |
+
|
6 |
+
import matplotlib.patches as mpatches
|
7 |
+
import matplotlib.pyplot as plt
|
8 |
+
import numpy as np
|
9 |
+
import pandas as pd
|
10 |
+
import scipy.constants as const
|
11 |
+
from matplotlib.legend_handler import HandlerPatch
|
12 |
+
from sunpy import log
|
13 |
+
from sunpy.coordinates import frames
|
14 |
+
from sunpy.coordinates import get_horizons_coord
|
15 |
+
|
16 |
+
from apps.extras.selected_bodies import body_dict
|
17 |
+
|
18 |
+
plt.rcParams['axes.linewidth'] = 1.5
|
19 |
+
plt.rcParams['font.size'] = 15
|
20 |
+
plt.rcParams['agg.path.chunksize'] = 20000
|
21 |
+
|
22 |
+
pd.options.display.max_rows = None
|
23 |
+
pd.options.display.float_format = '{:.1f}'.format
|
24 |
+
|
25 |
+
# disable unnecessary logging
|
26 |
+
log.setLevel('WARNING')
|
27 |
+
|
28 |
+
|
29 |
+
def print_body_list():
|
30 |
+
"""
|
31 |
+
prints a selection of body keys and the corresponding body names which may be provided to the
|
32 |
+
HeliosphericConstellation class
|
33 |
+
"""
|
34 |
+
# print('Please visit https://ssd.jpl.nasa.gov/horizons.cgi?s_target=1#top for a complete list of available bodies')
|
35 |
+
data = pd.DataFrame\
|
36 |
+
.from_dict(body_dict, orient='index', columns=['ID', 'Body', 'Color'])\
|
37 |
+
.drop(['ID', 'Color'], 'columns')\
|
38 |
+
.drop_duplicates()
|
39 |
+
data.index.name = 'Key'
|
40 |
+
return data
|
41 |
+
|
42 |
+
|
43 |
+
class HeliosphericConstellation():
|
44 |
+
"""
|
45 |
+
Class which handles the selected bodies
|
46 |
+
Parameters
|
47 |
+
----------
|
48 |
+
date: str
|
49 |
+
body_list: list
|
50 |
+
list of body keys to be used. Keys can be string of int.
|
51 |
+
vsw_list: list, optional
|
52 |
+
list of solar wind speeds at the position of the different bodies. Must have the same length as body_list.
|
53 |
+
Default is an epmty list leading to vsw=400km/s used for every body.
|
54 |
+
reference_long: float, optional
|
55 |
+
Carrington longitute of reference position at the Sun
|
56 |
+
reference_lat: float, optional
|
57 |
+
Heliographic latitude of referene position at the Sun
|
58 |
+
"""
|
59 |
+
|
60 |
+
def __init__(self, date, body_list, vsw_list=[], reference_long=None, reference_lat=None):
|
61 |
+
body_list = list(dict.fromkeys(body_list))
|
62 |
+
bodies = deepcopy(body_dict)
|
63 |
+
|
64 |
+
self.date = date
|
65 |
+
self.reference_long = reference_long
|
66 |
+
self.reference_lat = reference_lat
|
67 |
+
|
68 |
+
pos_E = get_horizons_coord(399, self.date, 'id') # (lon, lat, radius) in (deg, deg, AU)
|
69 |
+
self.pos_E = pos_E.transform_to(frames.HeliographicCarrington(observer='Sun'))
|
70 |
+
|
71 |
+
if len(vsw_list) == 0:
|
72 |
+
vsw_list = np.zeros(len(body_list)) + 400
|
73 |
+
|
74 |
+
random_cols = ['forestgreen', 'mediumblue', 'm', 'saddlebrown', 'tomato', 'olive', 'steelblue', 'darkmagenta',
|
75 |
+
'c', 'darkslategray', 'yellow', 'darkolivegreen']
|
76 |
+
body_lon_list = []
|
77 |
+
body_lat_list = []
|
78 |
+
body_dist_list = []
|
79 |
+
longsep_E_list = []
|
80 |
+
latsep_E_list = []
|
81 |
+
body_vsw_list = []
|
82 |
+
footp_long_list = []
|
83 |
+
longsep_list = []
|
84 |
+
latsep_list = []
|
85 |
+
footp_longsep_list = []
|
86 |
+
|
87 |
+
for i, body in enumerate(body_list.copy()):
|
88 |
+
if body in bodies:
|
89 |
+
body_id = bodies[body][0]
|
90 |
+
body_lab = bodies[body][1]
|
91 |
+
body_color = bodies[body][2]
|
92 |
+
|
93 |
+
else:
|
94 |
+
body_id = body
|
95 |
+
body_lab = str(body)
|
96 |
+
body_color = random_cols[i]
|
97 |
+
bodies.update(dict.fromkeys([body_id], [body_id, body_lab, body_color]))
|
98 |
+
|
99 |
+
try:
|
100 |
+
pos = get_horizons_coord(body_id, date, 'id') # (lon, lat, radius) in (deg, deg, AU)
|
101 |
+
pos = pos.transform_to(frames.HeliographicCarrington(observer='Sun'))
|
102 |
+
bodies[body_id].append(pos)
|
103 |
+
bodies[body_id].append(vsw_list[i])
|
104 |
+
|
105 |
+
longsep_E = pos.lon.value - self.pos_E.lon.value
|
106 |
+
if longsep_E > 180:
|
107 |
+
longsep_E = longsep_E - 360.
|
108 |
+
latsep_E = pos.lat.value - self.pos_E.lat.value
|
109 |
+
|
110 |
+
body_lon_list.append(pos.lon.value)
|
111 |
+
body_lat_list.append(pos.lat.value)
|
112 |
+
body_dist_list.append(pos.radius.value)
|
113 |
+
longsep_E_list.append(longsep_E)
|
114 |
+
latsep_E_list.append(latsep_E)
|
115 |
+
|
116 |
+
body_vsw_list.append(vsw_list[i])
|
117 |
+
|
118 |
+
sep, alpha = self.backmapping(pos, date, reference_long, vsw=vsw_list[i])
|
119 |
+
bodies[body_id].append(sep)
|
120 |
+
|
121 |
+
body_footp_long = pos.lon.value + alpha
|
122 |
+
if body_footp_long > 360:
|
123 |
+
body_footp_long = body_footp_long - 360
|
124 |
+
footp_long_list.append(body_footp_long)
|
125 |
+
|
126 |
+
if self.reference_long is not None:
|
127 |
+
bodies[body_id].append(sep)
|
128 |
+
long_sep = pos.lon.value - self.reference_long
|
129 |
+
if long_sep > 180:
|
130 |
+
long_sep = long_sep - 360.
|
131 |
+
|
132 |
+
longsep_list.append(long_sep)
|
133 |
+
footp_longsep_list.append(sep)
|
134 |
+
|
135 |
+
if self.reference_lat is not None:
|
136 |
+
lat_sep = pos.lat.value - self.reference_lat
|
137 |
+
latsep_list.append(lat_sep)
|
138 |
+
except ValueError:
|
139 |
+
print('')
|
140 |
+
print('!!! No ephemeris for target "' + str(body) + '" for date ' + self.date)
|
141 |
+
st.warning('No ephemeris for target "' + str(body) + '" for date ' + self.date)
|
142 |
+
body_list.remove(body)
|
143 |
+
|
144 |
+
body_dict_short = {sel_key: bodies[sel_key] for sel_key in body_list}
|
145 |
+
self.body_dict = body_dict_short
|
146 |
+
self.max_dist = np.max(body_dist_list)
|
147 |
+
self.coord_table = pd.DataFrame(
|
148 |
+
{'Spacecraft/Body': list(self.body_dict.keys()), 'Carrington Longitude (Β°)': body_lon_list,
|
149 |
+
'Latitude (Β°)': body_lat_list, 'Heliocentric Distance (AU)': body_dist_list,
|
150 |
+
"Longitudinal separation to Earth's longitude": longsep_E_list,
|
151 |
+
"Latitudinal separation to Earth's latitude": latsep_E_list, 'Vsw': body_vsw_list,
|
152 |
+
'Magnetic footpoint longitude (Carrington)': footp_long_list})
|
153 |
+
|
154 |
+
if self.reference_long is not None:
|
155 |
+
self.coord_table['Longitudinal separation between body and reference_long'] = longsep_list
|
156 |
+
self.coord_table[
|
157 |
+
"Longitudinal separation between body's mangetic footpoint and reference_long"] = footp_longsep_list
|
158 |
+
if self.reference_lat is not None:
|
159 |
+
self.coord_table['Latitudinal separation between body and reference_lat'] = latsep_list
|
160 |
+
|
161 |
+
pass
|
162 |
+
self.coord_table.style.set_properties(**{'text-align': 'left'})
|
163 |
+
|
164 |
+
def backmapping(self, body_pos, date, reference_long, vsw=400):
|
165 |
+
"""
|
166 |
+
Determine the longitudinal separation angle of a given spacecraft and a given reference longitude
|
167 |
+
Parameters
|
168 |
+
----------
|
169 |
+
body_pos : astropy.coordinates.sky_coordinate.SkyCoord
|
170 |
+
coordinate of the body in Carrington coordinates
|
171 |
+
date: str
|
172 |
+
e.g., '2020-03-22 12:30'
|
173 |
+
reference_long: float
|
174 |
+
Carrington longitude of reference point at Sun to which we determine the longitudinal separation
|
175 |
+
vsw: float
|
176 |
+
solar wind speed (km/s) used to determine the position of the magnetic footpoint of the body. Default is 400.
|
177 |
+
out:
|
178 |
+
sep: float
|
179 |
+
longitudinal separation of body magnetic footpoint and reference longitude in degrees
|
180 |
+
alpha: float
|
181 |
+
backmapping angle
|
182 |
+
"""
|
183 |
+
AU = const.au / 1000 # km
|
184 |
+
|
185 |
+
pos = body_pos
|
186 |
+
lon = pos.lon.value
|
187 |
+
dist = pos.radius.value
|
188 |
+
|
189 |
+
omega = math.radians(360. / (25.38 * 24 * 60 * 60)) # rot-angle in rad/sec, sidereal period
|
190 |
+
|
191 |
+
tt = dist * AU / vsw
|
192 |
+
alpha = math.degrees(omega * tt)
|
193 |
+
|
194 |
+
if reference_long is not None:
|
195 |
+
sep = (lon + alpha) - reference_long
|
196 |
+
if sep > 180.:
|
197 |
+
sep = sep - 360
|
198 |
+
|
199 |
+
if sep < -180.:
|
200 |
+
sep = 360 - abs(sep)
|
201 |
+
else:
|
202 |
+
sep = np.nan
|
203 |
+
|
204 |
+
return sep, alpha
|
205 |
+
|
206 |
+
def plot(self, plot_spirals=True, plot_sun_body_line=False, show_earth_centered_coord=True, reference_vsw=400, transparent=False, outfile=''):
|
207 |
+
"""
|
208 |
+
Make a polar plot showing the Sun in the center (view from North) and the positions of the selected bodies
|
209 |
+
Parameters
|
210 |
+
----------
|
211 |
+
plot_spirals: bool
|
212 |
+
if True, the magnetic field lines connecting the bodies with the Sun are plotted
|
213 |
+
plot_sun_body_line: bool
|
214 |
+
if True, straight lines connecting the bodies with the Sun are plotted
|
215 |
+
show_earth_centered_coord: bool
|
216 |
+
if True, additional longitudinal tickmarks are shown with Earth at longitude 0
|
217 |
+
reference_vsw: int
|
218 |
+
if defined, defines solar wind speed for reference. if not defined, 400 km/s is used
|
219 |
+
outfile: string
|
220 |
+
if provided, the plot is saved with outfile as filename
|
221 |
+
"""
|
222 |
+
import pylab as pl
|
223 |
+
AU = const.au / 1000 # km
|
224 |
+
|
225 |
+
fig, ax = plt.subplots(subplot_kw=dict(projection='polar'), figsize=(12, 8))
|
226 |
+
self.ax = ax
|
227 |
+
|
228 |
+
r = np.arange(0.007, self.max_dist + 0.3, 0.001)
|
229 |
+
omega = np.radians(360. / (25.38 * 24 * 60 * 60)) # solar rot-angle in rad/sec, sidereal period
|
230 |
+
|
231 |
+
for i, body_id in enumerate(self.body_dict):
|
232 |
+
body_lab = self.body_dict[body_id][1]
|
233 |
+
body_color = self.body_dict[body_id][2]
|
234 |
+
body_vsw = self.body_dict[body_id][4]
|
235 |
+
body_pos = self.body_dict[body_id][3]
|
236 |
+
|
237 |
+
pos = body_pos
|
238 |
+
dist_body = pos.radius.value
|
239 |
+
body_long = pos.lon.value
|
240 |
+
|
241 |
+
E_long = self.pos_E.lon.value
|
242 |
+
dist_e = self.pos_E.radius.value
|
243 |
+
|
244 |
+
# plot body positions
|
245 |
+
ax.plot(np.deg2rad(body_long), dist_body, 's', color=body_color, label=body_lab)
|
246 |
+
if plot_sun_body_line:
|
247 |
+
# ax.plot(alpha_ref[0], 0.01, 0)
|
248 |
+
ax.plot([np.deg2rad(body_long), np.deg2rad(body_long)], [0.01, dist_body], ':', color=body_color)
|
249 |
+
# plot the spirals
|
250 |
+
if plot_spirals:
|
251 |
+
tt = dist_body * AU / body_vsw
|
252 |
+
alpha = np.degrees(omega * tt)
|
253 |
+
alpha_body = np.deg2rad(body_long) + omega / (body_vsw / AU) * (dist_body - r)
|
254 |
+
ax.plot(alpha_body, r, color=body_color)
|
255 |
+
|
256 |
+
if self.reference_long is not None:
|
257 |
+
delta_ref = self.reference_long
|
258 |
+
if delta_ref < 0.:
|
259 |
+
delta_ref = delta_ref + 360.
|
260 |
+
alpha_ref = np.deg2rad(delta_ref) + omega / (reference_vsw / AU) * (dist_e / AU - r) - (
|
261 |
+
omega / (reference_vsw / AU) * (dist_e / AU))
|
262 |
+
# old arrow style:
|
263 |
+
# arrow_dist = min([self.max_dist + 0.1, 2.])
|
264 |
+
# ref_arr = plt.arrow(alpha_ref[0], 0.01, 0, arrow_dist, head_width=0.12, head_length=0.11, edgecolor='black',
|
265 |
+
# facecolor='black', lw=2, zorder=5, overhang=0.2)
|
266 |
+
arrow_dist = min([self.max_dist/3.2, 2.])
|
267 |
+
ref_arr = plt.arrow(alpha_ref[0], 0.01, 0, arrow_dist, head_width=0.2, head_length=0.07, edgecolor='black',
|
268 |
+
facecolor='black', lw=1.8, zorder=5, overhang=0.2)
|
269 |
+
|
270 |
+
if plot_spirals:
|
271 |
+
ax.plot(alpha_ref, r, '--k', label=f'field line connecting to\nref. long. (vsw={reference_vsw} km/s)')
|
272 |
+
|
273 |
+
leg1 = ax.legend(loc=(1.2, 0.7), fontsize=13)
|
274 |
+
if self.reference_long is not None:
|
275 |
+
def legend_arrow(width, height, **_):
|
276 |
+
return mpatches.FancyArrow(0, 0.5 * height, width, 0, length_includes_head=True,
|
277 |
+
head_width=0.75 * height)
|
278 |
+
|
279 |
+
leg2 = ax.legend([ref_arr], ['reference long.'], loc=(1.2, 0.6),
|
280 |
+
handler_map={mpatches.FancyArrow: HandlerPatch(patch_func=legend_arrow), },
|
281 |
+
fontsize=13)
|
282 |
+
ax.add_artist(leg1)
|
283 |
+
|
284 |
+
ax.set_rlabel_position(E_long + 120)
|
285 |
+
ax.set_theta_offset(np.deg2rad(270 - E_long))
|
286 |
+
ax.set_rmax(self.max_dist + 0.3)
|
287 |
+
ax.set_rmin(0.01)
|
288 |
+
ax.yaxis.get_major_locator().base.set_params(nbins=4)
|
289 |
+
circle = plt.Circle((0., 0.), self.max_dist + 0.29, transform=ax.transData._b, edgecolor="k", facecolor=None,
|
290 |
+
fill=False, lw=2)
|
291 |
+
ax.add_patch(circle)
|
292 |
+
|
293 |
+
# manually plot r-grid lines with different resolution depending on maximum distance bodyz
|
294 |
+
# st.sidebar.info(self.max_dist)
|
295 |
+
if self.max_dist < 2:
|
296 |
+
ax.set_rgrids(np.arange(0, self.max_dist + 0.29, 0.5)[1:], angle=22.5)
|
297 |
+
# st.sidebar.info(str(np.arange(0, self.max_dist + 0.29, 0.5)))
|
298 |
+
else:
|
299 |
+
if self.max_dist < 10:
|
300 |
+
ax.set_rgrids(np.arange(0, self.max_dist + 0.29, 1.0)[1:], angle=22.5)
|
301 |
+
# st.sidebar.info(str(np.arange(0, self.max_dist + 0.29, 1.0)))
|
302 |
+
|
303 |
+
ax.set_title(self.date + '\n', pad=60)
|
304 |
+
|
305 |
+
plt.tight_layout()
|
306 |
+
plt.subplots_adjust(bottom=0.15)
|
307 |
+
|
308 |
+
if show_earth_centered_coord:
|
309 |
+
pos1 = ax.get_position() # get the original position of the polar plot
|
310 |
+
offset = 0.12
|
311 |
+
pos2 = [pos1.x0 - offset / 2, pos1.y0 - offset / 2, pos1.width + offset, pos1.height + offset]
|
312 |
+
ax2 = self._polar_twin(ax, E_long, pos2)
|
313 |
+
|
314 |
+
ax.tick_params(axis='x', pad=10)
|
315 |
+
|
316 |
+
ax.text(0.94, 0.16, 'Solar-MACH',
|
317 |
+
fontfamily='DejaVu Serif', fontsize=28,
|
318 |
+
ha='right', va='bottom', transform=fig.transFigure)
|
319 |
+
ax.text(0.94, 0.12, 'https://solar-mach.github.io',
|
320 |
+
fontfamily='DejaVu Sans', fontsize=18,
|
321 |
+
ha='right', va='bottom', transform=fig.transFigure)
|
322 |
+
|
323 |
+
if transparent:
|
324 |
+
fig.patch.set_alpha(0.0)
|
325 |
+
|
326 |
+
if outfile != '':
|
327 |
+
plt.savefig(outfile)
|
328 |
+
st.pyplot(fig)
|
329 |
+
|
330 |
+
def _polar_twin(self, ax, E_long, position):
|
331 |
+
"""
|
332 |
+
add an additional axes which is needed to plot additional longitudinal tickmarks with Earth at longitude 0
|
333 |
+
"""
|
334 |
+
ax2 = ax.figure.add_axes(position, projection='polar',
|
335 |
+
label='twin', frameon=False,
|
336 |
+
theta_direction=ax.get_theta_direction(),
|
337 |
+
theta_offset=E_long)
|
338 |
+
|
339 |
+
ax2.set_rmax(self.max_dist + 0.3)
|
340 |
+
ax2.yaxis.set_visible(False)
|
341 |
+
ax2.set_theta_zero_location("S")
|
342 |
+
ax2.tick_params(axis='x', colors='darkgreen', pad=10)
|
343 |
+
gridlines = ax2.xaxis.get_gridlines()
|
344 |
+
for xax in gridlines:
|
345 |
+
xax.set_color('darkgreen')
|
346 |
+
|
347 |
+
return ax2
|
apps/extras/models.json
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"zh_core_web_sm":"Chinese (zh_core_web_sm)",
|
3 |
+
"zh_core_web_trf":"Chinese (zh_core_web_trf)",
|
4 |
+
"da_core_news_sm":"Danish (da_core_news_sm)",
|
5 |
+
"nl_core_news_sm":"Dutch (nl_core_news_sm)",
|
6 |
+
"en_core_web_sm":"English (en_core_web_sm)",
|
7 |
+
"en_core_web_trf":"English (en_core_web_trf)",
|
8 |
+
"fr_core_news_sm":"French (fr_core_news_sm)",
|
9 |
+
"de_core_news_sm":"German (de_core_news_sm)",
|
10 |
+
"el_core_news_sm":"Greek (el_core_news_sm)",
|
11 |
+
"it_core_news_sm":"Italian (it_core_news_sm)",
|
12 |
+
"ja_core_news_sm":"Japanese (ja_core_news_sm)",
|
13 |
+
"lt_core_news_sm":"Lithuanian (lt_core_news_sm)",
|
14 |
+
"mk_core_news_sm":"Macedonian (mk_core_news_sm)",
|
15 |
+
"nb_core_news_sm":"Norwegian (nb_core_news_sm)",
|
16 |
+
"pl_core_news_sm":"Polish (pl_core_news_sm)",
|
17 |
+
"pl_core_news_md":"Polish (pl_core_news_md)",
|
18 |
+
"pt_core_news_sm":"Portuguese (pt_core_news_sm)",
|
19 |
+
"pt_core_news_md":"Portuguese (pt_core_news_md)",
|
20 |
+
"ro_core_news_sm":"Romanian (ro_core_news_sm)",
|
21 |
+
"ru_core_news_sm":"Russian (ru_core_news_sm)",
|
22 |
+
"es_core_news_sm":"Spanish (es_core_news_sm)"
|
23 |
+
}
|
apps/extras/selected_bodies.py
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# selected_bodies.py
|
2 |
+
|
3 |
+
# initialize the body dictionary
|
4 |
+
body_dict = dict.fromkeys(['Mercury', 199], [199, 'Mercury', 'darkturquoise'])
|
5 |
+
body_dict.update(dict.fromkeys(['Venus', 299], [299, 'Venus', 'darkorchid']))
|
6 |
+
body_dict.update(dict.fromkeys(['Earth', 'EARTH', 'earth',399], [399, 'Earth', 'green']))
|
7 |
+
body_dict.update(dict.fromkeys(['Mars', 499], [499, 'Mars', 'maroon']))
|
8 |
+
body_dict.update(dict.fromkeys(['Jupiter', 599], [599, 'Jupiter', 'navy']))
|
9 |
+
|
10 |
+
body_dict.update(dict.fromkeys(['STEREO B', 'STEREO-B', 'STB', 'stb', -235], [-235, 'STEREO B', 'b']))
|
11 |
+
body_dict.update(dict.fromkeys(['STEREO A', 'STEREO-A', 'STA', 'sta', -234], [-234, 'STEREO A', 'red']))
|
12 |
+
body_dict.update(dict.fromkeys(['SOHO', 'soho', -21], [-21, 'SOHO', 'darkgreen']))
|
13 |
+
body_dict.update(dict.fromkeys(['Solar Orbiter', 'SolO', 'solarorbiter', 'SolarOrbiter', -144], [-144, 'Solar Orbiter', 'dodgerblue']))
|
14 |
+
body_dict.update(dict.fromkeys(['PSP', 'Parker Solar Probe', 'parkersolarprobe', 'ParkerSolarProbe', -96], [-96, 'Parker Solar Probe', 'purple']))
|
15 |
+
body_dict.update(dict.fromkeys(['BepiColombo', 'Bepi', 'MPO', -121], [-121, 'BepiColombo', 'orange']))
|
16 |
+
body_dict.update(dict.fromkeys(['MAVEN', -202], [-202, 'MAVEN', 'brown']))
|
17 |
+
body_dict.update(dict.fromkeys(['Mars Express', -41], [-41, 'Mars Express', 'darkorange']))
|
18 |
+
body_dict.update(dict.fromkeys(['MESSENGER', -236], [-236, 'MESSENGER', 'olivedrab']))
|
19 |
+
body_dict.update(dict.fromkeys(['Juno', -61], [-61, 'Juno', 'orangered']))
|
20 |
+
body_dict.update(dict.fromkeys(['Cassini', -82], [-82, 'Cassini', 'mediumvioletred']))
|
21 |
+
body_dict.update(dict.fromkeys(['Rosetta', -226], [-226, 'Rosetta', 'blueviolet']))
|
22 |
+
body_dict.update(dict.fromkeys(['Pioneer10', -23], [-23, 'Pioneer 10', 'teal']))
|
23 |
+
body_dict.update(dict.fromkeys(['Pioneer11', -24], [-24, 'Pioneer 11', 'darkblue']))
|
24 |
+
body_dict.update(dict.fromkeys(['Ulysses', -55], [-55, 'Ulysses', 'dimgray']))
|
25 |
+
body_dict.update(dict.fromkeys(['Voyager1', -31], [-31, 'Voyager 1', 'darkred']))
|
26 |
+
body_dict.update(dict.fromkeys(['Voyager2', -32], [-32, 'Voyager 2', 'midnightblue']))
|
apps/home_app.py
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import streamlit as st
|
3 |
+
from hydralit import HydraHeadApp
|
4 |
+
|
5 |
+
MENU_LAYOUT = [1,1,1,7,2]
|
6 |
+
|
7 |
+
class HomeApp(HydraHeadApp):
|
8 |
+
|
9 |
+
|
10 |
+
def __init__(self, title = 'Hydralit Explorer', **kwargs):
|
11 |
+
self.__dict__.update(kwargs)
|
12 |
+
self.title = title
|
13 |
+
|
14 |
+
|
15 |
+
#This one method that must be implemented in order to be used in a Hydralit application.
|
16 |
+
#The application must also inherit from the hydrapp class in order to correctly work within Hydralit.
|
17 |
+
def run(self):
|
18 |
+
|
19 |
+
try:
|
20 |
+
st.markdown("<h1 style='text-align:center;padding: 0px 0px;color:black;font-size:200%;'>Home</h1>",unsafe_allow_html=True)
|
21 |
+
st.markdown("<h2 style='text-align: center;'>This example was written using the <a href = https://github.com/TangleSpace/hydralit>Hydralit</a> library. Sourecode for this example is located <a href = https://github.com/TangleSpace/hydralit-example>here</a>.</h2>",unsafe_allow_html=True)
|
22 |
+
|
23 |
+
col_header_logo_left_far, col_header_logo_left,col_header_text,col_header_logo_right,col_header_logo_right_far = st.columns([1,2,2,2,1])
|
24 |
+
|
25 |
+
#col_header_logo_right_far.image(os.path.join(".","resources","hydra.png"),width=100,)
|
26 |
+
|
27 |
+
if col_header_text.button('This will open a new tab and go'):
|
28 |
+
self.do_redirect("https://hotstepper.readthedocs.io/index.html")
|
29 |
+
|
30 |
+
_,_,col_logo, col_text,_ = st.columns(MENU_LAYOUT)
|
31 |
+
col_logo.image(os.path.join(".","resources","data.png"),width=80,)
|
32 |
+
col_text.subheader("This explorer has multiple applications, each application could be run individually, however where is the fun in that? Below is a sample home page.")
|
33 |
+
|
34 |
+
st.markdown('<br><br>',unsafe_allow_html=True)
|
35 |
+
|
36 |
+
|
37 |
+
_,_,col_logo, col_text,col_btn = st.columns(MENU_LAYOUT)
|
38 |
+
# if col_text.button('Cheat Sheet β‘οΈ'):
|
39 |
+
# self.do_redirect('Cheat Sheet')
|
40 |
+
col_logo.image(os.path.join(".","resources","classroom.png"),width=50,)
|
41 |
+
col_text.info("This application is all credit to [streamlit cheat sheet](https://github.com/daniellewisDL/streamlit-cheat-sheet), this is an example of how quickly an existing application can be wrapped in a HydraHeadAPP class and used in Hydralit.")
|
42 |
+
|
43 |
+
#The sample content in a sub-section with jump to format.
|
44 |
+
_,_,col_logo, col_text,col_btn = st.columns(MENU_LAYOUT)
|
45 |
+
# if col_text.button('Sequency Denoising β‘οΈ'):
|
46 |
+
# self.do_redirect('Sequency Denoising')
|
47 |
+
|
48 |
+
col_logo.image(os.path.join(".","resources","denoise.png"),width=50,)
|
49 |
+
col_text.info("This application is a quick look at some analysis of vessel queue data with discrete denoising using Sequency methods as provided by the [Hotstepper](https://github.com/TangleSpace/hotstepper) package.")
|
50 |
+
|
51 |
+
_,_,col_logo, col_text,col_btn = st.columns(MENU_LAYOUT)
|
52 |
+
# if col_text.button('Solar Mach β‘οΈ'):
|
53 |
+
# self.do_redirect('Solar Mach')
|
54 |
+
col_logo.image(os.path.join(".","resources","satellite.png"),width=50,)
|
55 |
+
col_text.info("This application is all credit to [Solar-MACH](https://github.com/jgieseler/Solar-MACH), this is an example of how quickly an existing application can be wrapped in a HydraHeadAPP class and used in Hydralit.")
|
56 |
+
|
57 |
+
_,_,col_logo, col_text,col_btn = st.columns(MENU_LAYOUT)
|
58 |
+
# if col_text.button('Spacy NLP β‘οΈ'):
|
59 |
+
# self.do_redirect('Spacy NLP')
|
60 |
+
col_logo.image(os.path.join(".","resources","belgium.png"),width=50,)
|
61 |
+
col_text.info("This application is all credit to [spacy-streamlit-demo](https://github.com/ines/spacy-streamlit-demo), this is an example of how quickly an existing application can be wrapped in a HydraHeadAPP class and used in Hydralit.")
|
62 |
+
|
63 |
+
_,_,col_logo, col_text,col_btn = st.columns(MENU_LAYOUT)
|
64 |
+
# if col_text.button('Uber Pickups β‘οΈ'):
|
65 |
+
# self.do_redirect('Uber Pickups')
|
66 |
+
col_logo.image(os.path.join(".","resources","taxi.png"),width=50,)
|
67 |
+
col_text.info("This application is all credit to [demo-uber-nyc-pickups](https://github.com/streamlit/demo-uber-nyc-pickups), this is an example of how quickly an existing application can be wrapped in a HydraHeadAPP class and used in Hydralit.")
|
68 |
+
|
69 |
+
|
70 |
+
except Exception as e:
|
71 |
+
st.image(os.path.join(".","resources","failure.png"),width=100,)
|
72 |
+
st.error('An error has occurred, someone will be punished for your inconvenience, we humbly request you try again.')
|
73 |
+
st.error('Error details: {}'.format(e))
|
74 |
+
|
75 |
+
|
76 |
+
|
77 |
+
|
78 |
+
|
apps/load_app.py
ADDED
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import hydralit_components as hc
|
3 |
+
import time
|
4 |
+
from hydralit import HydraHeadApp
|
5 |
+
|
6 |
+
|
7 |
+
class LoaderTestApp(HydraHeadApp):
|
8 |
+
|
9 |
+
def __init__(self, title = 'Loader Playground', delay=0, **kwargs):
|
10 |
+
self.__dict__.update(kwargs)
|
11 |
+
self.title = title
|
12 |
+
self.delay = delay
|
13 |
+
|
14 |
+
def run(self):
|
15 |
+
|
16 |
+
single_loader_list={
|
17 |
+
'pacman':{'loader': hc.Loaders.pacman,'length': 0},
|
18 |
+
'points_line':{'loader': hc.Loaders.points_line,'length': 0},
|
19 |
+
'grid_points':{'loader': hc.Loaders.grid_points,'length': 0},
|
20 |
+
'pulse_bars':{'loader': hc.Loaders.pulse_bars,'length': 0},
|
21 |
+
'showcase_pretty':{'loader': hc.Loaders.showcase_pretty,'length': 0}
|
22 |
+
}
|
23 |
+
|
24 |
+
multi_loader_list={
|
25 |
+
'standard_loaders': {'loader': hc.Loaders.standard_loaders,'length': 8},
|
26 |
+
'pretty_loaders': {'loader': hc.Loaders.pretty_loaders,'length': 15}
|
27 |
+
}
|
28 |
+
|
29 |
+
s,c1,c2,c3 = st.columns([2,4,4,4])
|
30 |
+
loader_delay = st.slider('Loader Display Time (sec)', 2, 20, 5)
|
31 |
+
loader_mixer = s.checkbox('Multi-select Loaders')
|
32 |
+
|
33 |
+
|
34 |
+
if loader_mixer:
|
35 |
+
loader_list = multi_loader_list
|
36 |
+
loader_replicat = s.checkbox('Enable Loader Replication')
|
37 |
+
selected_loader = c1.selectbox('Select Loader',loader_list.keys())
|
38 |
+
|
39 |
+
if loader_replicat:
|
40 |
+
loader_index = c2.selectbox('Loader index',list(range(loader_list[selected_loader]['length'])))
|
41 |
+
loader_rep = c3.selectbox('Loader Replication',[1,2,3,4,5,6,7,8,9,10])
|
42 |
+
loader_index=[loader_index]*loader_rep
|
43 |
+
else:
|
44 |
+
loader_index = c2.multiselect('Loader indexes',list(range(loader_list[selected_loader]['length'])))
|
45 |
+
|
46 |
+
else:
|
47 |
+
loader_list = single_loader_list
|
48 |
+
loader_index = 0
|
49 |
+
selected_loader = c1.selectbox('Select Loader',loader_list.keys())
|
50 |
+
|
51 |
+
|
52 |
+
b,c, = st.columns([3,7])
|
53 |
+
|
54 |
+
if b.button('Unleash the Loader!'):
|
55 |
+
with hc.HyLoader('Now doing loading',loader_list[selected_loader]['loader'],index=loader_index):
|
56 |
+
time.sleep(loader_delay)
|
57 |
+
|
58 |
+
cex = c.expander('Show Code')
|
59 |
+
|
60 |
+
cex.code(
|
61 |
+
"""
|
62 |
+
import hydralit_components as hc
|
63 |
+
|
64 |
+
single_loader_list={
|
65 |
+
'pacman': hc.Loaders.pacman
|
66 |
+
'points_line': hc.Loaders.points_line
|
67 |
+
'grid_points': hc.Loaders.grid_points
|
68 |
+
'pulse_bars': hc.Loaders.pulse_bars
|
69 |
+
'showcase_pretty': hc.Loaders.showcase_pretty
|
70 |
+
}
|
71 |
+
|
72 |
+
multi_loader_list={
|
73 |
+
'standard_loaders': hc.Loaders.standard_loaders,
|
74 |
+
'pretty_loaders': hc.Loaders.pretty_loaders
|
75 |
+
}
|
76 |
+
|
77 |
+
# a dedicated single loader
|
78 |
+
with hc.HyLoader('Now doing loading',single_loader_list['pacman'],):
|
79 |
+
time.sleep(loader_delay)
|
80 |
+
|
81 |
+
# for 3 loaders from the standard loader group
|
82 |
+
with hc.HyLoader('Now doing loading',multi_loader_list['standard_loaders'],index=[3,0,5]):
|
83 |
+
time.sleep(loader_delay)
|
84 |
+
|
85 |
+
# for 1 (index=5) from the standard loader group
|
86 |
+
with hc.HyLoader('Now doing loading',multi_loader_list['standard_loaders'],index=5):
|
87 |
+
time.sleep(loader_delay)
|
88 |
+
|
89 |
+
# for 4 replications of the same loader (index=2) from the standard loader group
|
90 |
+
with hc.HyLoader('Now doing loading',multi_loader_list['standard_loaders'],index=[2,2,2,2]):
|
91 |
+
time.sleep(loader_delay)
|
92 |
+
"""
|
93 |
+
)
|
apps/login_app.py
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import time
|
2 |
+
from typing import Dict
|
3 |
+
import streamlit as st
|
4 |
+
from hydralit import HydraHeadApp
|
5 |
+
|
6 |
+
|
7 |
+
class LoginApp(HydraHeadApp):
|
8 |
+
"""
|
9 |
+
This is an example login application to be used to secure access within a HydraApp streamlit application.
|
10 |
+
This application implementation uses the allow_access session variable and uses the do_redirect method if the login check is successful.
|
11 |
+
|
12 |
+
"""
|
13 |
+
|
14 |
+
def __init__(self, title = '', **kwargs):
|
15 |
+
self.__dict__.update(kwargs)
|
16 |
+
self.title = title
|
17 |
+
|
18 |
+
|
19 |
+
def run(self) -> None:
|
20 |
+
"""
|
21 |
+
Application entry point.
|
22 |
+
"""
|
23 |
+
|
24 |
+
st.markdown("<h1 style='text-align: center;'>Secure Hydralit Login</h1>", unsafe_allow_html=True)
|
25 |
+
|
26 |
+
c1,c2,c3, = st.columns([2,2,2])
|
27 |
+
c3.image("./resources/lock.png",width=100,)
|
28 |
+
c3.image("./resources/hydra.png",width=100,)
|
29 |
+
|
30 |
+
form_data = self._create_login_form(c2)
|
31 |
+
|
32 |
+
pretty_btn = """
|
33 |
+
<style>
|
34 |
+
div[class="row-widget stButton"] > button {
|
35 |
+
width: 100%;
|
36 |
+
}
|
37 |
+
</style>
|
38 |
+
<br><br>
|
39 |
+
"""
|
40 |
+
c2.markdown(pretty_btn,unsafe_allow_html=True)
|
41 |
+
|
42 |
+
if form_data['submitted']:
|
43 |
+
self._do_login(form_data, c2)
|
44 |
+
|
45 |
+
|
46 |
+
def _create_login_form(self, parent_container) -> Dict:
|
47 |
+
|
48 |
+
login_form = parent_container.form(key="login_form")
|
49 |
+
|
50 |
+
form_state = {}
|
51 |
+
form_state['username'] = login_form.text_input('Username')
|
52 |
+
form_state['password'] = login_form.text_input('Password',type="password")
|
53 |
+
form_state['access_level'] = login_form.selectbox('Example Access Level',(1,2))
|
54 |
+
form_state['submitted'] = login_form.form_submit_button('Login')
|
55 |
+
|
56 |
+
parent_container.write("sample login -> joe & joe")
|
57 |
+
|
58 |
+
if parent_container.button('Guest Login',key='guestbtn'):
|
59 |
+
# set access level to a negative number to allow a kick to the unsecure_app set in the parent
|
60 |
+
self.set_access(1, 'guest')
|
61 |
+
self.do_redirect()
|
62 |
+
|
63 |
+
if parent_container.button('Sign Up',key='signupbtn'):
|
64 |
+
# set access level to a negative number to allow a kick to the unsecure_app set in the parent
|
65 |
+
self.set_access(-1, 'guest')
|
66 |
+
|
67 |
+
#Do the kick to the signup app
|
68 |
+
self.do_redirect()
|
69 |
+
|
70 |
+
return form_state
|
71 |
+
|
72 |
+
|
73 |
+
def _do_login(self, form_data, msg_container) -> None:
|
74 |
+
|
75 |
+
#access_level=0 Access denied!
|
76 |
+
access_level = self._check_login(form_data)
|
77 |
+
|
78 |
+
if access_level > 0:
|
79 |
+
msg_container.success(f"βοΈ Login success")
|
80 |
+
with st.spinner("π€ now redirecting to application...."):
|
81 |
+
time.sleep(1)
|
82 |
+
|
83 |
+
#access control uses an int value to allow for levels of permission that can be set for each user, this can then be checked within each app seperately.
|
84 |
+
self.set_access(form_data['access_level'], form_data['username'])
|
85 |
+
|
86 |
+
#Do the kick to the home page
|
87 |
+
self.do_redirect()
|
88 |
+
else:
|
89 |
+
self.session_state.allow_access = 0
|
90 |
+
self.session_state.current_user = None
|
91 |
+
|
92 |
+
msg_container.error(f"β Login unsuccessful, π please check your username and password and try again.")
|
93 |
+
|
94 |
+
|
95 |
+
def _check_login(self, login_data) -> int:
|
96 |
+
#this method returns a value indicating the success of verifying the login details provided and the permission level, 1 for default access, 0 no access etc.
|
97 |
+
|
98 |
+
if login_data['username'] == 'joe' and login_data['password'] == 'joe':
|
99 |
+
return 1
|
100 |
+
else:
|
101 |
+
return 0
|
apps/myloading_app.py
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import time
|
2 |
+
import streamlit as st
|
3 |
+
from hydralit import HydraHeadApp
|
4 |
+
from hydralit_components import HyLoader, Loaders
|
5 |
+
|
6 |
+
|
7 |
+
class MyLoadingApp(HydraHeadApp):
|
8 |
+
|
9 |
+
def __init__(self, title = 'Loader', delay=0,loader=Loaders.standard_loaders, **kwargs):
|
10 |
+
self.__dict__.update(kwargs)
|
11 |
+
self.title = title
|
12 |
+
self.delay = delay
|
13 |
+
self._loader = loader
|
14 |
+
|
15 |
+
def run(self,app_target):
|
16 |
+
|
17 |
+
try:
|
18 |
+
|
19 |
+
se_loader_txt = """
|
20 |
+
<style>
|
21 |
+
#rcorners1 {
|
22 |
+
border-radius: 25px;
|
23 |
+
background: grey;
|
24 |
+
color: #00000;
|
25 |
+
alignment: center;
|
26 |
+
opacity: 0.95;
|
27 |
+
padding: 20px;
|
28 |
+
width: 1920px;
|
29 |
+
height: 400px;
|
30 |
+
z-index: 9998;
|
31 |
+
}
|
32 |
+
#banner {
|
33 |
+
color: white;
|
34 |
+
vertical-align: text-top;
|
35 |
+
text-align: center;
|
36 |
+
z-index: 9999;
|
37 |
+
}
|
38 |
+
</style>
|
39 |
+
<div id="rcorners1">
|
40 |
+
<h1 id="banner">Now loading Sequency Denoising</h1>
|
41 |
+
<br>
|
42 |
+
</div>
|
43 |
+
"""
|
44 |
+
app_title = ''
|
45 |
+
if hasattr(app_target,'title'):
|
46 |
+
app_title = app_target.title
|
47 |
+
|
48 |
+
if app_title == 'Sequency Denoising':
|
49 |
+
with HyLoader(se_loader_txt, loader_name=Loaders.pacman):
|
50 |
+
time.sleep(int(self.delay))
|
51 |
+
app_target.run()
|
52 |
+
|
53 |
+
elif app_title == 'Loader Playground':
|
54 |
+
app_target.run()
|
55 |
+
else:
|
56 |
+
with HyLoader("β¨Now loading {}".format(app_title), loader_name=self._loader,index=[3,0,5]):
|
57 |
+
time.sleep(int(self.delay))
|
58 |
+
app_target.run()
|
59 |
+
|
60 |
+
|
61 |
+
|
62 |
+
except Exception as e:
|
63 |
+
st.image("./resources/failure.png",width=100,)
|
64 |
+
st.error('An error has occurred, someone will be punished for your inconvenience, we humbly request you try again.')
|
65 |
+
st.error('Error details: {}'.format(e))
|
66 |
+
|
apps/signup.py
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import time
|
2 |
+
import os
|
3 |
+
from typing import Dict
|
4 |
+
import streamlit as st
|
5 |
+
from hydralit import HydraHeadApp
|
6 |
+
|
7 |
+
|
8 |
+
class SignUpApp(HydraHeadApp):
|
9 |
+
"""
|
10 |
+
This is an example signup application to be used to secure access within a HydraApp streamlit application.
|
11 |
+
|
12 |
+
This application is an example of allowing an application to run from the login without requiring authentication.
|
13 |
+
|
14 |
+
"""
|
15 |
+
|
16 |
+
def __init__(self, title = '', **kwargs):
|
17 |
+
self.__dict__.update(kwargs)
|
18 |
+
self.title = title
|
19 |
+
|
20 |
+
|
21 |
+
def run(self) -> None:
|
22 |
+
"""
|
23 |
+
Application entry point.
|
24 |
+
|
25 |
+
"""
|
26 |
+
|
27 |
+
st.markdown("<h1 style='text-align: center;'>Secure Hydralit Signup</h1>", unsafe_allow_html=True)
|
28 |
+
|
29 |
+
c1,c2,c3 = st.columns([2,2,2])
|
30 |
+
c3.image("./resources/lock.png",width=100,)
|
31 |
+
c3.image("./resources/hydra.png",width=100,)
|
32 |
+
|
33 |
+
pretty_btn = """
|
34 |
+
<style>
|
35 |
+
div[class="row-widget stButton"] > button {
|
36 |
+
width: 100%;
|
37 |
+
}
|
38 |
+
</style>
|
39 |
+
<br><br>
|
40 |
+
"""
|
41 |
+
c2.markdown(pretty_btn,unsafe_allow_html=True)
|
42 |
+
|
43 |
+
if 'MSG' in os.environ.keys():
|
44 |
+
st.info(os.environ['MSG'])
|
45 |
+
|
46 |
+
form_data = self._create_signup_form(c2)
|
47 |
+
|
48 |
+
pretty_btn = """
|
49 |
+
<style>
|
50 |
+
div[class="row-widget stButton"] > button {
|
51 |
+
width: 100%;
|
52 |
+
}
|
53 |
+
</style>
|
54 |
+
<br><br>
|
55 |
+
"""
|
56 |
+
c2.markdown(pretty_btn,unsafe_allow_html=True)
|
57 |
+
|
58 |
+
|
59 |
+
|
60 |
+
if form_data['submitted']:
|
61 |
+
self._do_signup(form_data, c2)
|
62 |
+
|
63 |
+
|
64 |
+
def _create_signup_form(self, parent_container) -> Dict:
|
65 |
+
|
66 |
+
login_form = parent_container.form(key="login_form")
|
67 |
+
|
68 |
+
form_state = {}
|
69 |
+
form_state['username'] = login_form.text_input('Username')
|
70 |
+
form_state['password'] = login_form.text_input('Password',type="password")
|
71 |
+
form_state['password2'] = login_form.text_input('Confirm Password',type="password")
|
72 |
+
form_state['access_level'] = login_form.selectbox('Example Access Level',(1,2))
|
73 |
+
form_state['submitted'] = login_form.form_submit_button('Sign Up')
|
74 |
+
|
75 |
+
if parent_container.button('Login',key='loginbtn'):
|
76 |
+
# set access level to a negative number to allow a kick to the unsecure_app set in the parent
|
77 |
+
self.set_access(0, None)
|
78 |
+
|
79 |
+
#Do the kick to the signup app
|
80 |
+
self.do_redirect()
|
81 |
+
|
82 |
+
return form_state
|
83 |
+
|
84 |
+
def _do_signup(self, form_data, msg_container) -> None:
|
85 |
+
if form_data['submitted'] and (form_data['password'] != form_data['password2']):
|
86 |
+
st.error('Passwords do not match, please try again.')
|
87 |
+
else:
|
88 |
+
with st.spinner("π€ now redirecting to login...."):
|
89 |
+
self._save_signup(form_data)
|
90 |
+
time.sleep(2)
|
91 |
+
|
92 |
+
#access control uses an int value to allow for levels of permission that can be set for each user, this can then be checked within each app seperately.
|
93 |
+
self.set_access(0, None)
|
94 |
+
|
95 |
+
#Do the kick back to the login screen
|
96 |
+
self.do_redirect()
|
97 |
+
|
98 |
+
def _save_signup(self, signup_data):
|
99 |
+
#get the user details from the form and save somehwere
|
100 |
+
|
101 |
+
#signup_data
|
102 |
+
# this is the data submitted
|
103 |
+
|
104 |
+
#just show the data we captured
|
105 |
+
what_we_got = f"""
|
106 |
+
captured signup details: \n
|
107 |
+
username: {signup_data['username']} \n
|
108 |
+
password: {signup_data['password']} \n
|
109 |
+
access level: {signup_data['access_level']} \n
|
110 |
+
"""
|
111 |
+
|
112 |
+
st.write(what_we_got)
|
113 |
+
|
apps/solar_mach.py
ADDED
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import datetime
|
2 |
+
import io
|
3 |
+
from hydralit import HydraHeadApp
|
4 |
+
|
5 |
+
import astropy.units as u
|
6 |
+
import pandas as pd
|
7 |
+
import streamlit as st
|
8 |
+
from astropy.coordinates import SkyCoord
|
9 |
+
from sunpy.coordinates import frames
|
10 |
+
|
11 |
+
from apps.extras.backmapping import *
|
12 |
+
import hydralit_components as hc
|
13 |
+
|
14 |
+
|
15 |
+
class SolarMach(HydraHeadApp):
|
16 |
+
|
17 |
+
def __init__(self, title = '', **kwargs):
|
18 |
+
self.__dict__.update(kwargs)
|
19 |
+
self.title = title
|
20 |
+
|
21 |
+
def run(self):
|
22 |
+
|
23 |
+
st.title('Solar-MACH')
|
24 |
+
|
25 |
+
st.subheader('Source for this great app is from the Streamlit gallery [Solar-MACH](https://github.com/jgieseler/Solar-MACH). An example of how easy it is to convert an existing application and use within a Hydralit multi-page application, see the secret saurce [here] (https://github.com/TangleSpace/hydralit).')
|
26 |
+
st.markdown('<br><br>',unsafe_allow_html=True)
|
27 |
+
st.markdown('## Multi-spacecraft longitudinal configuration plotter')
|
28 |
+
|
29 |
+
# provide date and time
|
30 |
+
with st.sidebar.container():
|
31 |
+
d = st.sidebar.date_input("Select date", datetime.date.today()-datetime.timedelta(days = 2))
|
32 |
+
t = st.sidebar.time_input('Select time', datetime.time(1, 30))
|
33 |
+
date = datetime.datetime.combine(d, t).strftime("%Y-%m-%d %H:%M:%S")
|
34 |
+
|
35 |
+
# plotting settings
|
36 |
+
with st.sidebar.container():
|
37 |
+
st.sidebar.subheader('Plot options:')
|
38 |
+
plot_spirals = st.sidebar.checkbox('Parker spiral for each body', value=True)
|
39 |
+
plot_sun_body_line = st.sidebar.checkbox('Straight line from Sun to body', value=True)
|
40 |
+
show_earth_centered_coord = st.sidebar.checkbox('Add Earth-aligned coord. system', value=False)
|
41 |
+
transparent = st.sidebar.checkbox('Transparent background', value=False)
|
42 |
+
|
43 |
+
plot_reference = st.sidebar.checkbox('Plot reference (e.g. flare)', value=True)
|
44 |
+
|
45 |
+
with st.sidebar.expander("Reference coordinates (e.g. flare)", expanded=plot_reference):
|
46 |
+
reference_sys = st.radio('Coordinate system:', ['Carrington', 'Stonyhurst'], index=0)
|
47 |
+
if reference_sys == 'Carrington':
|
48 |
+
reference_long = st.slider('Longitude:', 0, 360, 20)
|
49 |
+
reference_lat = st.slider('Latitude:', -90, 90, 0)
|
50 |
+
if reference_sys == 'Stonyhurst':
|
51 |
+
reference_long = st.slider('Longitude:', -180, 180, 20)
|
52 |
+
reference_lat = st.slider('Latitude:', -90, 90, 0)
|
53 |
+
# convert Stonyhurst coordinates to Carrington for further use:
|
54 |
+
coord = SkyCoord(reference_long*u.deg, reference_lat*u.deg, frame=frames.HeliographicStonyhurst, obstime=date)
|
55 |
+
coord = coord.transform_to(frames.HeliographicCarrington(observer='Sun'))
|
56 |
+
reference_long = coord.lon.value
|
57 |
+
reference_lat = coord.lat.value
|
58 |
+
import math
|
59 |
+
reference_vsw = int(float(st.text_input('Solar wind speed for reference', 400)))
|
60 |
+
if plot_reference is False:
|
61 |
+
reference_long = None
|
62 |
+
reference_lat = None
|
63 |
+
|
64 |
+
st.sidebar.subheader('Choose bodies/spacecraft and measured solar wind speeds')
|
65 |
+
with st.sidebar.container():
|
66 |
+
full_body_list = \
|
67 |
+
st.sidebar.text_area('Bodies/spacecraft (scroll down for example list)',
|
68 |
+
'STEREO A, Earth, BepiColombo, PSP, Solar Orbiter, Mars',
|
69 |
+
height=50)
|
70 |
+
vsw_list = \
|
71 |
+
st.sidebar.text_area('Solar wind speed per body/SC (mind the order!)', '400, 400, 400, 400, 400, 400',
|
72 |
+
height=50)
|
73 |
+
body_list = full_body_list.split(',')
|
74 |
+
vsw_list = vsw_list.split(',')
|
75 |
+
body_list = [body_list[i].strip() for i in range(len(body_list))]
|
76 |
+
wrong_vsw = False
|
77 |
+
try:
|
78 |
+
vsw_list = [int(vsw_list[i].strip()) for i in range(len(vsw_list))]
|
79 |
+
except ValueError:
|
80 |
+
wrong_vsw = True
|
81 |
+
|
82 |
+
all_bodies = print_body_list()
|
83 |
+
# ugly workaround to not show the index in the table: replace them with empty strings
|
84 |
+
all_bodies.reset_index(inplace=True)
|
85 |
+
all_bodies.index = [""] * len(all_bodies)
|
86 |
+
st.sidebar.table(all_bodies['Key'])
|
87 |
+
|
88 |
+
st.sidebar.markdown('[Complete list of available bodies](https://ssd.jpl.nasa.gov/horizons.cgi?s_target=1#top)')
|
89 |
+
|
90 |
+
if wrong_vsw:
|
91 |
+
st.error('ERROR: There is something wrong in the solar wind speed list! Maybe some missing or wrong comma?')
|
92 |
+
st.stop()
|
93 |
+
|
94 |
+
|
95 |
+
if len(body_list) == len(vsw_list):
|
96 |
+
# initialize the bodies
|
97 |
+
c = HeliosphericConstellation(date, body_list, vsw_list, reference_long,
|
98 |
+
reference_lat)
|
99 |
+
|
100 |
+
# make the longitudinal constellation plot
|
101 |
+
plot_file = 'Solar-MACH_'+datetime.datetime.combine(d, t).strftime("%Y-%m-%d_%H-%M-%S")+'.png'
|
102 |
+
|
103 |
+
c.plot(
|
104 |
+
plot_spirals=plot_spirals, # plot Parker spirals for each body
|
105 |
+
plot_sun_body_line=plot_sun_body_line, # plot straight line between Sun and body
|
106 |
+
show_earth_centered_coord=show_earth_centered_coord, # display Earth-aligned coordinate system
|
107 |
+
reference_vsw=reference_vsw, # define solar wind speed at reference
|
108 |
+
transparent = transparent,
|
109 |
+
# outfile=plot_file # output file (optional)
|
110 |
+
)
|
111 |
+
|
112 |
+
# download plot
|
113 |
+
filename = 'Solar-MACH_'+datetime.datetime.combine(d, t).strftime("%Y-%m-%d_%H-%M-%S")
|
114 |
+
plot2 = io.BytesIO()
|
115 |
+
plt.savefig(plot2, format='png', bbox_inches="tight")
|
116 |
+
# plot3 = base64.b64encode(plot2.getvalue()).decode("utf-8").replace("\n", "")
|
117 |
+
# st.markdown(f'<a href="data:file/png;base64,{plot3}" download="{plot_file}" target="_blank">Download figure as .png file</a>', unsafe_allow_html=True)
|
118 |
+
download_button_str = self.download_button(plot2.getvalue(), filename+'.png', f'Download figure as .png file', pickle_it=False)
|
119 |
+
#st.markdown(download_button_str, unsafe_allow_html=True)
|
120 |
+
|
121 |
+
# display coordinates table
|
122 |
+
df = c.coord_table
|
123 |
+
df.index = df['Spacecraft/Body']
|
124 |
+
df = df.drop(columns=['Spacecraft/Body'])
|
125 |
+
df = df.round(0)
|
126 |
+
df = df.rename(columns=
|
127 |
+
{"Spacecraft/Body": "Spacecraft / body",
|
128 |
+
"Carrington Longitude (Β°)": "Carrington longitude",
|
129 |
+
"Latitude (Β°)": "Carrington latitude",
|
130 |
+
"Heliocentric Distance (AU)": "Heliocent. distance",
|
131 |
+
"Longitudinal separation to Earth's longitude": "Longitud. separation to Earth longitude",
|
132 |
+
"Latitudinal separation to Earth's latitude": "Latitud. separation to Earth latitude",
|
133 |
+
"Vsw": "Solar wind speed",
|
134 |
+
"Magnetic footpoint longitude (Carrington)": "Magnetic footpoint Carrington longitude",
|
135 |
+
"Longitudinal separation between body and reference_long": "Longitud. separation bw. body & reference",
|
136 |
+
"Longitudinal separation between body's mangetic footpoint and reference_long": "Longitud. separation bw. body's magnetic footpoint & reference",
|
137 |
+
"Latitudinal separation between body and reference_lat": "Latitudinal separation bw. body & reference"})
|
138 |
+
st.table(df.T)
|
139 |
+
|
140 |
+
# download coordinates
|
141 |
+
# filename = 'Solar-MACH_'+datetime.datetime.combine(d, t).strftime("%Y-%m-%d_%H-%M-%S")
|
142 |
+
# csv = c.coord_table.to_csv().encode()
|
143 |
+
# b64 = base64.b64encode(csv).decode()
|
144 |
+
# st.markdown(f'<a href="data:file/csv;base64,{b64}" download="{filename}.csv" target="_blank">Download table as .csv file</a>', unsafe_allow_html=True)
|
145 |
+
download_button_str = self.download_button(c.coord_table, filename+'.csv', f'Download table as .csv file', pickle_it=False)
|
146 |
+
#st.markdown(download_button_str, unsafe_allow_html=True)
|
147 |
+
else:
|
148 |
+
st.error(f"ERROR: Number of elements in the bodies/spacecraft list \
|
149 |
+
({len(body_list)}) and solar wind speed list ({len(vsw_list)}) \
|
150 |
+
don't match! Please verify that for each body there is a solar \
|
151 |
+
wind speed provided!")
|
152 |
+
|
153 |
+
# footer
|
154 |
+
st.markdown("""---""")
|
155 |
+
st.markdown('The *Solar MAgnetic Connection Haus* (Solar-MACH) tool is a \
|
156 |
+
multi-spacecraft longitudinal configuration plotter. It was \
|
157 |
+
originally developed at the University of Kiel, Germany, and further \
|
158 |
+
discussed within the [ESA Heliophysics Archives USer (HAUS)]\
|
159 |
+
(https://www.cosmos.esa.int/web/esdc/archives-user-groups/heliophysics) \
|
160 |
+
group. It is now opened to everyone ([original code]\
|
161 |
+
(https://github.com/esdc-esac-esa-int/Solar-MACH)).')
|
162 |
+
|
163 |
+
st.markdown('[Forked and modified](https://github.com/jgieseler/Solar-MACH) by \
|
164 |
+
[J. Gieseler](https://jgieseler.github.io) (University of Turku, Finland). \
|
165 |
+
[**Get in contact**](mailto:jan.gieseler@utu.fi?subject=Solar-MACH).')
|
166 |
+
|
167 |
+
col1, col2 = st.columns((5,1))
|
168 |
+
col1.markdown("The development of the online tool has received funding from the \
|
169 |
+
European Union's Horizon 2020 research and innovation programme \
|
170 |
+
under grant agreement No 101004159 (SERPENTINE).")
|
171 |
+
col2.markdown('[<img src="https://serpentine-h2020.eu/wp-content/uploads/2021/02/SERPENTINE_logo_new.png" \
|
172 |
+
height="80">](https://serpentine-h2020.eu)', unsafe_allow_html=True)
|
173 |
+
|
174 |
+
st.markdown('Powered by: \
|
175 |
+
[<img src="https://matplotlib.org/stable/_static/logo2_compressed.svg" height="25">](https://matplotlib.org) \
|
176 |
+
[<img src="https://streamlit.io/images/brand/streamlit-logo-secondary-colormark-darktext.svg" height="30">](https://streamlit.io) \
|
177 |
+
[<img src="https://raw.githubusercontent.com/sunpy/sunpy-logo/master/generated/sunpy_logo_landscape.svg" height="30">](https://sunpy.org)', \
|
178 |
+
unsafe_allow_html=True)
|
apps/spacy_nlp.py
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import spacy_streamlit
|
2 |
+
from pathlib import Path
|
3 |
+
import streamlit as st
|
4 |
+
import srsly
|
5 |
+
import os
|
6 |
+
import importlib
|
7 |
+
|
8 |
+
from hydralit import HydraHeadApp
|
9 |
+
|
10 |
+
class SpacyNLP(HydraHeadApp):
|
11 |
+
|
12 |
+
def __init__(self, title = '', **kwargs):
|
13 |
+
self.__dict__.update(kwargs)
|
14 |
+
self.title = title
|
15 |
+
|
16 |
+
def run(self):
|
17 |
+
|
18 |
+
#st.experimental_set_query_params(selected=self.title)
|
19 |
+
|
20 |
+
MODELS = srsly.read_json(os.path.join(Path(__file__).parent,"extras","models.json"))
|
21 |
+
DEFAULT_MODEL = "en_core_web_sm"
|
22 |
+
DEFAULT_TEXT = "David Bowie moved to the US in 1974, initially staying in New York City before settling in Los Angeles."
|
23 |
+
DESCRIPTION = """**Explore trained [spaCy v3.0](https://nightly.spacy.io) pipelines**"""
|
24 |
+
|
25 |
+
def get_default_text(nlp):
|
26 |
+
# Check if spaCy has built-in example texts for the language
|
27 |
+
try:
|
28 |
+
examples = importlib.import_module(f".lang.{nlp.lang}.examples", "spacy")
|
29 |
+
return examples.sentences[0]
|
30 |
+
except (ModuleNotFoundError, ImportError):
|
31 |
+
return ""
|
32 |
+
|
33 |
+
st.subheader('Source for this great app is from the Streamlit gallery [NLP with spaCy](https://github.com/ines/spacy-streamlit-demo). An example of how easy it is to convert an existing application and use within a Hydralit multi-page application, see the secret saurce [here] (https://github.com/TangleSpace/hydralit).')
|
34 |
+
st.markdown('<br><br>',unsafe_allow_html=True)
|
35 |
+
|
36 |
+
st.info(r"Yes, this application will show an error if you don't have the 'en_core_web_sm' Spacy model installed, this was left to show that if an app crashes, it won't affect the HydraApp or the other HydraHeadApps, this app will crash and burn on it's own. If you want to fix the error, just install the missing model with [**python -m spacy download en_core_web_sm**](https://spacy.io/usage)")
|
37 |
+
spacy_streamlit.visualize(
|
38 |
+
MODELS,
|
39 |
+
default_model=DEFAULT_MODEL,
|
40 |
+
visualizers=["parser", "ner", "similarity", "tokens"],
|
41 |
+
show_visualizer_select=True,
|
42 |
+
sidebar_description=DESCRIPTION,
|
43 |
+
get_default_text=get_default_text
|
44 |
+
)
|
apps/uber_app.py
ADDED
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright 2018-2019 Streamlit Inc.
|
2 |
+
#
|
3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4 |
+
# you may not use this file except in compliance with the License.
|
5 |
+
# You may obtain a copy of the License at
|
6 |
+
#
|
7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8 |
+
#
|
9 |
+
# Unless required by applicable law or agreed to in writing, software
|
10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12 |
+
# See the License for the specific language governing permissions and
|
13 |
+
# limitations under the License.
|
14 |
+
|
15 |
+
import streamlit as st
|
16 |
+
import pandas as pd
|
17 |
+
import numpy as np
|
18 |
+
import altair as alt
|
19 |
+
import pydeck as pdk
|
20 |
+
from hydralit import HydraHeadApp
|
21 |
+
|
22 |
+
|
23 |
+
class UberNYC(HydraHeadApp):
|
24 |
+
|
25 |
+
def __init__(self, title = '', **kwargs):
|
26 |
+
self.__dict__.update(kwargs)
|
27 |
+
self.title = title
|
28 |
+
|
29 |
+
def run(self):
|
30 |
+
|
31 |
+
#st.experimental_set_query_params(selected=self.title)
|
32 |
+
print(self.title)
|
33 |
+
|
34 |
+
# LOADING DATA
|
35 |
+
DATE_TIME = "date/time"
|
36 |
+
DATA_URL = (
|
37 |
+
"http://s3-us-west-2.amazonaws.com/streamlit-demo-data/uber-raw-data-sep14.csv.gz"
|
38 |
+
)
|
39 |
+
|
40 |
+
@st.cache(persist=True)
|
41 |
+
def load_data(nrows):
|
42 |
+
data = pd.read_csv(DATA_URL, nrows=nrows)
|
43 |
+
lowercase = lambda x: str(x).lower()
|
44 |
+
data.rename(lowercase, axis="columns", inplace=True)
|
45 |
+
data[DATE_TIME] = pd.to_datetime(data[DATE_TIME])
|
46 |
+
return data
|
47 |
+
|
48 |
+
data = load_data(100000)
|
49 |
+
|
50 |
+
# CREATING FUNCTION FOR MAPS
|
51 |
+
|
52 |
+
def map(data, lat, lon, zoom):
|
53 |
+
st.write(pdk.Deck(
|
54 |
+
map_style="mapbox://styles/mapbox/light-v9",
|
55 |
+
initial_view_state={
|
56 |
+
"latitude": lat,
|
57 |
+
"longitude": lon,
|
58 |
+
"zoom": zoom,
|
59 |
+
"pitch": 50,
|
60 |
+
},
|
61 |
+
layers=[
|
62 |
+
pdk.Layer(
|
63 |
+
"HexagonLayer",
|
64 |
+
data=data,
|
65 |
+
get_position=["lon", "lat"],
|
66 |
+
radius=100,
|
67 |
+
elevation_scale=4,
|
68 |
+
elevation_range=[0, 1000],
|
69 |
+
pickable=True,
|
70 |
+
extruded=True,
|
71 |
+
),
|
72 |
+
]
|
73 |
+
))
|
74 |
+
|
75 |
+
st.subheader('Source for this great app is from the Streamlit gallery [NYC Uber Ridesharing Data](https://github.com/streamlit/demo-uber-nyc-pickups). An example of how easy it is to convert an existing application and use within a Hydralit multi-page application, see the secret saurce [here] (https://github.com/TangleSpace/hydralit).')
|
76 |
+
st.markdown('<br><br>',unsafe_allow_html=True)
|
77 |
+
|
78 |
+
# LAYING OUT THE TOP SECTION OF THE APP
|
79 |
+
row1_1, row1_2 = st.columns((2,3))
|
80 |
+
|
81 |
+
with row1_1:
|
82 |
+
st.title("NYC Uber Ridesharing Data")
|
83 |
+
|
84 |
+
hour_selected = st.slider("Select hour of pickup", 0, 23)
|
85 |
+
|
86 |
+
with row1_2:
|
87 |
+
st.write(
|
88 |
+
"""
|
89 |
+
##
|
90 |
+
Examining how Uber pickups vary over time in New York City's and at its major regional airports.
|
91 |
+
By sliding the slider on the left you can view different slices of time and explore different transportation trends.
|
92 |
+
""")
|
93 |
+
|
94 |
+
# FILTERING DATA BY HOUR SELECTED
|
95 |
+
data = data[data[DATE_TIME].dt.hour == hour_selected]
|
96 |
+
|
97 |
+
# LAYING OUT THE MIDDLE SECTION OF THE APP WITH THE MAPS
|
98 |
+
row2_1, row2_2, row2_3, row2_4 = st.columns((2,1,1,1))
|
99 |
+
|
100 |
+
# SETTING THE ZOOM LOCATIONS FOR THE AIRPORTS
|
101 |
+
la_guardia= [40.7900, -73.8700]
|
102 |
+
jfk = [40.6650, -73.7821]
|
103 |
+
newark = [40.7090, -74.1805]
|
104 |
+
zoom_level = 12
|
105 |
+
midpoint = (np.average(data["lat"]), np.average(data["lon"]))
|
106 |
+
|
107 |
+
with row2_1:
|
108 |
+
st.write("**All New York City from %i:00 and %i:00**" % (hour_selected, (hour_selected + 1) % 24))
|
109 |
+
map(data, midpoint[0], midpoint[1], 11)
|
110 |
+
|
111 |
+
with row2_2:
|
112 |
+
st.write("**La Guardia Airport**")
|
113 |
+
map(data, la_guardia[0],la_guardia[1], zoom_level)
|
114 |
+
|
115 |
+
with row2_3:
|
116 |
+
st.write("**JFK Airport**")
|
117 |
+
map(data, jfk[0],jfk[1], zoom_level)
|
118 |
+
|
119 |
+
with row2_4:
|
120 |
+
st.write("**Newark Airport**")
|
121 |
+
map(data, newark[0],newark[1], zoom_level)
|
122 |
+
|
123 |
+
# FILTERING DATA FOR THE HISTOGRAM
|
124 |
+
filtered = data[
|
125 |
+
(data[DATE_TIME].dt.hour >= hour_selected) & (data[DATE_TIME].dt.hour < (hour_selected + 1))
|
126 |
+
]
|
127 |
+
|
128 |
+
hist = np.histogram(filtered[DATE_TIME].dt.minute, bins=60, range=(0, 60))[0]
|
129 |
+
|
130 |
+
chart_data = pd.DataFrame({"minute": range(60), "pickups": hist})
|
131 |
+
|
132 |
+
# LAYING OUT THE HISTOGRAM SECTION
|
133 |
+
|
134 |
+
st.write("")
|
135 |
+
|
136 |
+
st.write("**Breakdown of rides per minute between %i:00 and %i:00**" % (hour_selected, (hour_selected + 1) % 24))
|
137 |
+
|
138 |
+
st.altair_chart(alt.Chart(chart_data)
|
139 |
+
.mark_area(
|
140 |
+
interpolate='step-after',
|
141 |
+
).encode(
|
142 |
+
x=alt.X("minute:Q", scale=alt.Scale(nice=False)),
|
143 |
+
y=alt.Y("pickups:Q"),
|
144 |
+
tooltip=['minute', 'pickups']
|
145 |
+
).configure_mark(
|
146 |
+
opacity=0.5,
|
147 |
+
color='red'
|
148 |
+
), use_container_width=True)
|
apps/walsh_app.py
ADDED
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import streamlit as st
|
3 |
+
from hydralit import HydraHeadApp
|
4 |
+
import matplotlib.pyplot as plt
|
5 |
+
import numpy as np
|
6 |
+
import pandas as pd
|
7 |
+
from hotstepper import Steps,Step
|
8 |
+
import hotstepper as hs
|
9 |
+
from itertools import chain
|
10 |
+
from hotstepper import Sequency
|
11 |
+
|
12 |
+
|
13 |
+
SIG_FIGURE_FMT = '{:,.2f}'
|
14 |
+
|
15 |
+
class WalshApp(HydraHeadApp):
|
16 |
+
|
17 |
+
|
18 |
+
def __init__(self, title = '', **kwargs):
|
19 |
+
self.__dict__.update(kwargs)
|
20 |
+
self.title = title
|
21 |
+
|
22 |
+
|
23 |
+
def run(self):
|
24 |
+
|
25 |
+
try:
|
26 |
+
st.title('Sequency Denoising')
|
27 |
+
st.subheader('Source for this quick tutorial on using Sequency methods for denoising step change data can be found in the [Hotstepper documentation](https://hotstepper.readthedocs.io/notebooks/sequency_quickstart.html). An example of how easy it is to convert an existing application and use within a Hydralit multi-page application, see the secret saurce [here] (https://github.com/TangleSpace/hydralit).')
|
28 |
+
st.markdown('<br><br>',unsafe_allow_html=True)
|
29 |
+
|
30 |
+
df_vq_samp = pd.read_csv(r'https://raw.githubusercontent.com/TangleSpace/hotstepper-data/master/data/vessel_queue.csv',parse_dates=['enter','leave'],dayfirst=True)
|
31 |
+
self.download_button(df_vq_samp,'data.csv','Download Example Data')
|
32 |
+
|
33 |
+
st.write(
|
34 |
+
"""
|
35 |
+
Another typical use case of Fourier transforms is to remove high frequency noise from a single by decomposing it into constituent frequency components and setting frequencies below a threshold value to zero. \
|
36 |
+
With Sequency analysis, we have a similar functionality, except since we have step data and we are wanting to retain the nature of the step data (as steps) instead of just smoothing away the details, \
|
37 |
+
we can use the denoise method of the Sequency module to remove the higher sequency number components. An explicit example is shown below, here for now, we pass in the direct steps data for denoising, \
|
38 |
+
apply a strength parameter to determine how many of the high sequency components are set to zero and then we construct a new Steps object.
|
39 |
+
"""
|
40 |
+
)
|
41 |
+
|
42 |
+
st.code(
|
43 |
+
"""
|
44 |
+
denoise_step_changes_strong = seq.denoise(rand_steps.step_changes(),denoise_strength=0.7,denoise_mode='range')
|
45 |
+
denoise_step_changes = seq.denoise(rand_steps.step_changes(),denoise_strength=0.2)
|
46 |
+
|
47 |
+
rand_steps_denoise_strong = Steps().add_direct(data_start=rand_steps.step_keys(),data_weight = denoise_step_changes_strong)
|
48 |
+
rand_steps_denoise = Steps().add_direct(data_start=rand_steps.step_keys(),data_weight = denoise_step_changes)
|
49 |
+
|
50 |
+
ax = rand_steps.plot(label='Original Data')
|
51 |
+
rand_steps_denoise.plot(ax=ax,color='g',linewidth=2,label='Light Denoise');
|
52 |
+
rand_steps_denoise_strong.plot(ax=ax,color='r',linewidth=2,linestyle='-',label='Strong Denoise')
|
53 |
+
ax.legend();
|
54 |
+
"""
|
55 |
+
)
|
56 |
+
|
57 |
+
denoise_power_strong_select = st.sidebar.slider('Strong Denoise Strength',value=0.7,min_value=0.01,max_value=1.0,step=0.01)
|
58 |
+
denoise_power_light_select = st.sidebar.slider('Light Denoise Strength',value=0.2,min_value=0.01,max_value=1.0,step=0.01)
|
59 |
+
denoise_mode_select = st.sidebar.radio('Denoise Mode',('range','value'))
|
60 |
+
|
61 |
+
|
62 |
+
seq = Sequency()
|
63 |
+
#Create a sequence of steps that we can analyse
|
64 |
+
steps_changes = np.random.randint(-10,12,100)
|
65 |
+
rand_steps = Steps().add_direct(data_start=list(range(1,len(steps_changes))),data_weight = steps_changes)
|
66 |
+
|
67 |
+
denoise_step_changes_strong = seq.denoise(rand_steps.step_changes(),denoise_strength=denoise_power_strong_select,denoise_mode=denoise_mode_select)
|
68 |
+
denoise_step_changes = seq.denoise(rand_steps.step_changes(),denoise_strength=denoise_power_light_select,denoise_mode=denoise_mode_select)
|
69 |
+
|
70 |
+
rand_steps_denoise_strong = Steps().add_direct(data_start=rand_steps.step_keys(),data_weight = denoise_step_changes_strong)
|
71 |
+
rand_steps_denoise = Steps().add_direct(data_start=rand_steps.step_keys(),data_weight = denoise_step_changes)
|
72 |
+
|
73 |
+
ax = rand_steps.plot(label='Original Data')
|
74 |
+
rand_steps_denoise.plot(ax=ax,color='g',linewidth=2,label='Light Denoise')
|
75 |
+
rand_steps_denoise_strong.plot(ax=ax,color='r',linewidth=2,linestyle='-',label='Strong Denoise')
|
76 |
+
ax.legend()
|
77 |
+
|
78 |
+
st.pyplot(ax.get_figure(),clear_figure=True)
|
79 |
+
|
80 |
+
|
81 |
+
st.write(
|
82 |
+
"""
|
83 |
+
As another quick example, we can apply the same technique to one of the HotStepper sample datasets, for this tutorial, weβll only look at the first two months of data in order to better highlight what the sequency denoising can do to help better show the trend or typical step behaviour of the data.
|
84 |
+
"""
|
85 |
+
)
|
86 |
+
|
87 |
+
st.code(
|
88 |
+
"""
|
89 |
+
df_vq_samp = pd.read_csv(r'https://raw.githubusercontent.com/TangleSpace/hotstepper-data/master/data/vessel_queue.csv',parse_dates=['enter','leave'],dayfirst=True)
|
90 |
+
|
91 |
+
vq_samp = Steps.read_dataframe(df_vq_samp,start='enter',end='leave')
|
92 |
+
vq_clip = vq_samp.clip(ubound=pd.Timestamp(2020,3,1))
|
93 |
+
|
94 |
+
dn = seq.denoise(vq_clip.step_changes(),denoise_mode='range')
|
95 |
+
vq_clip_dn = Steps().add_direct(data_start=vq_clip.step_keys(convert_keys=True),data_weight=dn)
|
96 |
+
|
97 |
+
ax = vq_clip.plot(label='Original Data',figsize=(14,6))
|
98 |
+
vq_clip_dn.plot(ax=ax,linewidth=3,label='Sequency Denoise')
|
99 |
+
ax.legend()
|
100 |
+
"""
|
101 |
+
)
|
102 |
+
|
103 |
+
vq_samp = Steps.read_dataframe(df_vq_samp,start='enter',end='leave')
|
104 |
+
vq_clip = vq_samp.clip(ubound=pd.Timestamp(2020,3,1))
|
105 |
+
|
106 |
+
|
107 |
+
dn_strong = seq.denoise(vq_clip.step_changes(),denoise_strength=denoise_power_strong_select,denoise_mode=denoise_mode_select)
|
108 |
+
dn_light = seq.denoise(vq_clip.step_changes(),denoise_strength=denoise_power_light_select,denoise_mode=denoise_mode_select)
|
109 |
+
|
110 |
+
vq_clip_dn_strong = Steps().add_direct(data_start=vq_clip.step_keys(convert_keys=True),data_weight=dn_strong)
|
111 |
+
vq_clip_dn_light = Steps().add_direct(data_start=vq_clip.step_keys(convert_keys=True),data_weight=dn_light)
|
112 |
+
|
113 |
+
ax = vq_clip.plot(label='Original Data',figsize=(14,6))
|
114 |
+
vq_clip_dn_strong.plot(ax=ax,linewidth=1.5,label='Strong Sequency Denoise')
|
115 |
+
vq_clip_dn_light.plot(ax=ax,linewidth=1.5,label='Light Sequency Denoise')
|
116 |
+
ax.legend()
|
117 |
+
|
118 |
+
st.pyplot(ax.get_figure(),clear_figure=True)
|
119 |
+
|
120 |
+
st.write(
|
121 |
+
"""
|
122 |
+
As the last item, we can take a look at the sequency spectrum for the vessel queue data. This dataset has a large number of changes and therefore the sequency range goes quite high, however it does show a number of peaks that are significantly larger than the others, indicating a number of distinct and repeating step change patterns within the data over this period.
|
123 |
+
"""
|
124 |
+
)
|
125 |
+
|
126 |
+
st.code(
|
127 |
+
"""
|
128 |
+
fig, (ax,ax2,ax3) = plt.subplots(nrows=3,figsize=(12,8))
|
129 |
+
fig.tight_layout(h_pad=4)
|
130 |
+
|
131 |
+
# Sequency object to use for analysis
|
132 |
+
vq_clip_seq = Sequency()
|
133 |
+
n,sp,l = vq_clip_seq.sequency_spectrum(vq_clip.step_changes())
|
134 |
+
|
135 |
+
|
136 |
+
ax.set_title('Step Change Sequency Spectrum')
|
137 |
+
ax.set_xlabel('Sequency Number')
|
138 |
+
ax.set_ylabel('Amplitude')
|
139 |
+
ax.stem(n,sp)
|
140 |
+
|
141 |
+
# number of data points, needed to create the sampling frequency
|
142 |
+
no_points = vq_clip.step_changes().shape[0]
|
143 |
+
|
144 |
+
fr,fsp = vq_clip_seq.frequency_spectrum(vq_clip.step_changes(),2*np.pi*no_points)
|
145 |
+
|
146 |
+
ax2.set_title('Step Change Frequency Spectrum')
|
147 |
+
ax2.set_xlabel('Frequency')
|
148 |
+
ax2.set_ylabel('Amplitude')
|
149 |
+
ax2.stem(fr,fsp)
|
150 |
+
|
151 |
+
# FFT the steps values instead of the delta changes to see the difference in the spectrum.
|
152 |
+
frv,fspv = vq_clip_seq.frequency_spectrum(vq_clip.step_values(),2*np.pi*no_points)
|
153 |
+
|
154 |
+
ax3.set_title('Steps Value Frequency Spectrum')
|
155 |
+
ax3.set_xlabel('Frequency')
|
156 |
+
ax3.set_ylabel('Amplitude')
|
157 |
+
ax3.stem(frv[1:],fspv[1:]);
|
158 |
+
"""
|
159 |
+
)
|
160 |
+
|
161 |
+
|
162 |
+
fig, (ax,ax2,ax3) = plt.subplots(nrows=3,figsize=(12,8))
|
163 |
+
fig.tight_layout(h_pad=4)
|
164 |
+
|
165 |
+
# Sequency object to use for analysis
|
166 |
+
vq_clip_seq = Sequency()
|
167 |
+
n,sp,l = vq_clip_seq.sequency_spectrum(vq_clip.step_changes())
|
168 |
+
|
169 |
+
|
170 |
+
ax.set_title('Step Change Sequency Spectrum')
|
171 |
+
ax.set_xlabel('Sequency Number')
|
172 |
+
ax.set_ylabel('Amplitude')
|
173 |
+
ax.stem(n,sp)
|
174 |
+
|
175 |
+
# number of data points, needed to create the sampling frequency
|
176 |
+
no_points = vq_clip.step_changes().shape[0]
|
177 |
+
|
178 |
+
fr,fsp = vq_clip_seq.frequency_spectrum(vq_clip.step_changes(),2*np.pi*no_points)
|
179 |
+
|
180 |
+
ax2.set_title('Step Change Frequency Spectrum')
|
181 |
+
ax2.set_xlabel('Frequency')
|
182 |
+
ax2.set_ylabel('Amplitude')
|
183 |
+
ax2.stem(fr,fsp)
|
184 |
+
|
185 |
+
# FFT the steps values instead of the delta changes to see the difference in the spectrum.
|
186 |
+
frv,fspv = vq_clip_seq.frequency_spectrum(vq_clip.step_values(),2*np.pi*no_points)
|
187 |
+
|
188 |
+
ax3.set_title('Steps Value Frequency Spectrum')
|
189 |
+
ax3.set_xlabel('Frequency')
|
190 |
+
ax3.set_ylabel('Amplitude')
|
191 |
+
ax3.stem(frv[1:],fspv[1:])
|
192 |
+
|
193 |
+
st.pyplot(fig,clear_figure=True)
|
194 |
+
|
195 |
+
|
196 |
+
except Exception as e:
|
197 |
+
st.image("./resources/failure.png",width=100,)
|
198 |
+
st.error('An error has occurred, someone will be punished for your inconvenience, we humbly request you try again.')
|
199 |
+
st.error('Error details: {}'.format(e))
|
200 |
+
|
apps/walsh_app_secure.py
ADDED
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import streamlit as st
|
3 |
+
from hydralit import HydraHeadApp
|
4 |
+
import matplotlib.pyplot as plt
|
5 |
+
import numpy as np
|
6 |
+
import pandas as pd
|
7 |
+
from hotstepper import Steps,Step
|
8 |
+
import hotstepper as hs
|
9 |
+
from hotstepper import Sequency
|
10 |
+
|
11 |
+
|
12 |
+
SIG_FIGURE_FMT = '{:,.2f}'
|
13 |
+
|
14 |
+
class WalshAppSecure(HydraHeadApp):
|
15 |
+
|
16 |
+
|
17 |
+
def __init__(self, title = '', **kwargs):
|
18 |
+
self.__dict__.update(kwargs)
|
19 |
+
self.title = title
|
20 |
+
|
21 |
+
|
22 |
+
def run(self):
|
23 |
+
|
24 |
+
try:
|
25 |
+
access_level,username = self.check_access()
|
26 |
+
|
27 |
+
if access_level > 1:
|
28 |
+
|
29 |
+
st.title('Sequency Denoising')
|
30 |
+
st.subheader('Source for this quick tutorial on using Sequency methods for denoising step change data can be found in the [Hotstepper documentation](https://hotstepper.readthedocs.io/notebooks/sequency_quickstart.html). An example of how easy it is to convert an existing application and use within a Hydralit multi-page application, see the secret saurce [here] (https://github.com/TangleSpace/hydralit).')
|
31 |
+
st.markdown('<br><br>',unsafe_allow_html=True)
|
32 |
+
|
33 |
+
df_vq_samp = pd.read_csv(r'https://raw.githubusercontent.com/TangleSpace/hotstepper-data/master/data/vessel_queue.csv',parse_dates=['enter','leave'],dayfirst=True)
|
34 |
+
self.download_button(df_vq_samp,'data.csv','Download Example Data')
|
35 |
+
|
36 |
+
st.write(
|
37 |
+
"""
|
38 |
+
Another typical use case of Fourier transforms is to remove high frequency noise from a single by decomposing it into constituent frequency components and setting frequencies below a threshold value to zero. \
|
39 |
+
With Sequency analysis, we have a similar functionality, except since we have step data and we are wanting to retain the nature of the step data (as steps) instead of just smoothing away the details, \
|
40 |
+
we can use the denoise method of the Sequency module to remove the higher sequency number components. An explicit example is shown below, here for now, we pass in the direct steps data for denoising, \
|
41 |
+
apply a strength parameter to determine how many of the high sequency components are set to zero and then we construct a new Steps object.
|
42 |
+
"""
|
43 |
+
)
|
44 |
+
|
45 |
+
st.code(
|
46 |
+
"""
|
47 |
+
denoise_step_changes_strong = seq.denoise(rand_steps.step_changes(),denoise_strength=0.7,denoise_mode='range')
|
48 |
+
denoise_step_changes = seq.denoise(rand_steps.step_changes(),denoise_strength=0.2)
|
49 |
+
|
50 |
+
rand_steps_denoise_strong = Steps().add_direct(data_start=rand_steps.step_keys(),data_weight = denoise_step_changes_strong)
|
51 |
+
rand_steps_denoise = Steps().add_direct(data_start=rand_steps.step_keys(),data_weight = denoise_step_changes)
|
52 |
+
|
53 |
+
ax = rand_steps.plot(label='Original Data')
|
54 |
+
rand_steps_denoise.plot(ax=ax,color='g',linewidth=2,label='Light Denoise');
|
55 |
+
rand_steps_denoise_strong.plot(ax=ax,color='r',linewidth=2,linestyle='-',label='Strong Denoise')
|
56 |
+
ax.legend();
|
57 |
+
"""
|
58 |
+
)
|
59 |
+
|
60 |
+
denoise_power_strong_select = st.sidebar.slider('Strong Denoise Strength',value=0.7,min_value=0.01,max_value=1.0,step=0.01)
|
61 |
+
denoise_power_light_select = st.sidebar.slider('Light Denoise Strength',value=0.2,min_value=0.01,max_value=1.0,step=0.01)
|
62 |
+
denoise_mode_select = st.sidebar.radio('Denoise Mode',('range','value'))
|
63 |
+
|
64 |
+
seq = Sequency()
|
65 |
+
#Create a sequence of steps that we can analyse
|
66 |
+
steps_changes = np.random.randint(-10,12,100)
|
67 |
+
rand_steps = Steps().add_direct(data_start=list(range(1,len(steps_changes))),data_weight = steps_changes)
|
68 |
+
|
69 |
+
denoise_step_changes_strong = seq.denoise(rand_steps.step_changes(),denoise_strength=denoise_power_strong_select,denoise_mode=denoise_mode_select)
|
70 |
+
denoise_step_changes = seq.denoise(rand_steps.step_changes(),denoise_strength=denoise_power_light_select,denoise_mode=denoise_mode_select)
|
71 |
+
|
72 |
+
rand_steps_denoise_strong = Steps().add_direct(data_start=rand_steps.step_keys(),data_weight = denoise_step_changes_strong)
|
73 |
+
rand_steps_denoise = Steps().add_direct(data_start=rand_steps.step_keys(),data_weight = denoise_step_changes)
|
74 |
+
|
75 |
+
ax = rand_steps.plot(label='Original Data')
|
76 |
+
rand_steps_denoise.plot(ax=ax,color='g',linewidth=2,label='Light Denoise')
|
77 |
+
rand_steps_denoise_strong.plot(ax=ax,color='r',linewidth=2,linestyle='-',label='Strong Denoise')
|
78 |
+
ax.legend()
|
79 |
+
|
80 |
+
st.pyplot(ax.get_figure(),clear_figure=True)
|
81 |
+
|
82 |
+
|
83 |
+
st.write(
|
84 |
+
"""
|
85 |
+
As another quick example, we can apply the same technique to one of the HotStepper sample datasets, for this tutorial, weβll only look at the first two months of data in order to better highlight what the sequency denoising can do to help better show the trend or typical step behaviour of the data.
|
86 |
+
"""
|
87 |
+
)
|
88 |
+
|
89 |
+
st.code(
|
90 |
+
"""
|
91 |
+
df_vq_samp = pd.read_csv(r'https://raw.githubusercontent.com/TangleSpace/hotstepper-data/master/data/vessel_queue.csv',parse_dates=['enter','leave'],dayfirst=True)
|
92 |
+
|
93 |
+
vq_samp = Steps.read_dataframe(df_vq_samp,start='enter',end='leave')
|
94 |
+
vq_clip = vq_samp.clip(ubound=pd.Timestamp(2020,3,1))
|
95 |
+
|
96 |
+
dn = seq.denoise(vq_clip.step_changes(),denoise_mode='range')
|
97 |
+
vq_clip_dn = Steps().add_direct(data_start=vq_clip.step_keys(convert_keys=True),data_weight=dn)
|
98 |
+
|
99 |
+
ax = vq_clip.plot(label='Original Data',figsize=(14,6))
|
100 |
+
vq_clip_dn.plot(ax=ax,linewidth=3,label='Sequency Denoise')
|
101 |
+
ax.legend()
|
102 |
+
"""
|
103 |
+
)
|
104 |
+
|
105 |
+
vq_samp = Steps.read_dataframe(df_vq_samp,start='enter',end='leave')
|
106 |
+
vq_clip = vq_samp.clip(ubound=pd.Timestamp(2020,3,1))
|
107 |
+
|
108 |
+
|
109 |
+
dn_strong = seq.denoise(vq_clip.step_changes(),denoise_strength=denoise_power_strong_select,denoise_mode=denoise_mode_select)
|
110 |
+
dn_light = seq.denoise(vq_clip.step_changes(),denoise_strength=denoise_power_light_select,denoise_mode=denoise_mode_select)
|
111 |
+
|
112 |
+
vq_clip_dn_strong = Steps().add_direct(data_start=vq_clip.step_keys(convert_keys=True),data_weight=dn_strong)
|
113 |
+
vq_clip_dn_light = Steps().add_direct(data_start=vq_clip.step_keys(convert_keys=True),data_weight=dn_light)
|
114 |
+
|
115 |
+
ax = vq_clip.plot(label='Original Data',figsize=(14,6))
|
116 |
+
vq_clip_dn_strong.plot(ax=ax,linewidth=1.5,label='Strong Sequency Denoise')
|
117 |
+
vq_clip_dn_light.plot(ax=ax,linewidth=1.5,label='Light Sequency Denoise')
|
118 |
+
ax.legend()
|
119 |
+
|
120 |
+
st.pyplot(ax.get_figure(),clear_figure=True)
|
121 |
+
|
122 |
+
st.write(
|
123 |
+
"""
|
124 |
+
As the last item, we can take a look at the sequency spectrum for the vessel queue data. This dataset has a large number of changes and therefore the sequency range goes quite high, however it does show a number of peaks that are significantly larger than the others, indicating a number of distinct and repeating step change patterns within the data over this period.
|
125 |
+
"""
|
126 |
+
)
|
127 |
+
|
128 |
+
st.code(
|
129 |
+
"""
|
130 |
+
fig, (ax,ax2,ax3) = plt.subplots(nrows=3,figsize=(12,8))
|
131 |
+
fig.tight_layout(h_pad=4)
|
132 |
+
|
133 |
+
# Sequency object to use for analysis
|
134 |
+
vq_clip_seq = Sequency()
|
135 |
+
n,sp,l = vq_clip_seq.sequency_spectrum(vq_clip.step_changes())
|
136 |
+
|
137 |
+
|
138 |
+
ax.set_title('Step Change Sequency Spectrum')
|
139 |
+
ax.set_xlabel('Sequency Number')
|
140 |
+
ax.set_ylabel('Amplitude')
|
141 |
+
ax.stem(n,sp)
|
142 |
+
|
143 |
+
# number of data points, needed to create the sampling frequency
|
144 |
+
no_points = vq_clip.step_changes().shape[0]
|
145 |
+
|
146 |
+
fr,fsp = vq_clip_seq.frequency_spectrum(vq_clip.step_changes(),2*np.pi*no_points)
|
147 |
+
|
148 |
+
ax2.set_title('Step Change Frequency Spectrum')
|
149 |
+
ax2.set_xlabel('Frequency')
|
150 |
+
ax2.set_ylabel('Amplitude')
|
151 |
+
ax2.stem(fr,fsp)
|
152 |
+
|
153 |
+
# FFT the steps values instead of the delta changes to see the difference in the spectrum.
|
154 |
+
frv,fspv = vq_clip_seq.frequency_spectrum(vq_clip.step_values(),2*np.pi*no_points)
|
155 |
+
|
156 |
+
ax3.set_title('Steps Value Frequency Spectrum')
|
157 |
+
ax3.set_xlabel('Frequency')
|
158 |
+
ax3.set_ylabel('Amplitude')
|
159 |
+
ax3.stem(frv[1:],fspv[1:]);
|
160 |
+
"""
|
161 |
+
)
|
162 |
+
|
163 |
+
|
164 |
+
fig, (ax,ax2,ax3) = plt.subplots(nrows=3,figsize=(12,8))
|
165 |
+
fig.tight_layout(h_pad=4)
|
166 |
+
|
167 |
+
# Sequency object to use for analysis
|
168 |
+
vq_clip_seq = Sequency()
|
169 |
+
n,sp,l = vq_clip_seq.sequency_spectrum(vq_clip.step_changes())
|
170 |
+
|
171 |
+
|
172 |
+
ax.set_title('Step Change Sequency Spectrum')
|
173 |
+
ax.set_xlabel('Sequency Number')
|
174 |
+
ax.set_ylabel('Amplitude')
|
175 |
+
ax.stem(n,sp)
|
176 |
+
|
177 |
+
# number of data points, needed to create the sampling frequency
|
178 |
+
no_points = vq_clip.step_changes().shape[0]
|
179 |
+
|
180 |
+
fr,fsp = vq_clip_seq.frequency_spectrum(vq_clip.step_changes(),2*np.pi*no_points)
|
181 |
+
|
182 |
+
ax2.set_title('Step Change Frequency Spectrum')
|
183 |
+
ax2.set_xlabel('Frequency')
|
184 |
+
ax2.set_ylabel('Amplitude')
|
185 |
+
ax2.stem(fr,fsp)
|
186 |
+
|
187 |
+
# FFT the steps values instead of the delta changes to see the difference in the spectrum.
|
188 |
+
frv,fspv = vq_clip_seq.frequency_spectrum(vq_clip.step_values(),2*np.pi*no_points)
|
189 |
+
|
190 |
+
ax3.set_title('Steps Value Frequency Spectrum')
|
191 |
+
ax3.set_xlabel('Frequency')
|
192 |
+
ax3.set_ylabel('Amplitude')
|
193 |
+
ax3.stem(frv[1:],fspv[1:])
|
194 |
+
|
195 |
+
st.pyplot(fig,clear_figure=True)
|
196 |
+
|
197 |
+
else:
|
198 |
+
_,c1,c2 = st.columns([2,2,2])
|
199 |
+
c2.image("./resources/lock.png",width=100,)
|
200 |
+
c2.image("./resources/hydra.png",width=100,)
|
201 |
+
c1.error('Sorry {}, you don\'t have enough permission to use this application, check with your local diety for more permission and try again.'.format(username))
|
202 |
+
c1.info('Go back to the login screen (logout) and select a higher access level and try again.')
|
203 |
+
|
204 |
+
|
205 |
+
|
206 |
+
except Exception as e:
|
207 |
+
st.image("./resources/failure.png",width=100,)
|
208 |
+
st.error('An error has occurred, someone will be punished for your inconvenience, we humbly request you try again.')
|
209 |
+
st.error('Error details: {}'.format(e))
|
210 |
+
|
docs/images/hydra.png
ADDED
js/exscripts.js
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
function get_st_btns() {
|
3 |
+
var all_btn = $("button.stButton");
|
4 |
+
console.log(all_btn);
|
5 |
+
}
|
6 |
+
|
7 |
+
$(document).ready(function () {
|
8 |
+
console.log('Hello from Hydralit Experimental!');
|
9 |
+
});
|
requirements.txt
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
compress_pickle
|
2 |
+
hydralit >=1.0.9
|
3 |
+
hydralit_components >=1.0.4
|
4 |
+
streamlit >=0.89
|
5 |
+
numpy==1.20
|
6 |
+
hotstepper
|
7 |
+
altair
|
8 |
+
pandas
|
9 |
+
spacy
|
10 |
+
validators
|
11 |
+
bokeh
|
12 |
+
srsly
|
13 |
+
spacy-streamlit
|
14 |
+
astroquery
|
15 |
+
sunpy
|
16 |
+
astropy
|
17 |
+
pydeck
|
18 |
+
scipy
|
resources/belgium.png
ADDED
resources/brain.png
ADDED
resources/classroom.png
ADDED
resources/dart.png
ADDED
resources/data.png
ADDED
resources/denoise.png
ADDED
resources/exchange.png
ADDED
resources/failure.png
ADDED
resources/hydra.png
ADDED
resources/jquery.js
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(g,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),m={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},w=g.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||w).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",E=function(e,t){return new E.fn.init(e,t)};function d(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!b(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}E.fn=E.prototype={jquery:f,constructor:E,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=E.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return E.each(this,e)},map:function(n){return this.pushStack(E.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(E.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(E.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},E.extend=E.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||b(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(E.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||E.isPlainObject(n)?n:{},i=!1,a[t]=E.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},E.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=y.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){C(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(d(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(d(Object(e))?E.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(d(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return v(a)},guid:1,support:m}),"function"==typeof Symbol&&(E.fn[Symbol.iterator]=t[Symbol.iterator]),E.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var p=function(n){var e,p,x,o,i,h,f,g,w,u,l,C,T,a,E,v,s,c,y,A="sizzle"+1*new Date,d=n.document,N=0,r=0,m=ue(),b=ue(),S=ue(),k=ue(),D=function(e,t){return e===t&&(l=!0),0},L={}.hasOwnProperty,t=[],j=t.pop,q=t.push,O=t.push,P=t.slice,H=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},I="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",R="[\\x20\\t\\r\\n\\f]",B="(?:\\\\[\\da-fA-F]{1,6}"+R+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",M="\\["+R+"*("+B+")(?:"+R+"*([*^$|!~]?=)"+R+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+B+"))|)"+R+"*\\]",W=":("+B+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+M+")*)|.*)\\)|)",F=new RegExp(R+"+","g"),$=new RegExp("^"+R+"+|((?:^|[^\\\\])(?:\\\\.)*)"+R+"+$","g"),z=new RegExp("^"+R+"*,"+R+"*"),_=new RegExp("^"+R+"*([>+~]|"+R+")"+R+"*"),U=new RegExp(R+"|>"),V=new RegExp(W),X=new RegExp("^"+B+"$"),Q={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),TAG:new RegExp("^("+B+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),bool:new RegExp("^(?:"+I+")$","i"),needsContext:new RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+R+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{O.apply(t=P.call(d.childNodes),d.childNodes),t[d.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!k[t+" "]&&(!v||!v.test(t))&&(1!==d||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&(U.test(t)||_.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&p.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=A)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+be(l[o]);c=l.join(",")}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){k(t,!0)}finally{s===A&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[A]=!0,e}function ce(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:d;return r!=T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),d!=T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),p.scope=ce(function(e){return a.appendChild(e).appendChild(T.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),p.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment("")),!e.getElementsByTagName("*").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=A,!T.getElementsByName||!T.getElementsByName(A).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="<a id='"+A+"'></a><select id='"+A+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+R+"*(?:value|"+I+")"),e.querySelectorAll("[id~="+A+"-]").length||v.push("~="),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+R+"*name"+R+"*="+R+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+A+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=T.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+R+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e==T||e.ownerDocument==d&&y(d,e)?-1:t==T||t.ownerDocument==d&&y(d,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==T?-1:t==T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]==d?-1:s[r]==d?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(C(e),p.matchesSelector&&E&&!k[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){k(t,!0)}return 0<se(t,T,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=T&&C(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=T&&C(e);var n=x.attrHandle[t.toLowerCase()],r=n&&L.call(x.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:p.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!p.detectDuplicates,u=!p.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(x=se.selectors={cacheLength:50,createPseudo:le,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(F," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),b="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=b&&e.nodeName.toLowerCase(),d=!n&&!b,p=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(b?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&d){p=(s=(r=(i=(o=(a=c)[A]||(a[A]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===N&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(p=s=0)||u.pop())if(1===a.nodeType&&++p&&a===e){i[h]=[N,s,p];break}}else if(d&&(p=s=(r=(i=(o=(a=e)[A]||(a[A]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===N&&r[1]),!1===p)while(a=++s&&a&&a[l]||(p=s=0)||u.pop())if((b?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++p&&(d&&((i=(o=a[A]||(a[A]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[N,p]),a===e))break;return(p-=v)===g||p%g==0&&0<=p/g}}},PSEUDO:function(e,o){var t,a=x.pseudos[e]||x.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[A]?a(o):1<a.length?(t=[e,e,"",o],x.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=H(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,"$1"));return s[A]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return X.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===T.activeElement&&(!T.hasFocus||T.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!x.pseudos.empty(e)},header:function(e){return K.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=x.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})x.pseudos[e]=pe(e);for(e in{submit:!0,reset:!0})x.pseudos[e]=he(e);function me(){}function be(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function xe(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,d=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[N,d];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[A]||(e[A]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===N&&r[1]===d)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Ce(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Te(p,h,g,v,y,e){return v&&!v[A]&&(v=Te(v)),y&&!y[A]&&(y=Te(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!p||!e&&h?c:Ce(c,s,p,n,r),d=g?y||(e?p:l||v)?[]:t:f;if(g&&g(f,d,n,r),v){i=Ce(d,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(d[u[o]]=!(f[u[o]]=a))}if(e){if(y||p){if(y){i=[],o=d.length;while(o--)(a=d[o])&&i.push(f[o]=a);y(null,d=[],i,r)}o=d.length;while(o--)(a=d[o])&&-1<(i=y?H(e,a):s[o])&&(e[i]=!(t[i]=a))}}else d=Ce(d===t?d.splice(l,d.length):d),y?y(null,t,d,r):O.apply(t,d)})}function Ee(e){for(var i,t,n,r=e.length,o=x.relative[e[0].type],a=o||x.relative[" "],s=o?1:0,u=xe(function(e){return e===i},a,!0),l=xe(function(e){return-1<H(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=x.relative[e[s].type])c=[xe(we(c),t)];else{if((t=x.filter[e[s].type].apply(null,e[s].matches))[A]){for(n=++s;n<r;n++)if(x.relative[e[n].type])break;return Te(1<s&&we(c),1<s&&be(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&be(e))}c.push(t)}return we(c)}return me.prototype=x.filters=x.pseudos,x.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=b[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=x.preFilter;while(a){for(o in n&&!(r=z.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=_.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($," ")}),a=a.slice(n.length)),x.filter)!(r=Q[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):b(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,b,r,i=[],o=[],a=S[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[A]?i.push(a):o.push(a);(a=S(e,(v=o,m=0<(y=i).length,b=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],d=w,p=e||b&&x.find.TAG("*",i),h=N+=null==d?1:Math.random()||.1,g=p.length;for(i&&(w=t==T||t||i);l!==g&&null!=(o=p[l]);l++){if(b&&o){a=0,t||o.ownerDocument==T||(C(o),n=!E);while(s=v[a++])if(s(o,t||T,n)){r.push(o);break}i&&(N=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=j.call(r));f=Ce(f)}O.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(N=h,w=d),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&x.relative[o[1].type]){if(!(t=(x.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=Q.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],x.relative[s=a.type])break;if((u=x.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&be(o)))return O.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},p.sortStable=A.split("").sort(D).join("")===A,p.detectDuplicates=!!l,C(),p.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(T.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),p.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(I,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(g);E.find=p,E.expr=p.selectors,E.expr[":"]=E.expr.pseudos,E.uniqueSort=E.unique=p.uniqueSort,E.text=p.getText,E.isXMLDoc=p.isXML,E.contains=p.contains,E.escapeSelector=p.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&E(e).is(n))break;r.push(e)}return r},A=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=E.expr.match.needsContext;function S(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var k=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1<i.call(n,e)!==r}):E.filter(n,e,r)}E.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?E.find.matchesSelector(r,e)?[r]:[]:E.find.matches(e,E.grep(t,function(e){return 1===e.nodeType}))},E.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(E(e).filter(function(){for(t=0;t<r;t++)if(E.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)E.find(e,i[t],n);return 1<r?E.uniqueSort(n):n},filter:function(e){return this.pushStack(D(this,e||[],!1))},not:function(e){return this.pushStack(D(this,e||[],!0))},is:function(e){return!!D(this,"string"==typeof e&&N.test(e)?E(e):e||[],!1).length}});var L,j=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||L,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:j.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:w,!0)),k.test(r[1])&&E.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=w.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,L=E(w);var q=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(E.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&E(e);if(!N.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&E.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?E.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(E(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(E.uniqueSort(E.merge(this.get(),E(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),E.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t,n){return h(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return h(e,"nextSibling")},prevAll:function(e){return h(e,"previousSibling")},nextUntil:function(e,t,n){return h(e,"nextSibling",n)},prevUntil:function(e,t,n){return h(e,"previousSibling",n)},siblings:function(e){return A((e.parentNode||{}).firstChild,e)},children:function(e){return A(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(S(e,"template")&&(e=e.content||e),E.merge([],e.childNodes))}},function(r,i){E.fn[r]=function(e,t){var n=E.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=E.filter(t,n)),1<this.length&&(O[r]||E.uniqueSort(n),q.test(r)&&n.reverse()),this.pushStack(n)}});var H=/[^\x20\t\r\n\f]+/g;function I(e){return e}function R(e){throw e}function B(e,t,n,r){var i;try{e&&b(i=e.promise)?i.call(e).done(t).fail(n):e&&b(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}E.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},E.each(e.match(H)||[],function(e,t){n[t]=!0}),n):E.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){E.each(e,function(e,t){b(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==T(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return E.each(arguments,function(e,t){var n;while(-1<(n=E.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<E.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},E.extend({Deferred:function(e){var o=[["notify","progress",E.Callbacks("memory"),E.Callbacks("memory"),2],["resolve","done",E.Callbacks("once memory"),E.Callbacks("once memory"),0,"resolved"],["reject","fail",E.Callbacks("once memory"),E.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return E.Deferred(function(r){E.each(o,function(e,t){var n=b(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&b(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,b(t)?s?t.call(e,l(u,o,I,s),l(u,o,R,s)):(u++,t.call(e,l(u,o,I,s),l(u,o,R,s),l(u,o,I,o.notifyWith))):(a!==I&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){E.Deferred.exceptionHook&&E.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==R&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(E.Deferred.getStackHook&&(t.stackTrace=E.Deferred.getStackHook()),g.setTimeout(t))}}return E.Deferred(function(e){o[0][3].add(l(0,e,b(r)?r:I,e.notifyWith)),o[1][3].add(l(0,e,b(t)?t:I)),o[2][3].add(l(0,e,b(n)?n:R))}).promise()},promise:function(e){return null!=e?E.extend(e,a):a}},s={};return E.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=E.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(B(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||b(i[t]&&i[t].then)))return o.then();while(t--)B(i[t],a(t),o.reject);return o.promise()}});var M=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;E.Deferred.exceptionHook=function(e,t){g.console&&g.console.warn&&e&&M.test(e.name)&&g.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},E.readyException=function(e){g.setTimeout(function(){throw e})};var W=E.Deferred();function F(){w.removeEventListener("DOMContentLoaded",F),g.removeEventListener("load",F),E.ready()}E.fn.ready=function(e){return W.then(e)["catch"](function(e){E.readyException(e)}),this},E.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--E.readyWait:E.isReady)||(E.isReady=!0)!==e&&0<--E.readyWait||W.resolveWith(w,[E])}}),E.ready.then=W.then,"complete"===w.readyState||"loading"!==w.readyState&&!w.documentElement.doScroll?g.setTimeout(E.ready):(w.addEventListener("DOMContentLoaded",F),g.addEventListener("load",F));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===T(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,b(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(E(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},z=/^-ms-/,_=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function V(e){return e.replace(z,"ms-").replace(_,U)}var X=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Q(){this.expando=E.expando+Q.uid++}Q.uid=1,Q.prototype={cache:function(e){var t=e[this.expando];return t||(t={},X(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[V(t)]=n;else for(r in t)i[V(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][V(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(V):(t=V(t))in r?[t]:t.match(H)||[]).length;while(n--)delete r[t[n]]}(void 0===t||E.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!E.isEmptyObject(t)}};var Y=new Q,G=new Q,K=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,J=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(J,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:K.test(i)?JSON.parse(i):i)}catch(e){}G.set(e,t,n)}else n=void 0;return n}E.extend({hasData:function(e){return G.hasData(e)||Y.hasData(e)},data:function(e,t,n){return G.access(e,t,n)},removeData:function(e,t){G.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),E.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=G.get(o),1===o.nodeType&&!Y.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=V(r.slice(5)),Z(o,r,i[r]));Y.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){G.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=G.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){G.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){G.remove(this,e)})}}),E.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,E.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=E.queue(e,t),r=n.length,i=n.shift(),o=E._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){E.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Y.get(e,n)||Y.access(e,n,{empty:E.Callbacks("once memory").add(function(){Y.remove(e,[t+"queue",n])})})}}),E.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?E.queue(this[0],t):void 0===n?this:this.each(function(){var e=E.queue(this,t,n);E._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&E.dequeue(this,t)})},dequeue:function(e){return this.each(function(){E.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=E.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Y.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,te=new RegExp("^(?:([+-])=|)("+ee+")([a-z%]*)$","i"),ne=["Top","Right","Bottom","Left"],re=w.documentElement,ie=function(e){return E.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return E.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&ie(e)&&"none"===E.css(e,"display")};var se={};function ue(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Y.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=se[s])||(o=a.body.appendChild(a.createElement(s)),u=E.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),se[s]=u)))):"none"!==n&&(l[c]="none",Y.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}E.fn.extend({show:function(){return ue(this,!0)},hide:function(){return ue(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?E(this).show():E(this).hide()})}});var le,ce,fe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,pe=/^$|^module$|\/(?:java|ecma)script/i;le=w.createDocumentFragment().appendChild(w.createElement("div")),(ce=w.createElement("input")).setAttribute("type","radio"),ce.setAttribute("checked","checked"),ce.setAttribute("name","t"),le.appendChild(ce),m.checkClone=le.cloneNode(!0).cloneNode(!0).lastChild.checked,le.innerHTML="<textarea>x</textarea>",m.noCloneChecked=!!le.cloneNode(!0).lastChild.defaultValue,le.innerHTML="<option></option>",m.option=!!le.lastChild;var he={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ge(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],"globalEval",!t||Y.get(t[n],"globalEval"))}he.tbody=he.tfoot=he.colgroup=he.caption=he.thead,he.th=he.td,m.option||(he.optgroup=he.option=[1,"<select multiple='multiple'>","</select>"]);var ye=/<|&#?\w+;/;function me(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p<h;p++)if((o=e[p])||0===o)if("object"===T(o))E.merge(d,o.nodeType?[o]:o);else if(ye.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=he[s]||he._default,a.innerHTML=u[1]+E.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;E.merge(d,a.childNodes),(a=f.firstChild).textContent=""}else d.push(t.createTextNode(o));f.textContent="",p=0;while(o=d[p++])if(r&&-1<E.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ge(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])pe.test(o.type||"")&&n.push(o)}return f}var be=/^([^.]*)(?:\.(.+)|)/;function xe(){return!0}function we(){return!1}function Ce(e,t){return e===function(){try{return w.activeElement}catch(e){}}()==("focus"===t)}function Te(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Te(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=we;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return E().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=E.guid++)),e.each(function(){E.event.add(this,t,i,r,n)})}function Ee(e,i,o){o?(Y.set(e,i,!1),E.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(E.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n&&n.value}else r.length&&(Y.set(this,i,{value:E.event.trigger(E.extend(r[0],E.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&E.event.add(e,i,xe)}E.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,d,p,h,g,v=Y.get(t);if(X(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&E.find.matchesSelector(re,i),n.guid||(n.guid=E.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof E&&E.event.triggered!==e.type?E.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(H)||[""]).length;while(l--)p=g=(s=be.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),p&&(f=E.event.special[p]||{},p=(i?f.delegateType:f.bindType)||p,f=E.event.special[p]||{},c=E.extend({type:p,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&E.expr.match.needsContext.test(i),namespace:h.join(".")},o),(d=u[p])||((d=u[p]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(p,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?d.splice(d.delegateCount++,0,c):d.push(c),E.event.global[p]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,d,p,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(H)||[""]).length;while(l--)if(p=g=(s=be.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),p){f=E.event.special[p]||{},d=u[p=(r?f.delegateType:f.bindType)||p]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=d.length;while(o--)c=d[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(d.splice(o,1),c.selector&&d.delegateCount--,f.remove&&f.remove.call(e,c));a&&!d.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||E.removeEvent(e,p,v.handle),delete u[p])}else for(p in u)E.event.remove(e,p+t[l],n,r,!0);E.isEmptyObject(u)&&Y.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=E.event.fix(e),l=(Y.get(this,"events")||Object.create(null))[u.type]||[],c=E.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=E.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((E.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<E(i,this).index(l):E.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(E.Event.prototype,t,{enumerable:!0,configurable:!0,get:b(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[E.expando]?e:new E.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return fe.test(t.type)&&t.click&&S(t,"input")&&Ee(t,"click",xe),!1},trigger:function(e){var t=this||e;return fe.test(t.type)&&t.click&&S(t,"input")&&Ee(t,"click"),!0},_default:function(e){var t=e.target;return fe.test(t.type)&&t.click&&S(t,"input")&&Y.get(t,"click")||S(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},E.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},E.Event=function(e,t){if(!(this instanceof E.Event))return new E.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?xe:we,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&E.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[E.expando]=!0},E.Event.prototype={constructor:E.Event,isDefaultPrevented:we,isPropagationStopped:we,isImmediatePropagationStopped:we,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=xe,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=xe,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=xe,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},E.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:!0},E.event.addProp),E.each({focus:"focusin",blur:"focusout"},function(e,t){E.event.special[e]={setup:function(){return Ee(this,e,Ce),!1},trigger:function(){return Ee(this,e),!0},_default:function(){return!0},delegateType:t}}),E.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){E.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||E.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),E.fn.extend({on:function(e,t,n,r){return Te(this,e,t,n,r)},one:function(e,t,n,r){return Te(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,E(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=we),this.each(function(){E.event.remove(this,e,n,t)})}});var Ae=/<script|<style|<link/i,Ne=/checked\s*(?:[^=]|=\s*.checked.)/i,Se=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function ke(e,t){return S(e,"table")&&S(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Le(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function je(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)E.event.add(t,i,s[i][n]);G.hasData(e)&&(o=G.access(e),a=E.extend({},o),G.set(t,a))}}function qe(n,r,i,o){r=v(r);var e,t,a,s,u,l,c=0,f=n.length,d=f-1,p=r[0],h=b(p);if(h||1<f&&"string"==typeof p&&!m.checkClone&&Ne.test(p))return n.each(function(e){var t=n.eq(e);h&&(r[0]=p.call(this,e,t.html())),qe(t,r,i,o)});if(f&&(t=(e=me(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=E.map(ge(e,"script"),De)).length;c<f;c++)u=e,c!==d&&(u=E.clone(u,!0,!0),s&&E.merge(a,ge(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,E.map(a,Le),c=0;c<s;c++)u=a[c],pe.test(u.type||"")&&!Y.access(u,"globalEval")&&E.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?E._evalUrl&&!u.noModule&&E._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):C(u.textContent.replace(Se,""),u,l))}return n}function Oe(e,t,n){for(var r,i=t?E.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||E.cleanData(ge(r)),r.parentNode&&(n&&ie(r)&&ve(ge(r,"script")),r.parentNode.removeChild(r));return e}E.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(m.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||E.isXMLDoc(e)))for(a=ge(c),r=0,i=(o=ge(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&fe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ge(e),a=a||ge(c),r=0,i=o.length;r<i;r++)je(o[r],a[r]);else je(e,c);return 0<(a=ge(c,"script")).length&&ve(a,!f&&ge(e,"script")),c},cleanData:function(e){for(var t,n,r,i=E.event.special,o=0;void 0!==(n=e[o]);o++)if(X(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?E.event.remove(n,r):E.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[G.expando]&&(n[G.expando]=void 0)}}}),E.fn.extend({detach:function(e){return Oe(this,e,!0)},remove:function(e){return Oe(this,e)},text:function(e){return $(this,function(e){return void 0===e?E.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return qe(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||ke(this,e).appendChild(e)})},prepend:function(){return qe(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=ke(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return qe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return qe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(E.cleanData(ge(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return E.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!he[(de.exec(e)||["",""])[1].toLowerCase()]){e=E.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(E.cleanData(ge(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return qe(this,arguments,function(e){var t=this.parentNode;E.inArray(this,n)<0&&(E.cleanData(ge(this)),t&&t.replaceChild(e,this))},n)}}),E.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){E.fn[e]=function(e){for(var t,n=[],r=E(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),E(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Pe=new RegExp("^("+ee+")(?!px)[a-z%]+$","i"),He=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=g),t.getComputedStyle(e)},Ie=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Re=new RegExp(ne.join("|"),"i");function Be(e,t,n){var r,i,o,a,s=e.style;return(n=n||He(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=E.style(e,t)),!m.pixelBoxStyles()&&Pe.test(a)&&Re.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function Me(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",re.appendChild(u).appendChild(l);var e=g.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=w.createElement("div"),l=w.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",m.clearCloneStyle="content-box"===l.style.backgroundClip,E.extend(m,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=w.createElement("table"),t=w.createElement("tr"),n=w.createElement("div"),e.style.cssText="position:absolute;left:-11111px;border-collapse:separate",t.style.cssText="border:1px solid",t.style.height="1px",n.style.height="9px",n.style.display="block",re.appendChild(e).appendChild(t).appendChild(n),r=g.getComputedStyle(t),a=parseInt(r.height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===t.offsetHeight,re.removeChild(e)),a}}))}();var We=["Webkit","Moz","ms"],Fe=w.createElement("div").style,$e={};function ze(e){var t=E.cssProps[e]||$e[e];return t||(e in Fe?e:$e[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=We.length;while(n--)if((e=We[n]+t)in Fe)return e}(e)||e)}var _e,Ue,Ve=/^(none|table(?!-c[ea]).+)/,Xe=/^--/,Qe={position:"absolute",visibility:"hidden",display:"block"},Ye={letterSpacing:"0",fontWeight:"400"};function Ge(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Ke(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=E.css(e,n+ne[a],!0,i)),r?("content"===n&&(u-=E.css(e,"padding"+ne[a],!0,i)),"margin"!==n&&(u-=E.css(e,"border"+ne[a]+"Width",!0,i))):(u+=E.css(e,"padding"+ne[a],!0,i),"padding"!==n?u+=E.css(e,"border"+ne[a]+"Width",!0,i):s+=E.css(e,"border"+ne[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Je(e,t,n){var r=He(e),i=(!m.boxSizingReliable()||n)&&"border-box"===E.css(e,"boxSizing",!1,r),o=i,a=Be(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Pe.test(a)){if(!n)return a;a="auto"}return(!m.boxSizingReliable()&&i||!m.reliableTrDimensions()&&S(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===E.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===E.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Ke(e,t,n||(i?"border":"content"),o,r,a)+"px"}E.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Be(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=V(t),u=Xe.test(t),l=e.style;if(u||(t=ze(s)),a=E.cssHooks[t]||E.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=function(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return E.css(e,t,"")},u=s(),l=n&&n[3]||(E.cssNumber[t]?"":"px"),c=e.nodeType&&(E.cssNumber[t]||"px"!==l&&+u)&&te.exec(E.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)E.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,E.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(E.cssNumber[s]?"":"px")),m.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=V(t);return Xe.test(t)||(t=ze(s)),(a=E.cssHooks[t]||E.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Be(e,t,r)),"normal"===i&&t in Ye&&(i=Ye[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),E.each(["height","width"],function(e,u){E.cssHooks[u]={get:function(e,t,n){if(t)return!Ve.test(E.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Je(e,u,n):Ie(e,Qe,function(){return Je(e,u,n)})},set:function(e,t,n){var r,i=He(e),o=!m.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===E.css(e,"boxSizing",!1,i),s=n?Ke(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Ke(e,u,"border",!1,i)-.5)),s&&(r=te.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=E.css(e,u)),Ge(0,t,s)}}}),E.cssHooks.marginLeft=Me(m.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Be(e,"marginLeft"))||e.getBoundingClientRect().left-Ie(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),E.each({margin:"",padding:"",border:"Width"},function(i,o){E.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(E.cssHooks[i+o].set=Ge)}),E.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=He(e),i=t.length;a<i;a++)o[t[a]]=E.css(e,t[a],!1,r);return o}return void 0!==n?E.style(e,t,n):E.css(e,t)},e,t,1<arguments.length)}}),E.fn.delay=function(r,e){return r=E.fx&&E.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=g.setTimeout(e,r);t.stop=function(){g.clearTimeout(n)}})},_e=w.createElement("input"),Ue=w.createElement("select").appendChild(w.createElement("option")),_e.type="checkbox",m.checkOn=""!==_e.value,m.optSelected=Ue.selected,(_e=w.createElement("input")).value="t",_e.type="radio",m.radioValue="t"===_e.value;var Ze,et=E.expr.attrHandle;E.fn.extend({attr:function(e,t){return $(this,E.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){E.removeAttr(this,e)})}}),E.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?E.prop(e,t,n):(1===o&&E.isXMLDoc(e)||(i=E.attrHooks[t.toLowerCase()]||(E.expr.match.bool.test(t)?Ze:void 0)),void 0!==n?null===n?void E.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=E.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!m.radioValue&&"radio"===t&&S(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(H);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),Ze={set:function(e,t,n){return!1===t?E.removeAttr(e,n):e.setAttribute(n,n),n}},E.each(E.expr.match.bool.source.match(/\w+/g),function(e,t){var a=et[t]||E.find.attr;et[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=et[o],et[o]=r,r=null!=a(e,t,n)?o:null,et[o]=i),r}});var tt=/^(?:input|select|textarea|button)$/i,nt=/^(?:a|area)$/i;function rt(e){return(e.match(H)||[]).join(" ")}function it(e){return e.getAttribute&&e.getAttribute("class")||""}function ot(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(H)||[]}E.fn.extend({prop:function(e,t){return $(this,E.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[E.propFix[e]||e]})}}),E.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&E.isXMLDoc(e)||(t=E.propFix[t]||t,i=E.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=E.find.attr(e,"tabindex");return t?parseInt(t,10):tt.test(e.nodeName)||nt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),m.optSelected||(E.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),E.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){E.propFix[this.toLowerCase()]=this}),E.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(b(t))return this.each(function(e){E(this).addClass(t.call(this,e,it(this)))});if((e=ot(t)).length)while(n=this[u++])if(i=it(n),r=1===n.nodeType&&" "+rt(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=rt(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(b(t))return this.each(function(e){E(this).removeClass(t.call(this,e,it(this)))});if(!arguments.length)return this.attr("class","");if((e=ot(t)).length)while(n=this[u++])if(i=it(n),r=1===n.nodeType&&" "+rt(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=rt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):b(i)?this.each(function(e){E(this).toggleClass(i.call(this,e,it(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=E(this),r=ot(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=it(this))&&Y.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Y.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+rt(it(n))+" ").indexOf(t))return!0;return!1}});var at=/\r/g;E.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=b(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,E(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=E.map(t,function(e){return null==e?"":e+""})),(r=E.valHooks[this.type]||E.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=E.valHooks[t.type]||E.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(at,""):null==e?"":e:void 0}}),E.extend({valHooks:{option:{get:function(e){var t=E.find.attr(e,"value");return null!=t?t:rt(E.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!S(n.parentNode,"optgroup"))){if(t=E(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=E.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<E.inArray(E.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),E.each(["radio","checkbox"],function(){E.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<E.inArray(E(e).val(),t)}},m.checkOn||(E.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),m.focusin="onfocusin"in g;var st=/^(?:focusinfocus|focusoutblur)$/,ut=function(e){e.stopPropagation()};E.extend(E.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,d=[n||w],p=y.call(e,"type")?e.type:e,h=y.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||w,3!==n.nodeType&&8!==n.nodeType&&!st.test(p+E.event.triggered)&&(-1<p.indexOf(".")&&(p=(h=p.split(".")).shift(),h.sort()),u=p.indexOf(":")<0&&"on"+p,(e=e[E.expando]?e:new E.Event(p,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:E.makeArray(t,[e]),c=E.event.special[p]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||p,st.test(s+p)||(o=o.parentNode);o;o=o.parentNode)d.push(o),a=o;a===(n.ownerDocument||w)&&d.push(a.defaultView||a.parentWindow||g)}i=0;while((o=d[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||p,(l=(Y.get(o,"events")||Object.create(null))[e.type]&&Y.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&X(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=p,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(d.pop(),t)||!X(n)||u&&b(n[p])&&!x(n)&&((a=n[u])&&(n[u]=null),E.event.triggered=p,e.isPropagationStopped()&&f.addEventListener(p,ut),n[p](),e.isPropagationStopped()&&f.removeEventListener(p,ut),E.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=E.extend(new E.Event,n,{type:e,isSimulated:!0});E.event.trigger(r,null,t)}}),E.fn.extend({trigger:function(e,t){return this.each(function(){E.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return E.event.trigger(e,t,n,!0)}}),m.focusin||E.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){E.event.simulate(r,e.target,E.event.fix(e))};E.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}}),E.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new g.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||E.error("Invalid XML: "+(n?E.map(n.childNodes,function(e){return e.textContent}).join("\n"):e)),t};var lt,ct=/\[\]$/,ft=/\r?\n/g,dt=/^(?:submit|button|image|reset|file)$/i,pt=/^(?:input|select|textarea|keygen)/i;function ht(n,e,r,i){var t;if(Array.isArray(e))E.each(e,function(e,t){r||ct.test(n)?i(n,t):ht(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==T(e))i(n,e);else for(t in e)ht(n+"["+t+"]",e[t],r,i)}E.param=function(e,t){var n,r=[],i=function(e,t){var n=b(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!E.isPlainObject(e))E.each(e,function(){i(this.name,this.value)});else for(n in e)ht(n,e[n],t,i);return r.join("&")},E.fn.extend({serialize:function(){return E.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=E.prop(this,"elements");return e?E.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!E(this).is(":disabled")&&pt.test(this.nodeName)&&!dt.test(e)&&(this.checked||!fe.test(e))}).map(function(e,t){var n=E(this).val();return null==n?null:Array.isArray(n)?E.map(n,function(e){return{name:t.name,value:e.replace(ft,"\r\n")}}):{name:t.name,value:n.replace(ft,"\r\n")}}).get()}}),E.fn.extend({wrapAll:function(e){var t;return this[0]&&(b(e)&&(e=e.call(this[0])),t=E(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return b(n)?this.each(function(e){E(this).wrapInner(n.call(this,e))}):this.each(function(){var e=E(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=b(t);return this.each(function(e){E(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){E(this).replaceWith(this.childNodes)}),this}}),E.expr.pseudos.hidden=function(e){return!E.expr.pseudos.visible(e)},E.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},m.createHTMLDocument=((lt=w.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===lt.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(m.createHTMLDocument?((r=(t=w.implementation.createHTMLDocument("")).createElement("base")).href=w.location.href,t.head.appendChild(r)):t=w),o=!n&&[],(i=k.exec(e))?[t.createElement(i[1])]:(i=me([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),b(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=Me(m.pixelPosition,function(e,t){if(t)return t=Be(e,n),Pe.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var gt=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;E.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),b(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||E.guid++,i},E.holdReady=function(e){e?E.readyWait++:E.ready(!0)},E.isArray=Array.isArray,E.parseJSON=JSON.parse,E.nodeName=S,E.isFunction=b,E.isWindow=x,E.camelCase=V,E.type=T,E.now=Date.now,E.isNumeric=function(e){var t=E.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},E.trim=function(e){return null==e?"":(e+"").replace(gt,"")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return E});var vt=g.jQuery,yt=g.$;return E.noConflict=function(e){return g.$===E&&(g.$=yt),e&&g.jQuery===E&&(g.jQuery=vt),E},"undefined"==typeof e&&(g.jQuery=g.$=E),E});
|
resources/lock.png
ADDED
resources/satellite.png
ADDED
resources/search.png
ADDED
resources/taxi.png
ADDED
resources/vessel.png
ADDED
runtime.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
python-3.7.12
|
secure_app.py
ADDED
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from hydralit import HydraApp
|
2 |
+
import hydralit_components as hc
|
3 |
+
import apps
|
4 |
+
import streamlit as st
|
5 |
+
|
6 |
+
#Only need to set these here as we are add controls outside of Hydralit, to customise a run Hydralit!
|
7 |
+
st.set_page_config(page_title='Secure Hydralit Data Explorer',page_icon="π",layout='wide',initial_sidebar_state='auto',)
|
8 |
+
|
9 |
+
if __name__ == '__main__':
|
10 |
+
|
11 |
+
#---ONLY HERE TO SHOW OPTIONS WITH HYDRALIT - NOT REQUIRED, use Hydralit constructor parameters.
|
12 |
+
st.write('Some options to change the way our Hydralit application looks and feels')
|
13 |
+
c1,c2,c3,c4,_ = st.columns([2,2,2,2,8])
|
14 |
+
hydralit_navbar = c1.checkbox('Use Hydralit Navbar',True)
|
15 |
+
sticky_navbar = c2.checkbox('Use Sticky Navbar',False)
|
16 |
+
animate_navbar = c3.checkbox('Use Animated Navbar',True)
|
17 |
+
hide_st = c4.checkbox('Hide Streamlit Markers',True)
|
18 |
+
|
19 |
+
over_theme = {'txc_inactive': '#FFFFFF'}
|
20 |
+
#this is the host application, we add children to it and that's it!
|
21 |
+
app = HydraApp(
|
22 |
+
title='Secure Hydralit Data Explorer',
|
23 |
+
favicon="π",
|
24 |
+
hide_streamlit_markers=hide_st,
|
25 |
+
#add a nice banner, this banner has been defined as 5 sections with spacing defined by the banner_spacing array below.
|
26 |
+
use_banner_images=["./resources/hydra.png",None,{'header':"<h1 style='text-align:center;padding: 0px 0px;color:grey;font-size:200%;'>Secure Hydralit Explorer</h1><br>"},None,"./resources/lock.png"],
|
27 |
+
banner_spacing=[5,30,60,30,5],
|
28 |
+
use_navbar=hydralit_navbar,
|
29 |
+
navbar_sticky=sticky_navbar,
|
30 |
+
navbar_animation=animate_navbar,
|
31 |
+
navbar_theme=over_theme
|
32 |
+
)
|
33 |
+
|
34 |
+
#Home button will be in the middle of the nav list now
|
35 |
+
app.add_app("Home", icon="π ", app=apps.HomeApp(title='Home'),is_home=True)
|
36 |
+
|
37 |
+
#add all your application classes here
|
38 |
+
app.add_app("Cheat Sheet", icon="π", app=apps.CheatApp(title="Cheat Sheet"))
|
39 |
+
app.add_app("Sequency Denoising",icon="π", app=apps.WalshApp(title="Sequency Denoising"))
|
40 |
+
app.add_app("Sequency (Secure)",icon="ππ", app=apps.WalshAppSecure(title="Sequency (Secure)"))
|
41 |
+
app.add_app("Solar Mach", icon="π°οΈ", app=apps.SolarMach(title="Solar Mach"))
|
42 |
+
app.add_app("Spacy NLP", icon="β¨οΈ", app=apps.SpacyNLP(title="Spacy NLP"))
|
43 |
+
app.add_app("Uber Pickups", icon="π", app=apps.UberNYC(title="Uber Pickups"))
|
44 |
+
app.add_app("Solar Mach", icon="π°οΈ", app=apps.SolarMach(title="Solar Mach"))
|
45 |
+
app.add_app("Loader Playground", icon="β²οΈ", app=apps.LoaderTestApp(title="Loader Playground"))
|
46 |
+
app.add_app("Cookie Cutter", icon="πͺ", app=apps.CookieCutterApp(title="Cookie Cutter"))
|
47 |
+
|
48 |
+
#we have added a sign-up app to demonstrate the ability to run an unsecure app
|
49 |
+
#only 1 unsecure app is allowed
|
50 |
+
app.add_app("Signup", icon="π°οΈ", app=apps.SignUpApp(title='Signup'), is_unsecure=True)
|
51 |
+
|
52 |
+
#we want to have secure access for this HydraApp, so we provide a login application
|
53 |
+
#optional logout label, can be blank for something nicer!
|
54 |
+
app.add_app("Login", apps.LoginApp(title='Login'),is_login=True)
|
55 |
+
|
56 |
+
#specify a custom loading app for a custom transition between apps, this includes a nice custom spinner
|
57 |
+
app.add_loader_app(apps.MyLoadingApp(delay=0))
|
58 |
+
|
59 |
+
#we can inject a method to be called everytime a user logs out
|
60 |
+
#---------------------------------------------------------------------
|
61 |
+
# @app.logout_callback
|
62 |
+
# def mylogout_cb():
|
63 |
+
# print('I was called from Hydralit at logout!')
|
64 |
+
#---------------------------------------------------------------------
|
65 |
+
|
66 |
+
#we can inject a method to be called everytime a user logs in
|
67 |
+
#---------------------------------------------------------------------
|
68 |
+
# @app.login_callback
|
69 |
+
# def mylogin_cb():
|
70 |
+
# print('I was called from Hydralit at login!')
|
71 |
+
#---------------------------------------------------------------------
|
72 |
+
|
73 |
+
#if we want to auto login a guest but still have a secure app, we can assign a guest account and go straight in
|
74 |
+
app.enable_guest_access()
|
75 |
+
|
76 |
+
#check user access level to determine what should be shown on the menu
|
77 |
+
user_access_level, username = app.check_access()
|
78 |
+
|
79 |
+
# If the menu is cluttered, just rearrange it into sections!
|
80 |
+
# completely optional, but if you have too many entries, you can make it nicer by using accordian menus
|
81 |
+
if user_access_level > 1:
|
82 |
+
complex_nav = {
|
83 |
+
'Home': ['Home'],
|
84 |
+
'Loader Playground': ['Loader Playground'],
|
85 |
+
'Intro π': ['Cheat Sheet',"Solar Mach"],
|
86 |
+
'Hotstepper π₯': ["Sequency Denoising","Sequency (Secure)"],
|
87 |
+
'Clustering': ["Uber Pickups"],
|
88 |
+
'NLP': ["Spacy NLP"],
|
89 |
+
'Cookie Cutter': ['Cookie Cutter']
|
90 |
+
}
|
91 |
+
elif user_access_level == 1:
|
92 |
+
complex_nav = {
|
93 |
+
'Home': ['Home'],
|
94 |
+
'Loader Playground': ['Loader Playground'],
|
95 |
+
'Intro π': ['Cheat Sheet',"Solar Mach"],
|
96 |
+
'Hotstepper π₯': ["Sequency Denoising"],
|
97 |
+
'Clustering': ["Uber Pickups"],
|
98 |
+
'NLP': ["Spacy NLP"],
|
99 |
+
'Cookie Cutter': ['Cookie Cutter']
|
100 |
+
}
|
101 |
+
else:
|
102 |
+
complex_nav = {
|
103 |
+
'Home': ['Home'],
|
104 |
+
}
|
105 |
+
|
106 |
+
|
107 |
+
#and finally just the entire app and all the children.
|
108 |
+
app.run(complex_nav)
|
109 |
+
|
110 |
+
|
111 |
+
#print user movements and current login details used by Hydralit
|
112 |
+
#---------------------------------------------------------------------
|
113 |
+
# user_access_level, username = app.check_access()
|
114 |
+
# prev_app, curr_app = app.get_nav_transition()
|
115 |
+
# print(prev_app,'- >', curr_app)
|
116 |
+
# print(int(user_access_level),'- >', username)
|
117 |
+
# print('Other Nav after: ',app.session_state.other_nav_app)
|
118 |
+
#---------------------------------------------------------------------
|
119 |
+
|
setup.sh
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
mkdir -p ~/.streamlit/
|
2 |
+
echo "\
|
3 |
+
[general]\n\
|
4 |
+
email = \"{c6lculus8ntr0py@gmail.com}\"\n\
|
5 |
+
" > ~/.streamlit/credentials.toml
|
6 |
+
echo "\
|
7 |
+
[server]\n\
|
8 |
+
headless = true\n\
|
9 |
+
enableCORS=false\n\
|
10 |
+
port = $PORT\n\
|
11 |
+
" > ~/.streamlit/config.toml
|