Skip to content
This repository was archived by the owner on Sep 3, 2022. It is now read-only.

Commit f1160b0

Browse files
authored
Adding a Python 3 Kernel to Datalab. (#1344)
* Adding a Python 3 Kernel to Datalab. Installs Python 3 and py3 versions of our supported packages, including the python3 jupyter kernel, and adds a dropdown to the notebook page to allow users to switch kernels. Fixes #902 * Fix merge error. * Changes based on review comments. * Fixing minimum toolbar width. * Fixing build error.
1 parent 7967b01 commit f1160b0

File tree

6 files changed

+281
-20
lines changed

6 files changed

+281
-20
lines changed

containers/base/Dockerfile

Lines changed: 75 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,6 @@ RUN echo "deb-src http://ftp.us.debian.org/debian testing main" >> /etc/apt/sour
6767
pip install -U --upgrade-strategy only-if-needed --no-cache-dir PyYAML==3.11 && \
6868
pip install -U --upgrade-strategy only-if-needed --no-cache-dir six==1.10.0 && \
6969
pip install -U --upgrade-strategy only-if-needed --no-cache-dir ipywidgets==6.0.0 && \
70-
# Install notebook after ipywidgets, and keep it pinned to 4.2.3, higher versions may
71-
# not work well with datalab. For example, kernel gateway doesn't work with 4.3.0 notebook
72-
# (https://github.com/googledatalab/datalab/issues/1083)
73-
pip install -U --upgrade-strategy only-if-needed --no-cache-dir notebook==4.2.3 && \
7470
pip install -U --upgrade-strategy only-if-needed --no-cache-dir ipykernel==4.5.2 && \
7571
pip install -U --upgrade-strategy only-if-needed --no-cache-dir future==0.15.2 && \
7672
pip install -U --upgrade-strategy only-if-needed --no-cache-dir psutil==4.3.0 && \
@@ -81,8 +77,75 @@ RUN echo "deb-src http://ftp.us.debian.org/debian testing main" >> /etc/apt/sour
8177
pip install -U --upgrade-strategy only-if-needed --no-cache-dir crcmod==1.7 && \
8278
pip install -U --upgrade-strategy only-if-needed --no-cache-dir pillow==3.4.1 && \
8379
pip install -U --upgrade-strategy only-if-needed --no-cache-dir google-cloud-dataflow==0.6.0 && \
80+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir tensorflow-transform==0.1.7 && \
81+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir tensorflow==1.0.1 && \
82+
# Setting protobuf to 3.1.0 to workaround a tensorflow 1.0 issue in tcmalloc
83+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir protobuf==3.1.0 && \
8484
find /usr/local/lib/python2.7 -type d -name tests | xargs rm -rf && \
8585

86+
# Python 3
87+
apt-get install --no-install-recommends -y -q python3-dev && \
88+
# Get pip set up such that pip -> py2 and pip3 -> py3
89+
# And they both work.
90+
wget https://bootstrap.pypa.io/get-pip.py && \
91+
python3 ./get-pip.py && \
92+
python ./get-pip.py --force-reinstall && \
93+
94+
# Install other Python 3 packages
95+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir numpy==1.11.2 && \
96+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir pandas==0.19.1 && \
97+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir scipy==0.18.0 && \
98+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir scikit-learn==0.17.1 && \
99+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir sympy==0.7.6.1 && \
100+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir statsmodels==0.6.1 && \
101+
102+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir tornado==4.4.2 \
103+
--upgrade-strategy only-if-needed --no-cache-dir pyzmq==16.0.2 \
104+
--upgrade-strategy only-if-needed --no-cache-dir jinja2==2.8 \
105+
--upgrade-strategy only-if-needed --no-cache-dir jsonschema==2.5.1 \
106+
--upgrade-strategy only-if-needed --no-cache-dir python-dateutil==2.5.0 \
107+
--upgrade-strategy only-if-needed --no-cache-dir pytz==2016.7 \
108+
--upgrade-strategy only-if-needed --no-cache-dir pandocfilters==1.3.0 \
109+
--upgrade-strategy only-if-needed --no-cache-dir pygments==2.1.3 \
110+
--upgrade-strategy only-if-needed --no-cache-dir argparse==1.2.1 \
111+
--upgrade-strategy only-if-needed --no-cache-dir mock==2.0.0 \
112+
--upgrade-strategy only-if-needed --no-cache-dir requests==2.9.1 \
113+
--upgrade-strategy only-if-needed --no-cache-dir oauth2client==2.2.0 \
114+
--upgrade-strategy only-if-needed --no-cache-dir httplib2==0.9.2 \
115+
--upgrade-strategy only-if-needed --no-cache-dir futures==3.0.5 && \
116+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir matplotlib==1.5.3 && \
117+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir ggplot==0.6.8 && \
118+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir seaborn==0.7.0 && \
119+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir PyYAML==3.11 && \
120+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir six==1.10.0 && \
121+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir psutil==4.3.0 && \
122+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir google-api-python-client==1.5.1 && \
123+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir plotly==1.12.5 && \
124+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir nltk==3.2.1 && \
125+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir bs4==0.0.1 && \
126+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir crcmod==1.7 && \
127+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir pillow==3.4.1 && \
128+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir tensorflow==1.0.1 && \
129+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir protobuf==3.1.0 && \
130+
# Install IPython related packages with no-deps, to ensure that we don't
131+
# Overwrite the python 2 version of jupyter with the python 3 version.
132+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir ipywidgets==6.0.0 && \
133+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir notebook==4.2.3 && \
134+
pip3 install -U --upgrade-strategy only-if-needed --no-cache-dir ipykernel==4.5.2 && \
135+
find /usr/local/lib/python3.4 -type d -name tests | xargs rm -rf && \
136+
137+
# Install python2 version of notebook after the python3 version, so that we
138+
# default to using python 2.
139+
# Install notebook after ipywidgets, and keep it pinned to 4.2.3, higher versions may
140+
# not work well with datalab. For example, kernel gateway doesn't work with 4.3.0 notebook
141+
# (https://github.com/googledatalab/datalab/issues/1083)
142+
pip install -U --force-reinstall --no-deps --no-cache-dir notebook==4.2.3 && \
143+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir notebook==4.2.3 && \
144+
145+
# Install the Python 2 and Python 3 kernels
146+
python -m ipykernel install && \
147+
python3 -m ipykernel install && \
148+
86149

87150
# Setup Node.js using LTS 6.10
88151
mkdir -p /tools/node && \
@@ -138,15 +201,8 @@ RUN echo "deb-src http://ftp.us.debian.org/debian testing main" >> /etc/apt/sour
138201
rm -rf /usr/share/i18n/locales/* && \
139202
cd /
140203

141-
ENV LANG en_US.UTF-8
142204

143-
# Install tf-transform
144-
RUN pip install -U --upgrade-strategy only-if-needed --no-cache-dir tensorflow-transform==0.1.7
145-
146-
# Install TensorFlow
147-
# Setting protobuf to 3.1.0 to workaround a tensorflow 1.0 issue in tcmalloc
148-
RUN pip install -U --upgrade-strategy only-if-needed --no-cache-dir tensorflow==1.0 && \
149-
pip install -U --upgrade-strategy only-if-needed --no-cache-dir protobuf==3.1.0
205+
ENV LANG en_US.UTF-8
150206

151207
ADD config/ipython.py /etc/ipython/ipython_config.py
152208
ADD config/nbconvert.py /etc/jupyter/jupyter_notebook_config.py
@@ -159,17 +215,19 @@ ADD nbconvert /datalab/nbconvert
159215
# Then link stuff needed for nbconvert to a location where Jinja will find it.
160216
# I'd prefer to just use absolute path in Jinja imports but those don't work.
161217
RUN ipython profile create default && \
162-
jupyter notebook --generate-config && \
163-
if [ -d /datalab/lib/pydatalab/.git ]; then \
218+
jupyter notebook --generate-config
219+
220+
RUN if [ -d /datalab/lib/pydatalab/.git ]; then \
164221
echo "use local lib"; \
165222
else \
166223
git clone https://github.com/googledatalab/pydatalab.git /datalab/lib/pydatalab; \
167-
fi && \
168-
cd /datalab/lib/pydatalab && \
224+
fi
225+
RUN cd /datalab/lib/pydatalab && \
169226
/tools/node/bin/npm install -g typescript && \
170227
tsc --module amd --noImplicitAny --outdir datalab/notebook/static datalab/notebook/static/*.ts && \
171228
tsc --module amd --noImplicitAny --outdir google/datalab/notebook/static google/datalab/notebook/static/*.ts && \
172-
/tools/node/bin/npm uninstall -g typescript && \
229+
/tools/node/bin/npm uninstall -g typescript
230+
RUN cd /datalab/lib/pydatalab && \
173231
pip install --upgrade-strategy only-if-needed --no-cache-dir . && \
174232
pip install --upgrade-strategy only-if-needed /datalab/lib/pydatalab/solutionbox/image_classification/. && \
175233
pip install --upgrade-strategy only-if-needed /datalab/lib/pydatalab/solutionbox/structured_data/. && \

containers/base/Dockerfile.py2

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
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+
FROM debian:jessie
16+
MAINTAINER Google Cloud DataLab
17+
18+
# Container configuration
19+
EXPOSE 8080
20+
21+
# Path configuration
22+
ENV PATH $PATH:/tools/node/bin:/tools/google-cloud-sdk/bin
23+
ENV PYTHONPATH /env/python
24+
25+
# Setup OS and core packages
26+
RUN echo "deb-src http://ftp.us.debian.org/debian testing main" >> /etc/apt/sources.list && \
27+
apt-get update -y && \
28+
apt-get install --no-install-recommends -y -q python unzip ca-certificates build-essential \
29+
libatlas-base-dev liblapack-dev gfortran libpng-dev libfreetype6-dev libxft-dev libxml2-dev \
30+
python-dev python-setuptools python-zmq openssh-client wget curl git pkg-config zip && \
31+
easy_install pip && \
32+
mkdir -p /tools && \
33+
34+
# Save GPL source packages
35+
mkdir -p /srcs && \
36+
cd /srcs && \
37+
apt-get source -d wget git python-zmq ca-certificates pkg-config libpng-dev && \
38+
wget --progress=dot:mega https://mirrors.kernel.org/gnu/gcc/gcc-4.9.2/gcc-4.9.2.tar.bz2 && \
39+
cd / && \
40+
41+
# Setup Python packages. Rebuilding numpy/scipy is expensive so we move this early
42+
# to reduce the chance that prior steps can cause changes requiring a rebuild.
43+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir numpy==1.11.2 && \
44+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir pandas==0.19.1 && \
45+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir scipy==0.18.0 && \
46+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir scikit-learn==0.17.1 && \
47+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir sympy==0.7.6.1 && \
48+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir statsmodels==0.6.1 && \
49+
50+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir tornado==4.4.2 \
51+
--upgrade-strategy only-if-needed --no-cache-dir pyzmq==16.0.2 \
52+
--upgrade-strategy only-if-needed --no-cache-dir jinja2==2.8 \
53+
--upgrade-strategy only-if-needed --no-cache-dir jsonschema==2.5.1 \
54+
--upgrade-strategy only-if-needed --no-cache-dir python-dateutil==2.5.0 \
55+
--upgrade-strategy only-if-needed --no-cache-dir pytz==2016.7 \
56+
--upgrade-strategy only-if-needed --no-cache-dir pandocfilters==1.3.0 \
57+
--upgrade-strategy only-if-needed --no-cache-dir pygments==2.1.3 \
58+
--upgrade-strategy only-if-needed --no-cache-dir argparse==1.2.1 \
59+
--upgrade-strategy only-if-needed --no-cache-dir mock==2.0.0 \
60+
--upgrade-strategy only-if-needed --no-cache-dir requests==2.9.1 \
61+
--upgrade-strategy only-if-needed --no-cache-dir oauth2client==2.2.0 \
62+
--upgrade-strategy only-if-needed --no-cache-dir httplib2==0.9.2 \
63+
--upgrade-strategy only-if-needed --no-cache-dir futures==3.0.5 && \
64+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir matplotlib==1.5.3 && \
65+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir ggplot==0.6.8 && \
66+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir seaborn==0.7.0 && \
67+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir PyYAML==3.11 && \
68+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir six==1.10.0 && \
69+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir ipywidgets==6.0.0 && \
70+
# Install notebook after ipywidgets, and keep it pinned to 4.2.3, higher versions may
71+
# not work well with datalab. For example, kernel gateway doesn't work with 4.3.0 notebook
72+
# (https://github.com/googledatalab/datalab/issues/1083)
73+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir notebook==4.2.3 && \
74+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir ipykernel==4.5.2 && \
75+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir future==0.15.2 && \
76+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir psutil==4.3.0 && \
77+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir google-api-python-client==1.5.1 && \
78+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir plotly==1.12.5 && \
79+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir nltk==3.2.1 && \
80+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir bs4==0.0.1 && \
81+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir crcmod==1.7 && \
82+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir pillow==3.4.1 && \
83+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir google-cloud-dataflow==0.6.0 && \
84+
find /usr/local/lib/python2.7 -type d -name tests | xargs rm -rf && \
85+
86+
87+
# Setup Node.js using LTS 6.10
88+
mkdir -p /tools/node && \
89+
wget -nv https://nodejs.org/dist/v6.10.0/node-v6.10.0-linux-x64.tar.gz -O node.tar.gz && \
90+
tar xzf node.tar.gz -C /tools/node --strip-components=1 && \
91+
rm node.tar.gz && \
92+
93+
# Setup Google Cloud SDK
94+
# Also apply workaround for gsutil failure brought by this version of Google Cloud.
95+
# (https://code.google.com/p/google-cloud-sdk/issues/detail?id=538) in final step.
96+
wget -nv https://dl.google.com/dl/cloudsdk/release/google-cloud-sdk.zip && \
97+
unzip -qq google-cloud-sdk.zip -d tools && \
98+
rm google-cloud-sdk.zip && \
99+
tools/google-cloud-sdk/install.sh --usage-reporting=false \
100+
--path-update=false --bash-completion=false \
101+
--disable-installation-options && \
102+
tools/google-cloud-sdk/bin/gcloud -q components update \
103+
gcloud core bq gsutil compute preview alpha beta && \
104+
# disable the gcloud update message
105+
tools/google-cloud-sdk/bin/gcloud config set component_manager/disable_update_check true && \
106+
touch /tools/google-cloud-sdk/lib/third_party/google.py && \
107+
108+
# Add some unchanging bits - specifically node modules (that need to be kept in sync
109+
# with packages.json manually, but help save build time, by preincluding them in an
110+
# earlier layer).
111+
# Note: ws is now over 1.0 but using that gives issues so leaving at 0.4.2 for now.
112+
/tools/node/bin/npm install \
113+
114+
115+
116+
117+
118+
119+
120+
cd / && \
121+
/tools/node/bin/npm install -g forever && \
122+
123+
# Clean up
124+
apt-get purge -y build-essential bzip2 cpp cpp-4.9 python-setuptools pkg-config libfreetype6-dev && \
125+
apt-get autoremove -y && \
126+
rm -rf /var/lib/apt/lists/* && \
127+
rm -rf /var/lib/dpkg/info/* && \
128+
rm -rf /tmp/* && \
129+
rm -rf /root/.cache/* && \
130+
rm -rf /usr/share/locale/* && \
131+
rm -rf /usr/share/i18n/locales/* && \
132+
cd /
133+
134+
# Install tf-transform
135+
RUN pip install -U --upgrade-strategy only-if-needed --no-cache-dir tensorflow-transform==0.1.7
136+
137+
# Install TensorFlow
138+
# Setting protobuf to 3.1.0 to workaround a tensorflow 1.0 issue in tcmalloc
139+
RUN pip install -U --upgrade-strategy only-if-needed --no-cache-dir tensorflow==1.0 && \
140+
pip install -U --upgrade-strategy only-if-needed --no-cache-dir protobuf==3.1.0
141+
142+
ADD config/ipython.py /etc/ipython/ipython_config.py
143+
ADD config/nbconvert.py /etc/jupyter/jupyter_notebook_config.py
144+
145+
# Directory "py" may be empty and in that case it will git clone pydatalab from repo
146+
ADD pydatalab /datalab/lib/pydatalab
147+
ADD nbconvert /datalab/nbconvert
148+
149+
# Do IPython configuration and install build artifacts
150+
# Then link stuff needed for nbconvert to a location where Jinja will find it.
151+
# I'd prefer to just use absolute path in Jinja imports but those don't work.
152+
RUN ipython profile create default && \
153+
jupyter notebook --generate-config && \
154+
if [ -d /datalab/lib/pydatalab/.git ]; then \
155+
echo "use local lib"; \
156+
else \
157+
git clone https://github.com/googledatalab/pydatalab.git /datalab/lib/pydatalab; \
158+
fi && \
159+
cd /datalab/lib/pydatalab && \
160+
/tools/node/bin/npm install -g typescript && \
161+
tsc --module amd --noImplicitAny --outdir datalab/notebook/static datalab/notebook/static/*.ts && \
162+
tsc --module amd --noImplicitAny --outdir google/datalab/notebook/static google/datalab/notebook/static/*.ts && \
163+
/tools/node/bin/npm uninstall -g typescript && \
164+
pip install --upgrade-strategy only-if-needed --no-cache-dir . && \
165+
pip install --upgrade-strategy only-if-needed /datalab/lib/pydatalab/solutionbox/image_classification/. && \
166+
pip install --upgrade-strategy only-if-needed /datalab/lib/pydatalab/solutionbox/structured_data/. && \
167+
jupyter nbextension install --py datalab.notebook && \
168+
jupyter nbextension install --py google.datalab.notebook && \
169+
jupyter nbextension enable --py widgetsnbextension && \
170+
rm datalab/notebook/static/*.js google/datalab/notebook/static/*.js && \
171+
mkdir -p /datalab/nbconvert && \
172+
cp -R /usr/local/share/jupyter/nbextensions/gcpdatalab/* /datalab/nbconvert && \
173+
ln -s /usr/local/lib/python2.7/dist-packages/notebook/static/custom/custom.css /datalab/nbconvert/custom.css && \
174+
cd /
175+

sources/web/datalab/config/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"--ContentsManager.untitled_notebook=\"Untitled Notebook\"",
4242
"--NotebookNotary.algorithm=\"sha1\"",
4343
"--KernelManager.autorestart=True",
44-
"--KernelSpecManager.whitelist=[\"python2\"]",
44+
"--MultiKernelManager.default_kernel_name=\"python2\"",
4545
"--ip=\"127.0.0.1\""
4646
]
4747
}

sources/web/datalab/static/datalab.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
body {
2525
font-family: 'Open Sans', Helvetica, sans-serif;
2626
font-size: 14px;
27-
min-width: 720px;
27+
min-width: 760px;
2828
}
2929

3030
/* Layout */
@@ -590,7 +590,7 @@ div.modal-dialog pre, div.modal-dialog code, #help code, #help pre {
590590
}
591591

592592
/* Responsive Design */
593-
@media screen and (max-width: 1080px) {
593+
@media screen and (max-width: 1220px) {
594594
span.toolbar-text {
595595
display: none;
596596
}

sources/web/datalab/static/notebook-app.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,21 @@ define(['static/appbar', 'static/minitoolbar'], function(appbar, minitoolbar) {
8080
Jupyter.notebook.undelete_cell.bind(Jupyter.notebook))
8181
});
8282

83+
events.on('kernel_connected.Kernel', function() {
84+
$('#currentKernelName').text(Jupyter.kernelselector.current_selection);
85+
$('#kernelSelectorDropdown').empty();
86+
Object.keys(Jupyter.kernelselector.kernelspecs).forEach(function(kernel) {
87+
$('#kernelSelectorDropdown').append(`
88+
<li>
89+
<a href="#" onclick="Jupyter.kernelselector.set_kernel('` + kernel + `')">
90+
` + kernel + `
91+
</a>
92+
</li>
93+
`
94+
)
95+
})
96+
});
97+
8398
events.on('notebook_loaded.Notebook', function() {
8499

85100
// create the cell toolbar
@@ -657,10 +672,14 @@ define(['static/appbar', 'static/minitoolbar'], function(appbar, minitoolbar) {
657672
document.getElementById('navigation').style.display = '';
658673
document.getElementById('help').style.display = 'none';
659674
}
675+
660676
}
661677

662678
return {
663679
preLoad: preLoad,
664680
postLoad, postLoad,
665681
};
666682
});
683+
684+
685+

0 commit comments

Comments
 (0)