├── LICENSE
├── README.md
├── _common
├── bc_js_filepicker-3.0.2.js
├── form.js
└── form
│ ├── attributes.yml
│ └── form.yml
├── sh_code-server
├── form.js
├── form.yml.erb
├── icon.png
├── manifest.yml
├── submit.yml.erb
├── template
│ ├── after.sh.erb
│ ├── before.sh.erb
│ └── script.sh.erb
└── view.html.erb
├── sh_jupyterlab
├── form.js
├── form.yml.erb
├── icon.png
├── manifest.yml
├── submit.yml.erb
├── template
│ ├── after.sh
│ ├── before.sh.erb
│ └── script.sh.erb
└── view.html.erb
├── sh_matlab
├── form.js
├── form.yml.erb
├── icon.png
├── manifest.yml
├── submit.yml.erb
├── template
│ ├── after.sh.erb
│ ├── before.sh.erb
│ └── script.sh.erb
└── view.html.erb
├── sh_notebook
├── form.js
├── form.yml.erb
├── icon.png
├── manifest.yml
├── submit.yml.erb
├── template
│ ├── after.sh
│ ├── before.sh.erb
│ └── script.sh.erb
└── view.html.erb
├── sh_rstudio
├── form.js
├── form.yml.erb
├── icon.png
├── manifest.yml
├── submit.yml.erb
├── template
│ ├── after.sh.erb
│ ├── before.sh.erb
│ ├── bin
│ │ └── auth
│ └── script.sh.erb
└── view.html.erb
└── sh_tensorboard
├── README.md
├── form.js
├── form.yml.erb
├── icon.jpg
├── icon.png
├── manifest.yml
├── submit.yml.erb
├── template
├── after.sh
├── before.sh.erb
├── bin
│ └── authrevproxy.py
└── script.sh.erb
└── view.html.erb
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Open OnDemand apps for Sherlock
2 |
3 | This repository contains [Open OnDemand](https://openondemand.org/) used on
4 | [Sherlock](https://www.sherlock.stanford.edu)
5 |
6 | ## `sh_jupyter`
7 |
8 | Local customizations for [Jupyter](https://jupyter.org/) notebooks, based on
9 | https://github.com/OSC/bc_osc_jupyter
10 |
11 | ## `sh_rstudio`
12 |
13 | Local customizations for [RStudio
14 | Server](https://rstudio.com/products/rstudio/), based on
15 | https://github.com/OSC/bc_osc_rstudio_server
16 |
17 | ## `sh_tensorboard`
18 |
19 | OnDemand app for [Tensorboard](https://www.tensorflow.org/tensorboard)
20 |
21 | Because Tensorboard doesn't provide any kind of authentication mechanism, this
22 | app adds an transparent authentication layer, via an authenticating reverse
23 | proxy and session cookies. The workflow is transparent for users, but
24 | Tensorboard sessions can only be accessed through the OnDemand portal.
25 |
26 | ## `sh_code-server`
27 |
28 | Local customizations for [code-server](https://coder.com/docs/code-server),
29 | based on https://github.com/OSC/bc_osc_codeserver
30 |
31 | ## `sh_matlab`
32 |
33 | OnDemand app for Matlab, using
34 | [matlab-proxy](https://github.com/mathworks/matlab-proxy)
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/_common/bc_js_filepicker-3.0.2.js:
--------------------------------------------------------------------------------
1 | !function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=10)}([function(t,e,n){(function(t){function n(t,e){for(var n=0,r=t.length-1;r>=0;r--){var o=t[r];"."===o?t.splice(r,1):".."===o?(t.splice(r,1),n++):n&&(t.splice(r,1),n--)}if(e)for(;n--;n)t.unshift("..");return t}function r(t,e){if(t.filter)return t.filter(e);for(var n=[],r=0;r=-1&&!o;i--){var a=i>=0?arguments[i]:t.cwd();if("string"!=typeof a)throw new TypeError("Arguments to path.resolve must be strings");a&&(e=a+"/"+e,o="/"===a.charAt(0))}return(o?"/":"")+(e=n(r(e.split("/"),(function(t){return!!t})),!o).join("/"))||"."},e.normalize=function(t){var i=e.isAbsolute(t),a="/"===o(t,-1);return(t=n(r(t.split("/"),(function(t){return!!t})),!i).join("/"))||i||(t="."),t&&a&&(t+="/"),(i?"/":"")+t},e.isAbsolute=function(t){return"/"===t.charAt(0)},e.join=function(){var t=Array.prototype.slice.call(arguments,0);return e.normalize(r(t,(function(t,e){if("string"!=typeof t)throw new TypeError("Arguments to path.join must be strings");return t})).join("/"))},e.relative=function(t,n){function r(t){for(var e=0;e=0&&""===t[n];n--);return e>n?[]:t.slice(e,n-e+1)}t=e.resolve(t).substr(1),n=e.resolve(n).substr(1);for(var o=r(t.split("/")),i=r(n.split("/")),a=Math.min(o.length,i.length),s=a,c=0;c=1;--i)if(47===(e=t.charCodeAt(i))){if(!o){r=i;break}}else o=!1;return-1===r?n?"/":".":n&&1===r?"/":t.slice(0,r)},e.basename=function(t,e){var n=function(t){"string"!=typeof t&&(t+="");var e,n=0,r=-1,o=!0;for(e=t.length-1;e>=0;--e)if(47===t.charCodeAt(e)){if(!o){n=e+1;break}}else-1===r&&(o=!1,r=e+1);return-1===r?"":t.slice(n,r)}(t);return e&&n.substr(-1*e.length)===e&&(n=n.substr(0,n.length-e.length)),n},e.extname=function(t){"string"!=typeof t&&(t+="");for(var e=-1,n=0,r=-1,o=!0,i=0,a=t.length-1;a>=0;--a){var s=t.charCodeAt(a);if(47!==s)-1===r&&(o=!1,r=a+1),46===s?-1===e?e=a:1!==i&&(i=1):-1!==e&&(i=-1);else if(!o){n=a+1;break}}return-1===e||-1===r||0===i||1===i&&e===r-1&&e===n+1?"":t.slice(e,r)};var o="b"==="ab".substr(-1)?function(t,e,n){return t.substr(e,n)}:function(t,e,n){return e<0&&(e=t.length+e),t.substr(e,n)}}).call(this,n(3))},function(t,e){function n(t){return(n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var r;r=function(){return this}();try{r=r||new Function("return this")()}catch(t){"object"===("undefined"==typeof window?"undefined":n(window))&&(r=window)}t.exports=r},function(t,e,n){"use strict";(function(t,r){function o(t){return(o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}
2 | /*!
3 | * Vue.js v2.7.14
4 | * (c) 2014-2022 Evan You
5 | * Released under the MIT License.
6 | */n.d(e,"a",(function(){return Kn}));var i=Object.freeze({}),a=Array.isArray;function s(t){return null==t}function c(t){return null!=t}function l(t){return!0===t}function u(t){return"string"==typeof t||"number"==typeof t||"symbol"===o(t)||"boolean"==typeof t}function f(t){return"function"==typeof t}function d(t){return null!==t&&"object"===o(t)}var p=Object.prototype.toString;function v(t){return"[object Object]"===p.call(t)}function h(t){return"[object RegExp]"===p.call(t)}function m(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function g(t){return c(t)&&"function"==typeof t.then&&"function"==typeof t.catch}function y(t){return null==t?"":Array.isArray(t)||v(t)&&t.toString===p?JSON.stringify(t,null,2):String(t)}function _(t){var e=parseFloat(t);return isNaN(e)?t:e}function b(t,e){for(var n=Object.create(null),r=t.split(","),o=0;o-1)return t.splice(r,1)}}var x=Object.prototype.hasOwnProperty;function k(t,e){return x.call(t,e)}function S(t){var e=Object.create(null);return function(n){return e[n]||(e[n]=t(n))}}var O=/-(\w)/g,$=S((function(t){return t.replace(O,(function(t,e){return e?e.toUpperCase():""}))})),T=S((function(t){return t.charAt(0).toUpperCase()+t.slice(1)})),E=/\B([A-Z])/g,A=S((function(t){return t.replace(E,"-$1").toLowerCase()}));var I=Function.prototype.bind?function(t,e){return t.bind(e)}:function(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n};function j(t,e){e=e||0;for(var n=t.length-e,r=new Array(n);n--;)r[n]=t[n+e];return r}function P(t,e){for(var n in e)t[n]=e[n];return t}function N(t){for(var e={},n=0;n0,tt=J&&J.indexOf("edge/")>0;J&&J.indexOf("android");var et=J&&/iphone|ipad|ipod|ios/.test(J);J&&/chrome\/\d+/.test(J),J&&/phantomjs/.test(J);var nt,rt=J&&J.match(/firefox\/(\d+)/),ot={}.watch,it=!1;if(X)try{var at={};Object.defineProperty(at,"passive",{get:function(){it=!0}}),window.addEventListener("test-passive",null,at)}catch(t){}var st=function(){return void 0===nt&&(nt=!X&&void 0!==t&&(t.process&&"server"===t.process.env.VUE_ENV)),nt},ct=X&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function lt(t){return"function"==typeof t&&/native code/.test(t.toString())}var ut,ft="undefined"!=typeof Symbol&<(Symbol)&&"undefined"!=typeof Reflect&<(Reflect.ownKeys);ut="undefined"!=typeof Set&<(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var dt=null;function pt(t){void 0===t&&(t=null),t||dt&&dt._scope.off(),dt=t,t&&t._scope.on()}var vt=function(){function t(t,e,n,r,o,i,a,s){this.tag=t,this.data=e,this.children=n,this.text=r,this.elm=o,this.ns=void 0,this.context=i,this.fnContext=void 0,this.fnOptions=void 0,this.fnScopeId=void 0,this.key=e&&e.key,this.componentOptions=a,this.componentInstance=void 0,this.parent=void 0,this.raw=!1,this.isStatic=!1,this.isRootInsert=!0,this.isComment=!1,this.isCloned=!1,this.isOnce=!1,this.asyncFactory=s,this.asyncMeta=void 0,this.isAsyncPlaceholder=!1}return Object.defineProperty(t.prototype,"child",{get:function(){return this.componentInstance},enumerable:!1,configurable:!0}),t}(),ht=function(t){void 0===t&&(t="");var e=new vt;return e.text=t,e.isComment=!0,e};function mt(t){return new vt(void 0,void 0,void 0,String(t))}function gt(t){var e=new vt(t.tag,t.data,t.children&&t.children.slice(),t.text,t.elm,t.context,t.componentOptions,t.asyncFactory);return e.ns=t.ns,e.isStatic=t.isStatic,e.key=t.key,e.isComment=t.isComment,e.fnContext=t.fnContext,e.fnOptions=t.fnOptions,e.fnScopeId=t.fnScopeId,e.asyncMeta=t.asyncMeta,e.isCloned=!0,e}var yt=0,_t=[],bt=function(){function t(){this._pending=!1,this.id=yt++,this.subs=[]}return t.prototype.addSub=function(t){this.subs.push(t)},t.prototype.removeSub=function(t){this.subs[this.subs.indexOf(t)]=null,this._pending||(this._pending=!0,_t.push(this))},t.prototype.depend=function(e){t.target&&t.target.addDep(this)},t.prototype.notify=function(t){var e=this.subs.filter((function(t){return t}));for(var n=0,r=e.length;n0&&(Jt((o=t(o,"".concat(n||"","_").concat(r)))[0])&&Jt(f)&&(d[i]=mt(f.text+o[0].text),o.shift()),d.push.apply(d,o)):u(o)?Jt(f)?d[i]=mt(f.text+o):""!==o&&d.push(mt(o)):Jt(o)&&Jt(f)?d[i]=mt(f.text+o.text):(l(e._isVList)&&c(o.tag)&&s(o.key)&&c(n)&&(o.key="__vlist".concat(n,"_").concat(r,"__")),d.push(o)));return d}(t):void 0}function Jt(t){return c(t)&&c(t.text)&&!1===t.isComment}function Zt(t,e){var n,r,o,i,s=null;if(a(t)||"string"==typeof t)for(s=new Array(t.length),n=0,r=t.length;n0,s=e?!!e.$stable:!a,c=e&&e.$key;if(e){if(e._normalized)return e._normalized;if(s&&r&&r!==i&&c===r.$key&&!a&&!r.$hasNormal)return r;for(var l in o={},e)e[l]&&"$"!==l[0]&&(o[l]=ge(t,n,l,e[l]))}else o={};for(var u in n)u in o||(o[u]=ye(n,u));return e&&Object.isExtensible(e)&&(e._normalized=o),G(o,"$stable",s),G(o,"$key",c),G(o,"$hasNormal",a),o}function ge(t,e,n,r){var i=function(){var e=dt;pt(t);var n=arguments.length?r.apply(null,arguments):r({}),i=(n=n&&"object"===o(n)&&!a(n)?[n]:Xt(n))&&n[0];return pt(e),n&&(!i||1===n.length&&i.isComment&&!he(i))?void 0:n};return r.proxy&&Object.defineProperty(e,n,{get:i,enumerable:!0,configurable:!0}),i}function ye(t,e){return function(){return t[e]}}function _e(t){return{get attrs(){if(!t._attrsProxy){var e=t._attrsProxy={};G(e,"_v_attr_proxy",!0),be(e,t.$attrs,i,t,"$attrs")}return t._attrsProxy},get listeners(){t._listenersProxy||be(t._listenersProxy={},t.$listeners,i,t,"$listeners");return t._listenersProxy},get slots(){return function(t){t._slotsProxy||Ce(t._slotsProxy={},t.$scopedSlots);return t._slotsProxy}(t)},emit:I(t.$emit,t),expose:function(e){e&&Object.keys(e).forEach((function(n){return Ht(t,e,n)}))}}}function be(t,e,n,r,o){var i=!1;for(var a in e)a in t?e[a]!==n[a]&&(i=!0):(i=!0,we(t,a,r,o));for(var a in t)a in e||(i=!0,delete t[a]);return i}function we(t,e,n,r){Object.defineProperty(t,e,{enumerable:!0,configurable:!0,get:function(){return n[r][e]}})}function Ce(t,e){for(var n in e)t[n]=e[n];for(var n in t)n in e||delete t[n]}var xe=null;function ke(t,e){return(t.__esModule||ft&&"Module"===t[Symbol.toStringTag])&&(t=t.default),d(t)?e.extend(t):t}function Se(t){if(a(t))for(var e=0;edocument.createEvent("Event").timeStamp&&(un=function(){return fn.now()})}var dn=function(t,e){if(t.post){if(!e.post)return 1}else if(e.post)return-1;return t.id-e.id};function pn(){var t,e;for(ln=un(),sn=!0,nn.sort(dn),cn=0;cncn&&nn[n].id>t.id;)n--;nn.splice(n+1,0,t)}else nn.push(t);an||(an=!0,Ue(pn))}}function hn(t,e){if(t){for(var n=Object.create(null),r=ft?Reflect.ownKeys(t):Object.keys(t),o=0;o-1)if(i&&!k(o,"default"))a=!1;else if(""===a||a===A(t)){var c=Dn(String,o.type);(c<0||s-1:"string"==typeof t?t.split(",").indexOf(e)>-1:!!h(t)&&t.test(e)}function Zn(t,e){var n=t.cache,r=t.keys,o=t._vnode;for(var i in n){var a=n[i];if(a){var s=a.name;s&&!e(s)&&Qn(n,i,r,o)}}}function Qn(t,e,n,r){var o=t[e];!o||r&&o.tag===r.tag||o.componentInstance.$destroy(),t[e]=null,C(n,e)}!function(t){t.prototype._init=function(t){var e=this;e._uid=qn++,e._isVue=!0,e.__v_skip=!0,e._scope=new zt(!0),e._scope._vm=!0,t&&t._isComponent?function(t,e){var n=t.$options=Object.create(t.constructor.options),r=e._parentVnode;n.parent=e.parent,n._parentVnode=r;var o=r.componentOptions;n.propsData=o.propsData,n._parentListeners=o.listeners,n._renderChildren=o.children,n._componentTag=o.tag,e.render&&(n.render=e.render,n.staticRenderFns=e.staticRenderFns)}(e,t):e.$options=In(Gn(e.constructor),t||{},e),e._renderProxy=e,e._self=e,function(t){var e=t.$options,n=e.parent;if(n&&!e.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(t)}t.$parent=n,t.$root=n?n.$root:t,t.$children=[],t.$refs={},t._provided=n?n._provided:Object.create(null),t._watcher=null,t._inactive=null,t._directInactive=!1,t._isMounted=!1,t._isDestroyed=!1,t._isBeingDestroyed=!1}(e),function(t){t._events=Object.create(null),t._hasHookEvent=!1;var e=t.$options._parentListeners;e&&Xe(t,e)}(e),function(t){t._vnode=null,t._staticTrees=null;var e=t.$options,n=t.$vnode=e._parentVnode,r=n&&n.context;t.$slots=pe(e._renderChildren,r),t.$scopedSlots=n?me(t.$parent,n.data.scopedSlots,t.$slots):i,t._c=function(e,n,r,o){return Oe(t,e,n,r,o,!1)},t.$createElement=function(e,n,r,o){return Oe(t,e,n,r,o,!0)};var o=n&&n.data;Pt(t,"$attrs",o&&o.attrs||i,null,!0),Pt(t,"$listeners",e._parentListeners||i,null,!0)}(e),en(e,"beforeCreate",void 0,!1),function(t){var e=hn(t.$options.inject,t);e&&(Et(!1),Object.keys(e).forEach((function(n){Pt(t,n,e[n])})),Et(!0))}(e),Un(e),function(t){var e=t.$options.provide;if(e){var n=f(e)?e.call(t):e;if(!d(n))return;for(var r=Vt(t),o=ft?Reflect.ownKeys(n):Object.keys(n),i=0;i1?j(n):n;for(var r=j(arguments,1),o='event handler for "'.concat(t,'"'),i=0,a=n.length;iparseInt(this.max)&&Qn(t,e[0],e,this._vnode),this.vnodeToCache=null}}},created:function(){this.cache=Object.create(null),this.keys=[]},destroyed:function(){for(var t in this.cache)Qn(this.cache,t,this.keys)},mounted:function(){var t=this;this.cacheVNode(),this.$watch("include",(function(e){Zn(t,(function(t){return Jn(e,t)}))})),this.$watch("exclude",(function(e){Zn(t,(function(t){return!Jn(e,t)}))}))},updated:function(){this.cacheVNode()},render:function(){var t=this.$slots.default,e=Se(t),n=e&&e.componentOptions;if(n){var r=Xn(n),o=this.include,i=this.exclude;if(o&&(!r||!Jn(o,r))||i&&r&&Jn(i,r))return e;var a=this.cache,s=this.keys,c=null==e.key?n.Ctor.cid+(n.tag?"::".concat(n.tag):""):e.key;a[c]?(e.componentInstance=a[c].componentInstance,C(s,c),s.push(c)):(this.vnodeToCache=e,this.keyToCache=c),e.data.keepAlive=!0}return e||t&&t[0]}}};!function(t){var e={get:function(){return V}};Object.defineProperty(t,"config",e),t.util={warn:kn,extend:P,mergeOptions:In,defineReactive:Pt},t.set=Nt,t.delete=Ft,t.nextTick=Ue,t.observable=function(t){return jt(t),t},t.options=Object.create(null),B.forEach((function(e){t.options[e+"s"]=Object.create(null)})),t.options._base=t,P(t.options.components,er),function(t){t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=j(arguments,1);return n.unshift(this),f(t.install)?t.install.apply(t,n):f(t)&&t.apply(null,n),e.push(t),this}}(t),function(t){t.mixin=function(t){return this.options=In(this.options,t),this}}(t),Yn(t),function(t){B.forEach((function(e){t[e]=function(t,n){return n?("component"===e&&v(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),"directive"===e&&f(n)&&(n={bind:n,update:n}),this.options[e+"s"][t]=n,n):this.options[e+"s"][t]}}))}(t)}(Kn),Object.defineProperty(Kn.prototype,"$isServer",{get:st}),Object.defineProperty(Kn.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(Kn,"FunctionalRenderContext",{value:mn}),Kn.version="2.7.14";var nr=b("style,class"),rr=b("input,textarea,option,select,progress"),or=b("contenteditable,draggable,spellcheck"),ir=b("events,caret,typing,plaintext-only"),ar=b("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,truespeed,typemustmatch,visible"),sr="http://www.w3.org/1999/xlink",cr=function(t){return":"===t.charAt(5)&&"xlink"===t.slice(0,5)},lr=function(t){return cr(t)?t.slice(6,t.length):""},ur=function(t){return null==t||!1===t};function fr(t){for(var e=t.data,n=t,r=t;c(r.componentInstance);)(r=r.componentInstance._vnode)&&r.data&&(e=dr(r.data,e));for(;c(n=n.parent);)n&&n.data&&(e=dr(e,n.data));return function(t,e){if(c(t)||c(e))return pr(t,vr(e));return""}(e.staticClass,e.class)}function dr(t,e){return{staticClass:pr(t.staticClass,e.staticClass),class:c(t.class)?[t.class,e.class]:e.class}}function pr(t,e){return t?e?t+" "+e:t:e||""}function vr(t){return Array.isArray(t)?function(t){for(var e,n="",r=0,o=t.length;r-1?Lr(t,e,n):ar(e)?ur(n)?t.removeAttribute(e):(n="allowfullscreen"===e&&"EMBED"===t.tagName?"true":e,t.setAttribute(e,n)):or(e)?t.setAttribute(e,function(t,e){return ur(e)||"false"===e?"false":"contenteditable"===t&&ir(e)?e:"true"}(e,n)):cr(e)?ur(n)?t.removeAttributeNS(sr,lr(e)):t.setAttributeNS(sr,e,n):Lr(t,e,n)}function Lr(t,e,n){if(ur(n))t.removeAttribute(e);else{if(Z&&!Q&&"TEXTAREA"===t.tagName&&"placeholder"===e&&""!==n&&!t.__ieph){t.addEventListener("input",(function e(n){n.stopImmediatePropagation(),t.removeEventListener("input",e)})),t.__ieph=!0}t.setAttribute(e,n)}}var Rr={create:Mr,update:Mr};function Ur(t,e){var n=e.elm,r=e.data,o=t.data;if(!(s(r.staticClass)&&s(r.class)&&(s(o)||s(o.staticClass)&&s(o.class)))){var i=fr(e),a=n._transitionClasses;c(a)&&(i=pr(i,vr(a))),i!==n._prevClass&&(n.setAttribute("class",i),n._prevClass=i)}}var Hr,Br={create:Ur,update:Ur};function zr(t,e,n){var r=Hr;return function o(){var i=e.apply(null,arguments);null!==i&&qr(t,o,n,r)}}var Vr=je&&!(rt&&Number(rt[1])<=53);function Wr(t,e,n,r){if(Vr){var o=ln,i=e;e=i._wrapper=function(t){if(t.target===t.currentTarget||t.timeStamp>=o||t.timeStamp<=0||t.target.ownerDocument!==document)return i.apply(this,arguments)}}Hr.addEventListener(t,e,it?{capture:n,passive:r}:n)}function qr(t,e,n,r){(r||Hr).removeEventListener(t,e._wrapper||e,n)}function Gr(t,e){if(!s(t.data.on)||!s(e.data.on)){var n=e.data.on||{},r=t.data.on||{};Hr=e.elm||t.elm,function(t){if(c(t.__r)){var e=Z?"change":"input";t[e]=[].concat(t.__r,t[e]||[]),delete t.__r}c(t.__c)&&(t.change=[].concat(t.__c,t.change||[]),delete t.__c)}(n),Gt(n,r,Wr,qr,zr,e.context),Hr=void 0}}var Kr,Yr={create:Gr,update:Gr,destroy:function(t){return Gr(t,Sr)}};function Xr(t,e){if(!s(t.data.domProps)||!s(e.data.domProps)){var n,r,o=e.elm,i=t.data.domProps||{},a=e.data.domProps||{};for(n in(c(a.__ob__)||l(a._v_attr_proxy))&&(a=e.data.domProps=P({},a)),i)n in a||(o[n]="");for(n in a){if(r=a[n],"textContent"===n||"innerHTML"===n){if(e.children&&(e.children.length=0),r===i[n])continue;1===o.childNodes.length&&o.removeChild(o.childNodes[0])}if("value"===n&&"PROGRESS"!==o.tagName){o._value=r;var u=s(r)?"":String(r);Jr(o,u)&&(o.value=u)}else if("innerHTML"===n&&gr(o.tagName)&&s(o.innerHTML)){(Kr=Kr||document.createElement("div")).innerHTML="");for(var f=Kr.firstChild;o.firstChild;)o.removeChild(o.firstChild);for(;f.firstChild;)o.appendChild(f.firstChild)}else if(r!==i[n])try{o[n]=r}catch(t){}}}}function Jr(t,e){return!t.composing&&("OPTION"===t.tagName||function(t,e){var n=!0;try{n=document.activeElement!==t}catch(t){}return n&&t.value!==e}(t,e)||function(t,e){var n=t.value,r=t._vModifiers;if(c(r)){if(r.number)return _(n)!==_(e);if(r.trim)return n.trim()!==e.trim()}return n!==e}(t,e))}var Zr={create:Xr,update:Xr},Qr=S((function(t){var e={},n=/:(.+)/;return t.split(/;(?![^(]*\))/g).forEach((function(t){if(t){var r=t.split(n);r.length>1&&(e[r[0].trim()]=r[1].trim())}})),e}));function to(t){var e=eo(t.style);return t.staticStyle?P(t.staticStyle,e):e}function eo(t){return Array.isArray(t)?N(t):"string"==typeof t?Qr(t):t}var no,ro=/^--/,oo=/\s*!important$/,io=function(t,e,n){if(ro.test(e))t.style.setProperty(e,n);else if(oo.test(n))t.style.setProperty(A(e),n.replace(oo,""),"important");else{var r=so(e);if(Array.isArray(n))for(var o=0,i=n.length;o-1?e.split(uo).forEach((function(e){return t.classList.add(e)})):t.classList.add(e);else{var n=" ".concat(t.getAttribute("class")||""," ");n.indexOf(" "+e+" ")<0&&t.setAttribute("class",(n+e).trim())}}function po(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(uo).forEach((function(e){return t.classList.remove(e)})):t.classList.remove(e),t.classList.length||t.removeAttribute("class");else{for(var n=" ".concat(t.getAttribute("class")||""," "),r=" "+e+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?t.setAttribute("class",n):t.removeAttribute("class")}}function vo(t){if(t){if("object"===o(t)){var e={};return!1!==t.css&&P(e,ho(t.name||"v")),P(e,t),e}return"string"==typeof t?ho(t):void 0}}var ho=S((function(t){return{enterClass:"".concat(t,"-enter"),enterToClass:"".concat(t,"-enter-to"),enterActiveClass:"".concat(t,"-enter-active"),leaveClass:"".concat(t,"-leave"),leaveToClass:"".concat(t,"-leave-to"),leaveActiveClass:"".concat(t,"-leave-active")}})),mo=X&&!Q,go="transition",yo="transitionend",_o="animation",bo="animationend";mo&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(go="WebkitTransition",yo="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(_o="WebkitAnimation",bo="webkitAnimationEnd"));var wo=X?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(t){return t()};function Co(t){wo((function(){wo(t)}))}function xo(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),fo(t,e))}function ko(t,e){t._transitionClasses&&C(t._transitionClasses,e),po(t,e)}function So(t,e,n){var r=$o(t,e),o=r.type,i=r.timeout,a=r.propCount;if(!o)return n();var s="transition"===o?yo:bo,c=0,l=function(){t.removeEventListener(s,u),n()},u=function(e){e.target===t&&++c>=a&&l()};setTimeout((function(){c0&&(n="transition",u=a,f=i.length):"animation"===e?l>0&&(n="animation",u=l,f=c.length):f=(n=(u=Math.max(a,l))>0?a>l?"transition":"animation":null)?"transition"===n?i.length:c.length:0,{type:n,timeout:u,propCount:f,hasTransform:"transition"===n&&Oo.test(r[go+"Property"])}}function To(t,e){for(;t.length1}function No(t,e){!0!==e.data.show&&Ao(e)}var Fo=function(t){var e,n,r={},o=t.modules,i=t.nodeOps;for(e=0;ev?_(t,s(n[g+1])?null:n[g+1].elm,n,p,g,r):p>g&&C(e,f,v)}(f,h,g,n,u):c(g)?(c(t.text)&&i.setTextContent(f,""),_(f,null,g,0,g.length-1,n)):c(h)?C(h,0,h.length-1):c(t.text)&&i.setTextContent(f,""):t.text!==e.text&&i.setTextContent(f,e.text),c(v)&&c(p=v.hook)&&c(p=p.postpatch)&&p(t,e)}}}function O(t,e,n){if(l(n)&&c(t.parent))t.parent.data.pendingInsert=e;else for(var r=0;r-1,a.selected!==i&&(a.selected=i);else if(L(Uo(a),r))return void(t.selectedIndex!==s&&(t.selectedIndex=s));o||(t.selectedIndex=-1)}}function Ro(t,e){return e.every((function(e){return!L(e,t)}))}function Uo(t){return"_value"in t?t._value:t.value}function Ho(t){t.target.composing=!0}function Bo(t){t.target.composing&&(t.target.composing=!1,zo(t.target,"input"))}function zo(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function Vo(t){return!t.componentInstance||t.data&&t.data.transition?t:Vo(t.componentInstance._vnode)}var Wo={model:Mo,show:{bind:function(t,e,n){var r=e.value,o=(n=Vo(n)).data&&n.data.transition,i=t.__vOriginalDisplay="none"===t.style.display?"":t.style.display;r&&o?(n.data.show=!0,Ao(n,(function(){t.style.display=i}))):t.style.display=r?i:"none"},update:function(t,e,n){var r=e.value;!r!=!e.oldValue&&((n=Vo(n)).data&&n.data.transition?(n.data.show=!0,r?Ao(n,(function(){t.style.display=t.__vOriginalDisplay})):Io(n,(function(){t.style.display="none"}))):t.style.display=r?t.__vOriginalDisplay:"none")},unbind:function(t,e,n,r,o){o||(t.style.display=t.__vOriginalDisplay)}}},qo={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function Go(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?Go(Se(e.children)):t}function Ko(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var o=n._parentListeners;for(var r in o)e[$(r)]=o[r];return e}function Yo(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{props:e.componentOptions.propsData})}var Xo=function(t){return t.tag||he(t)},Jo=function(t){return"show"===t.name},Zo={name:"transition",props:qo,abstract:!0,render:function(t){var e=this,n=this.$slots.default;if(n&&(n=n.filter(Xo)).length){0;var r=this.mode;0;var o=n[0];if(function(t){for(;t=t.parent;)if(t.data.transition)return!0}(this.$vnode))return o;var i=Go(o);if(!i)return o;if(this._leaving)return Yo(t,o);var a="__transition-".concat(this._uid,"-");i.key=null==i.key?i.isComment?a+"comment":a+i.tag:u(i.key)?0===String(i.key).indexOf(a)?i.key:a+i.key:i.key;var s=(i.data||(i.data={})).transition=Ko(this),c=this._vnode,l=Go(c);if(i.data.directives&&i.data.directives.some(Jo)&&(i.data.show=!0),l&&l.data&&!function(t,e){return e.key===t.key&&e.tag===t.tag}(i,l)&&!he(l)&&(!l.componentInstance||!l.componentInstance._vnode.isComment)){var f=l.data.transition=P({},s);if("out-in"===r)return this._leaving=!0,Kt(f,"afterLeave",(function(){e._leaving=!1,e.$forceUpdate()})),Yo(t,o);if("in-out"===r){if(he(i))return c;var d,p=function(){d()};Kt(s,"afterEnter",p),Kt(s,"enterCancelled",p),Kt(f,"delayLeave",(function(t){d=t}))}}return o}}},Qo=P({tag:String,moveClass:String},qo);function ti(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._enterCb()}function ei(t){t.data.newPos=t.elm.getBoundingClientRect()}function ni(t){var e=t.data.pos,n=t.data.newPos,r=e.left-n.left,o=e.top-n.top;if(r||o){t.data.moved=!0;var i=t.elm.style;i.transform=i.WebkitTransform="translate(".concat(r,"px,").concat(o,"px)"),i.transitionDuration="0s"}}delete Qo.mode;var ri={Transition:Zo,TransitionGroup:{props:Qo,beforeMount:function(){var t=this,e=this._update;this._update=function(n,r){var o=Ze(t);t.__patch__(t._vnode,t.kept,!1,!0),t._vnode=t.kept,o(),e.call(t,n,r)}},render:function(t){for(var e=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),r=this.prevChildren=this.children,o=this.$slots.default||[],i=this.children=[],a=Ko(this),s=0;s-1?_r[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:_r[t]=/HTMLUnknownElement/.test(e.toString())},P(Kn.options.directives,Wo),P(Kn.options.components,ri),Kn.prototype.__patch__=X?Fo:F,Kn.prototype.$mount=function(t,e){return function(t,e,n){var r;t.$el=e,t.$options.render||(t.$options.render=ht),en(t,"beforeMount"),r=function(){t._update(t._render(),n)},new qe(t,r,F,{before:function(){t._isMounted&&!t._isDestroyed&&en(t,"beforeUpdate")}},!0),n=!1;var o=t._preWatchers;if(o)for(var i=0;i1)for(var n=1;n=0&&(t._idleTimeoutId=setTimeout((function(){t._onTimeout&&t._onTimeout()}),e))},n(9),e.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==t&&t.setImmediate||this&&this.setImmediate,e.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==t&&t.clearImmediate||this&&this.clearImmediate}).call(this,n(1))},function(t,e,n){(function(t,e){!function(t,n){"use strict";if(!t.setImmediate){var r,o,i,a,s,c=1,l={},u=!1,f=t.document,d=Object.getPrototypeOf&&Object.getPrototypeOf(t);d=d&&d.setTimeout?d:t,"[object process]"==={}.toString.call(t.process)?r=function(t){e.nextTick((function(){v(t)}))}:!function(){if(t.postMessage&&!t.importScripts){var e=!0,n=t.onmessage;return t.onmessage=function(){e=!1},t.postMessage("","*"),t.onmessage=n,e}}()?t.MessageChannel?((i=new MessageChannel).port1.onmessage=function(t){v(t.data)},r=function(t){i.port2.postMessage(t)}):f&&"onreadystatechange"in f.createElement("script")?(o=f.documentElement,r=function(t){var e=f.createElement("script");e.onreadystatechange=function(){v(t),e.onreadystatechange=null,o.removeChild(e),e=null},o.appendChild(e)}):r=function(t){setTimeout(v,0,t)}:(a="setImmediate$"+Math.random()+"$",s=function(e){e.source===t&&"string"==typeof e.data&&0===e.data.indexOf(a)&&v(+e.data.slice(a.length))},t.addEventListener?t.addEventListener("message",s,!1):t.attachEvent("onmessage",s),r=function(e){t.postMessage(a+e,"*")}),d.setImmediate=function(t){"function"!=typeof t&&(t=new Function(""+t));for(var e=new Array(arguments.length-1),n=0;n=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,a=!0,c=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){c=!0,i=t},f:function(){try{a||null==n.return||n.return()}finally{if(c)throw i}}}}function s(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=new Array(e);n.*)").exec(s);null!=c&&n.push({title:i,href:c.groups.path||"/"})}}catch(t){r.e(t)}finally{r.f()}return n}function l(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";window.localStorage.setItem("files_last_path"+e,""+t)}function u(t){return function(t){if(Array.isArray(t))return f(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,e){if(!t)return;if("string"==typeof t)return f(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);"Object"===n&&t.constructor&&(n=t.constructor.name);if("Map"===n||"Set"===n)return Array.from(t);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return f(t,e)}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function f(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=new Array(e);n0&&void 0!==arguments[0]?arguments[0]:[],e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=window.localStorage.getItem("files_last_path"+e),r=t.length>0&&t[0].href,o="/";return n||r||o}(this.fs_favorites,this.modalId)},is_entry_disabled:function(t){return"d"!==t.type&&!this.is_entry_selectable(t)},is_entry_selectable:function(t){var e="dirs"===this.target_file_type||"both"===this.target_file_type,n="files"===this.target_file_type||"both"===this.target_file_type;return"d"===t.type?!!e&&(!this.target_file_pattern||!!t.name.match(this.target_file_pattern)):!!n&&(!this.target_file_pattern||!!t.name.match(this.target_file_pattern))}},mounted:function(){this.path=this.get_current_path(),this.filter_input=this.$el.querySelector("#"+this.filterId)},computed:{modalId:function(){return this.input?"modal-for-"+this.input.id:""},filterId:function(){return"filter-for-"+this.input.id},slugs:function(){return this.path.split(i.sep)},showFsFavorites:function(){return this.fs_favorites.length>0},fsEntryColWidth:function(){return this.showFsFavorites?"col-sm-7":"col-sm-12"}}};n(6);var p=function(t,e,n,r,o,i,a,s){var c,l="function"==typeof t?t.options:t;if(e&&(l.render=e,l.staticRenderFns=n,l._compiled=!0),r&&(l.functional=!0),i&&(l._scopeId="data-v-"+i),a?(c=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),o&&o.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(a)},l._ssrRegister=c):o&&(c=s?function(){o.call(this,(l.functional?this.parent:this).$root.$options.shadowRoot)}:o),c)if(l.functional){l._injectStyles=c;var u=l.render;l.render=function(t,e){return c.call(e),u(t,e)}}else{var f=l.beforeCreate;l.beforeCreate=f?[].concat(f,c):[c]}return{exports:t,options:l}}(d,o,[],!1,null,null,null).exports;function v(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=function(t,e){if(!t)return;if("string"==typeof t)return h(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);"Object"===n&&t.constructor&&(n=t.constructor.name);if("Map"===n||"Set"===n)return Array.from(t);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return h(t,e)}(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var r=0,o=function(){};return{s:o,n:function(){return r>=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,a=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){s=!0,i=t},f:function(){try{a||null==n.return||n.return()}finally{if(s)throw i}}}}function h(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=new Array(e);nn.parts.length&&(r.parts.length=n.parts.length)}else{var a=[];for(o=0;o
5 | Space separated list of additional modules to load Full list at https://www.sherlock.stanford.edu/docs/software/list
6 |
7 |
8 | sh_workspace:
9 | label: Workspace (optional)
10 | help: |
11 | Optionally select a folder to start the server in (the default is your `$HOME` directory).
12 | data-filepicker: true
13 | data-target-file-type: dirs
14 | data-default-directory: '$HOME'
15 | readonly: true
16 | value: '$HOME'
17 |
18 | auto_queues:
19 | label: "Partition"
20 | value: "dev"
21 | required: true
22 | display: true
23 | help: |
24 | Partition to submit the job to
25 |
26 | sh_cpus:
27 | label: "#CPUs"
28 | widget: "number_field"
29 | required: true
30 | min: 1
31 | value: "1"
32 | help: |
33 | Number of CPU cores to allocate
34 |
35 | sh_gpus:
36 | label: "#GPUs (optional)"
37 | widget: "number_field"
38 | min: 1
39 | max: 8
40 | value: ""
41 | help: |
42 |
43 | Number of GPUs to allocate (don't forget to load the `cuda` module in the `Additional modules` field above and to select a partition with GPUs)
44 |
45 |
46 | sh_mem:
47 | label: "Memory (GB) (optional)"
48 | widget: "number_field"
49 | help: |
50 | Amount of memory to allocate
51 |
52 | sh_features:
53 | label: "Additional node features (optional)"
54 | help: |
55 | Additional node features to request, expressed as job contraints
56 |
57 | bc_num_hours:
58 | label: "Runtime (in hours)"
59 | default: 2
60 |
--------------------------------------------------------------------------------
/_common/form/form.yml:
--------------------------------------------------------------------------------
1 | - sh_modules
2 | - sh_workspace
3 | - auto_queues
4 | - sh_cpus
5 | - sh_gpus
6 | - sh_mem
7 | - sh_features
8 | - bc_num_hours
9 | - bc_email_on_started
10 |
--------------------------------------------------------------------------------
/sh_code-server/form.js:
--------------------------------------------------------------------------------
1 | ../_common/form.js
--------------------------------------------------------------------------------
/sh_code-server/form.yml.erb:
--------------------------------------------------------------------------------
1 | cluster: "sherlock"
2 |
3 | form:
4 | <%- IO.foreach(File.expand_path(File.dirname(__FILE__))+"/../_common/form/form.yml") do |line| %>
5 | <%= line %>
6 | <%- end -%>
7 |
8 | attributes:
9 | <%- IO.foreach(File.expand_path(File.dirname(__FILE__))+"/../_common/form/attributes.yml") do |line| %>
10 | <%= line %>
11 | <%- end -%>
12 |
--------------------------------------------------------------------------------
/sh_code-server/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stanford-rc/sh_ood-apps/4c5cf6a4b5ed63813c61c7de32a68168d97787dc/sh_code-server/icon.png
--------------------------------------------------------------------------------
/sh_code-server/manifest.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: code-server
3 | category: Interactive Apps
4 | subcategory: IDE
5 | role: batch_connect
6 | description: |
7 | This app will launch a [VS Code] server using [code-server] on [Sherlock].
8 |
9 | [VS Code]: https://code.visualstudio.com/
10 | [code-server]: https://coder.com/
11 | [Sherlock]: https://www.sherlock.stanford.edu/
12 |
--------------------------------------------------------------------------------
/sh_code-server/submit.yml.erb:
--------------------------------------------------------------------------------
1 | batch_connect:
2 | template: "basic"
3 |
4 | script:
5 | native: [
6 | "-N", "1",
7 | "-c", "<%= sh_cpus.blank? ? 1 : sh_cpus.to_i %>",
8 | <%- if not sh_gpus.blank? -%>
9 | "-G", "<%= sh_gpus.to_i %>",
10 | <%- end -%>
11 | <%- if not sh_mem.blank? -%>
12 | "--mem", "<%= sh_mem.to_i %>G",
13 | <%- end -%>
14 | <%- if not sh_features.blank? -%>
15 | "--constraint", "<%= sh_features %>"
16 | <%- end -%>
17 | ]
18 |
--------------------------------------------------------------------------------
/sh_code-server/template/after.sh.erb:
--------------------------------------------------------------------------------
1 | # Wait for code-server to start
2 | echo "$(date): Waiting for code-server to open port ${port}..."
3 |
4 | if wait_until_port_used "${host}:${port}" 300; then
5 | echo "$(date): Discovered code-server listening on port ${port}!"
6 | else
7 | echo "$(date): Timed out waiting for code-server to open port ${port}!"
8 | clean_up 1
9 | fi
10 |
11 | sleep 2
12 |
--------------------------------------------------------------------------------
/sh_code-server/template/before.sh.erb:
--------------------------------------------------------------------------------
1 | # Export the module function if it exists
2 | [[ $(type -t module) == "function" ]] && export -f module
3 |
4 | # Find available port to run server on
5 | export port=$(find_port "$host")
6 |
7 | # Create password for authentication
8 | export password=$(create_passwd 16)
9 |
--------------------------------------------------------------------------------
/sh_code-server/template/script.sh.erb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # load modules
4 | module reset
5 | module load system git # avoid warnings about git version <= 2
6 | module load code-server
7 | <%- unless context.sh_modules.blank? -%>
8 | module load <%= context.sh_modules %>
9 | <%- end -%>
10 |
11 | # create server configuration
12 | CODE_SERVER_DATAROOT="$HOME/.local/share/code-server"
13 | CODE_SERVER_USER_DIR="$CODE_SERVER_DATAROOT/User"
14 | mkdir -p "$CODE_SERVER_DATAROOT/extensions"
15 |
16 | # expose the password to the server (required)
17 | export PASSWORD="$password"
18 |
19 | # change workspace
20 | cd <%= context.sh_workspace.blank? ? "$HOME" : context.sh_workspace %>
21 |
22 | # set workspace directory
23 | WORKSPACE_DIR=<%= context.sh_workspace.blank? ? "$HOME" : context.sh_workspace %>
24 |
25 | # start server
26 | code-server \
27 | --auth="password" \
28 | --bind-addr="0.0.0.0:${port}" \
29 | --disable-telemetry \
30 | --disable-update-check \
31 | --ignore-last-opened \
32 | --extensions-dir="$CODE_SERVER_DATAROOT/extensions" \
33 | --user-data-dir="$CODE_SERVER_DATAROOT" \
34 | "$WORKSPACE_DIR"
35 |
--------------------------------------------------------------------------------
/sh_code-server/view.html.erb:
--------------------------------------------------------------------------------
1 | <%
2 | require 'digest'
3 |
4 | # Generate form id, based on host and port
5 | form_id = Digest::SHA1.hexdigest("--" + host.to_s + "--" + port.to_s + "--")
6 |
7 | # Generate SHA256 digest of code-server Password
8 | cookieValue = Digest::SHA256.hexdigest(password)
9 | %>
10 |
11 |
25 |
26 |
32 |
--------------------------------------------------------------------------------
/sh_jupyterlab/form.js:
--------------------------------------------------------------------------------
1 | ../_common/form.js
--------------------------------------------------------------------------------
/sh_jupyterlab/form.yml.erb:
--------------------------------------------------------------------------------
1 | cluster: "sherlock"
2 |
3 | form:
4 | - sh_python_version
5 | - sh_extra_jupyter_args
6 | <%- IO.foreach(File.expand_path(File.dirname(__FILE__))+"/../_common/form/form.yml") do |line| %>
7 | <%= line %>
8 | <%- end -%>
9 |
10 |
11 | attributes:
12 |
13 | sh_extra_jupyter_args:
14 | label: "Extra Jupyter arguments (optional)"
15 |
16 | sh_python_version:
17 | label: "Python version"
18 | widget: select
19 | options:
20 | - [ "Python 3.6", "py36" ]
21 | - [ "Python 3.9", "py39" ]
22 | - [ "Python 3.12", "py312" ]
23 | value: "py39"
24 |
25 | <%- IO.foreach(File.expand_path(File.dirname(__FILE__))+"/../_common/form/attributes.yml") do |line| %>
26 | <%= line %>
27 | <%- end -%>
28 |
29 |
30 |
--------------------------------------------------------------------------------
/sh_jupyterlab/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stanford-rc/sh_ood-apps/4c5cf6a4b5ed63813c61c7de32a68168d97787dc/sh_jupyterlab/icon.png
--------------------------------------------------------------------------------
/sh_jupyterlab/manifest.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: JupyterLab
3 | category: Interactive Apps
4 | subcategory: IDE
5 | role: batch_connect
6 | description: |
7 | This app will launch a [JupyterLab] server on [Sherlock]
8 | [JupyterLab]: https://www.jupyter.org
9 | [Sherlock]: https://www.sherlock.stanford.edu
10 |
--------------------------------------------------------------------------------
/sh_jupyterlab/submit.yml.erb:
--------------------------------------------------------------------------------
1 | batch_connect:
2 | template: "basic"
3 |
4 | script:
5 | native: [
6 | "-N", "1",
7 | "-c", "<%= sh_cpus.blank? ? 1 : sh_cpus.to_i %>",
8 | <%- if not sh_gpus.blank? -%>
9 | "-G", "<%= sh_gpus.to_i %>",
10 | <%- end -%>
11 | <%- if not sh_mem.blank? -%>
12 | "--mem", "<%= sh_mem.to_i %>G",
13 | <%- end -%>
14 | <%- if not sh_features.blank? -%>
15 | "--constraint", "<%= sh_features %>"
16 | <%- end -%>
17 | ]
18 |
--------------------------------------------------------------------------------
/sh_jupyterlab/template/after.sh:
--------------------------------------------------------------------------------
1 | # Wait for server to start
2 | echo "Waiting for server to open port ${port}..."
3 | if wait_until_port_used "${host}:${port}" 60; then
4 | echo "Discovered server listening on port ${port}!"
5 | else
6 | echo "Timed out waiting for server to open port ${port}!"
7 | pkill -P ${SCRIPT_PID}
8 | clean_up 1
9 | fi
10 | sleep 2
11 |
--------------------------------------------------------------------------------
/sh_jupyterlab/template/before.sh.erb:
--------------------------------------------------------------------------------
1 | # Export the module function if it exists
2 | [[ $(type -t module) == "function" ]] && export -f module
3 |
4 | # Find available port to run server on
5 | export port=$(find_port $host)
6 |
7 | # Create password for authentication
8 | export password=$(create_passwd 16)
9 |
--------------------------------------------------------------------------------
/sh_jupyterlab/template/script.sh.erb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # load modules
4 | module reset
5 | module load $(module -t av py-jupyterlab | grep <%= context.sh_python_version %>)
6 | <%- unless context.sh_modules.blank? -%>
7 | module load <%= context.sh_modules %>
8 | <%- end -%>
9 |
10 | # create server configuration
11 | NOTEBOOK_ROOT=<%= context.sh_workspace.blank? ? "$HOME" : context.sh_workspace %>
12 |
13 | # Safari users hit this error https://github.com/jupyterlab/jupyterlab/issues/5486
14 | # so let's make a new workspace dir that's this job's PWD and copy the defult /lab
15 | # workspace over there so folks can update it.
16 | WORKSPACE_DIR="$HOME/.jupyter/lab/workspaces"
17 | FILES=$(ls $WORKSPACE_DIR 2>/dev/null)
18 |
19 | for FILE in ${FILES[@]}; do
20 | ID=$(jq -r '.metadata.id' $WORKSPACE_DIR/$FILE)
21 | if [[ $ID == "/lab" ]]; then
22 | WORKSPACE_FILE="$WORKSPACE_DIR/$FILE"
23 | break
24 | fi
25 | done
26 | if [[ ${WORKSPACE_FILE+x} ]]; then
27 | cp $WORKSPACE_FILE .
28 | fi
29 | export JUPYTERLAB_WORKSPACES_DIR=$PWD
30 |
31 | SALT=$(create_passwd 16)
32 | PASSWORD_SHA1=$(echo -n "${password}${SALT}" | openssl dgst -sha1 | awk '{print $NF}')
33 |
34 | # Generate Jupyter configuration file with secure file permissions
35 | # configuration directives changed from NotebookApp to ServerApp at some point
36 | CONFIG_FILE="${PWD}/config.py"
37 | <% context.sh_python_version.sub("py","").to_i >= 39 ? cfg = "Server" : cfg = "Notebook" %>
38 | (
39 | umask 077
40 | cat > "${CONFIG_FILE}" << EOL
41 | c.KernelSpecManager.ensure_native_kernel = False
42 | c.<%= cfg %>App.ip = '0.0.0.0'
43 | c.<%= cfg %>App.port = ${port}
44 | c.<%= cfg %>App.base_url = '/node/${host}/${port}/'
45 | c.<%= cfg %>App.port_retries = 0
46 | c.<%= cfg %>App.password = u'sha1:${SALT}:${PASSWORD_SHA1}'
47 | c.<%= cfg %>App.open_browser = False
48 | c.<%= cfg %>App.allow_origin = '*'
49 | c.<%= cfg %>App.notebook_dir = "$NOTEBOOK_ROOT"
50 | c.<%= cfg %>App.disable_check_xsrf = True
51 | c.<%= cfg %>App.shutdown_no_activity_timeout = 3600
52 | c.LabApp.check_for_updates_class = "jupyterlab.NeverCheckForUpdate"
53 | EOL
54 | )
55 |
56 | # change workspace
57 | cd "$NOTEBOOK_ROOT"
58 |
59 | # list available kernels and extensions (debug)
60 | jupyter kernelspec list
61 | jupyter labextension list
62 |
63 | # Launch the Jupyter Notebook Server
64 | jupyter lab --config="${CONFIG_FILE}" <%= context.sh_extra_jupyter_args %>
65 |
--------------------------------------------------------------------------------
/sh_jupyterlab/view.html.erb:
--------------------------------------------------------------------------------
1 | <%-
2 | base_url = "/node/#{host}/#{port}"
3 | login_url = "#{base_url}/login"
4 | next_url = "#{base_url}/#{jupyter_api}"
5 |
6 | full_url="#{login_url}?next=#{CGI.escape(next_url)}"
7 | form_id = "juypyter_form#{login_url.gsub('/', '_')}"
8 | %>
9 |
10 |
11 |
19 |
20 |
26 |
--------------------------------------------------------------------------------
/sh_matlab/form.js:
--------------------------------------------------------------------------------
1 | ../_common/form.js
--------------------------------------------------------------------------------
/sh_matlab/form.yml.erb:
--------------------------------------------------------------------------------
1 | cluster: "sherlock"
2 |
3 | form:
4 | <%- IO.foreach(File.expand_path(File.dirname(__FILE__))+"/../_common/form/form.yml") do |line| %>
5 | <%= line %>
6 | <%- end -%>
7 |
8 | attributes:
9 | <%- IO.foreach(File.expand_path(File.dirname(__FILE__))+"/../_common/form/attributes.yml") do |line| %>
10 | <%= line %>
11 | <%- end -%>
12 |
--------------------------------------------------------------------------------
/sh_matlab/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stanford-rc/sh_ood-apps/4c5cf6a4b5ed63813c61c7de32a68168d97787dc/sh_matlab/icon.png
--------------------------------------------------------------------------------
/sh_matlab/manifest.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: MATLAB
3 | category: Interactive Apps
4 | subcategory: Apps
5 | role: batch_connect
6 | description: |
7 | This app will launch a [MATLAB] server using [matlab-proxy] on [Sherlock].
8 |
9 | [MATLAB]: https://www.mathworks.com/products/matlab.html
10 | [matlab-proxy]: https://github.com/mathworks/matlab-proxy
11 | [Sherlock]: https://www.sherlock.stanford.edu/
12 |
--------------------------------------------------------------------------------
/sh_matlab/submit.yml.erb:
--------------------------------------------------------------------------------
1 | batch_connect:
2 | template: "basic"
3 |
4 | script:
5 | native: [
6 | "-N", "1",
7 | "-c", "<%= sh_cpus.blank? ? 1 : sh_cpus.to_i %>",
8 | <%- if not sh_gpus.blank? -%>
9 | "-G", "<%= sh_gpus.to_i %>",
10 | <%- end -%>
11 | <%- if not sh_mem.blank? -%>
12 | "--mem", "<%= sh_mem.to_i %>G",
13 | <%- end -%>
14 | <%- if not sh_features.blank? -%>
15 | "--constraint", "<%= sh_features %>"
16 | <%- end -%>
17 | ]
18 |
--------------------------------------------------------------------------------
/sh_matlab/template/after.sh.erb:
--------------------------------------------------------------------------------
1 | echo "$(date): Waiting for server to open port ${port}..."
2 |
3 | if wait_until_port_used "${host}:${port}" 300; then
4 | echo "$(date): Discovered server listening on port ${port}!"
5 | else
6 | echo "$(date): Timed out waiting for server to open port ${port}!"
7 | clean_up 1
8 | fi
9 |
10 | sleep 2
11 |
--------------------------------------------------------------------------------
/sh_matlab/template/before.sh.erb:
--------------------------------------------------------------------------------
1 | # Export the module function if it exists
2 | [[ $(type -t module) == "function" ]] && export -f module
3 |
4 | # Find available port to run server on
5 | export port=$(find_port $host)
6 |
7 | # Create password for authentication
8 | export password=$(create_passwd 32)
9 |
--------------------------------------------------------------------------------
/sh_matlab/template/script.sh.erb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # load modules
4 | module reset
5 | module load system py-matlab-proxy x11 # Xvfb
6 | module load matlab # >= R2020b
7 | <%- unless context.sh_modules.blank? -%>
8 | module load <%= context.sh_modules %>
9 | <%- end -%>
10 |
11 | # set workspace
12 | cd <%= context.sh_workspace.blank? ? "$HOME" : context.sh_workspace %>
13 |
14 | # start server
15 | env MWI_APP_PORT="$port" \
16 | MWI_APP_HOST="0.0.0.0" \
17 | MWI_ENABLE_TOKEN_AUTH="True" \
18 | MWI_AUTH_TOKEN="$password" \
19 | MWI_SHUTDOWN_ON_IDLE_TIMEOUT="60" \
20 | matlab-proxy-app
21 |
--------------------------------------------------------------------------------
/sh_matlab/view.html.erb:
--------------------------------------------------------------------------------
1 | <%-
2 | # generate form id, based on host and port
3 | form_id = Digest::SHA1.hexdigest("--" + host.to_s + "--" + port.to_s + "--")
4 | -%>
5 |
6 |
11 |
--------------------------------------------------------------------------------
/sh_notebook/form.js:
--------------------------------------------------------------------------------
1 | ../_common/form.js
--------------------------------------------------------------------------------
/sh_notebook/form.yml.erb:
--------------------------------------------------------------------------------
1 | cluster: "sherlock"
2 |
3 | form:
4 | - sh_python_version
5 | - sh_extra_jupyter_args
6 | <%- IO.foreach(File.expand_path(File.dirname(__FILE__))+"/../_common/form/form.yml") do |line| %>
7 | <%= line %>
8 | <%- end -%>
9 |
10 |
11 | attributes:
12 |
13 | sh_extra_jupyter_args:
14 | label: "Extra Jupyter arguments (optional)"
15 |
16 | sh_python_version:
17 | label: "Python version"
18 | widget: select
19 | options:
20 | - [ "Python 2.7", "py27" ]
21 | - [ "Python 3.6", "py36" ]
22 | - [ "Python 3.9", "py39" ]
23 | value: "py39"
24 |
25 | <%- IO.foreach(File.expand_path(File.dirname(__FILE__))+"/../_common/form/attributes.yml") do |line| %>
26 | <%= line %>
27 | <%- end -%>
28 |
29 |
30 |
--------------------------------------------------------------------------------
/sh_notebook/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stanford-rc/sh_ood-apps/4c5cf6a4b5ed63813c61c7de32a68168d97787dc/sh_notebook/icon.png
--------------------------------------------------------------------------------
/sh_notebook/manifest.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Jupyter Notebook
3 | category: Interactive Apps
4 | subcategory: IDE
5 | role: batch_connect
6 | description: |
7 | This app will launch a [Jupyter Notebook] server on [Sherlock]
8 | [Jupyter Notebook]: https://www.jupyter.org
9 | [Sherlock]: https://www.sherlock.stanford.edu
10 |
--------------------------------------------------------------------------------
/sh_notebook/submit.yml.erb:
--------------------------------------------------------------------------------
1 | batch_connect:
2 | template: "basic"
3 |
4 | script:
5 | native: [
6 | "-N", "1",
7 | "-c", "<%= sh_cpus.blank? ? 1 : sh_cpus.to_i %>",
8 | <%- if not sh_gpus.blank? -%>
9 | "-G", "<%= sh_gpus.to_i %>",
10 | <%- end -%>
11 | <%- if not sh_mem.blank? -%>
12 | "--mem", "<%= sh_mem.to_i %>G",
13 | <%- end -%>
14 | <%- if not sh_features.blank? -%>
15 | "--constraint", "<%= sh_features %>"
16 | <%- end -%>
17 | ]
18 |
--------------------------------------------------------------------------------
/sh_notebook/template/after.sh:
--------------------------------------------------------------------------------
1 | # Wait for server to start
2 | echo "Waiting for server to open port ${port}..."
3 | if wait_until_port_used "${host}:${port}" 60; then
4 | echo "Discovered server listening on port ${port}!"
5 | else
6 | echo "Timed out waiting for server to open port ${port}!"
7 | pkill -P ${SCRIPT_PID}
8 | clean_up 1
9 | fi
10 | sleep 2
11 |
--------------------------------------------------------------------------------
/sh_notebook/template/before.sh.erb:
--------------------------------------------------------------------------------
1 | # Export the module function if it exists
2 | [[ $(type -t module) == "function" ]] && export -f module
3 |
4 | # Find available port to run server on
5 | export port=$(find_port $host)
6 |
7 | # Create apssword for authentication
8 | export password=$(create_passwd 16)
9 |
--------------------------------------------------------------------------------
/sh_notebook/template/script.sh.erb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # load modules
4 | module reset
5 | module load py-jupyter/1.0.0_<%= context.sh_python_version %>
6 | <%- unless context.sh_modules.blank? -%>
7 | module load <%= context.sh_modules %>
8 | <%- end -%>
9 |
10 | # set workspace
11 | NOTEBOOK_ROOT=<%= context.sh_workspace.blank? ? "$HOME" : context.sh_workspace %>
12 |
13 | SALT=$(create_passwd 16)
14 | PASSWORD_SHA1=$(echo -n "${password}${SALT}" | openssl dgst -sha1 | awk '{print $NF}')
15 |
16 | # create server config
17 | export CONFIG_FILE="${PWD}/config.py"
18 | (
19 | umask 077
20 | cat > "$CONFIG_FILE" << EOL
21 | c.NotebookApp.ip = '*'
22 | c.NotebookApp.port = $port
23 | c.NotebookApp.port_retries = 0
24 | c.NotebookApp.password = u'sha1:${SALT}:${PASSWORD_SHA1}'
25 | c.NotebookApp.base_url = '/node/${host}/${port}/'
26 | c.NotebookApp.open_browser = False
27 | c.NotebookApp.allow_origin = '*'
28 | c.NotebookApp.notebook_dir = "$NOTEBOOK_ROOT"
29 | c.NotebookApp.disable_check_xsrf = True
30 | c.NotebookApp.shutdown_no_activity_timeout = 3600
31 | EOL
32 | )
33 |
34 | # change workspace
35 | cd $NOTEBOOK_ROOT
36 |
37 | # start server
38 | jupyter notebook --config="$CONFIG_FILE" <%= context.sh_extra_jupyter_args %>
39 |
--------------------------------------------------------------------------------
/sh_notebook/view.html.erb:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/sh_rstudio/form.js:
--------------------------------------------------------------------------------
1 | ../_common/form.js
--------------------------------------------------------------------------------
/sh_rstudio/form.yml.erb:
--------------------------------------------------------------------------------
1 | cluster: "sherlock"
2 |
3 | form:
4 | - auto_modules_R
5 | <%- IO.foreach(File.expand_path(File.dirname(__FILE__))+"/../_common/form/form.yml") do |line| %>
6 | <%= line %>
7 | <%- end -%>
8 |
9 | attributes:
10 |
11 | auto_modules_R:
12 | default: false
13 | value: R/4.2.0
14 |
15 | <%- IO.foreach(File.expand_path(File.dirname(__FILE__))+"/../_common/form/attributes.yml") do |line| %>
16 | <%= line %>
17 | <%- end -%>
18 |
--------------------------------------------------------------------------------
/sh_rstudio/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stanford-rc/sh_ood-apps/4c5cf6a4b5ed63813c61c7de32a68168d97787dc/sh_rstudio/icon.png
--------------------------------------------------------------------------------
/sh_rstudio/manifest.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: RStudio Server
3 | category: Interactive Apps
4 | subcategory: IDE
5 | role: batch_connect
6 | description: |
7 | This app will launch [RStudio Server] an IDE for [R] on [Sherlock].
8 |
9 | [RStudio Server]: https://www.rstudio.com/products/rstudio-server/
10 | [R]: https://www.r-project.org/
11 | [Sherlock]: https://www.sherlock.stanford.edu
12 |
--------------------------------------------------------------------------------
/sh_rstudio/submit.yml.erb:
--------------------------------------------------------------------------------
1 | batch_connect:
2 | template: "basic"
3 | conn_params:
4 | - csrftoken
5 |
6 | script:
7 | native: [
8 | "-N", "1",
9 | "-c", "<%= sh_cpus.blank? ? 1 : sh_cpus.to_i %>",
10 | <%- if not sh_gpus.blank? -%>
11 | "-G", "<%= sh_gpus.to_i %>",
12 | <%- end -%>
13 | <%- if not sh_mem.blank? -%>
14 | "--mem", "<%= sh_mem.to_i %>G",
15 | <%- end -%>
16 | <%- if not sh_features.blank? -%>
17 | "--constraint", "<%= sh_features %>"
18 | <%- end -%>
19 | ]
20 |
--------------------------------------------------------------------------------
/sh_rstudio/template/after.sh.erb:
--------------------------------------------------------------------------------
1 | # Wait for the server to start
2 | echo "Waiting for server to open port ${port}..."
3 | if wait_until_port_used "${host}:${port}" 120; then
4 | echo "Discovered server listening on port ${port}!"
5 | else
6 | echo "Timed out waiting for server to open port ${port}!"
7 | clean_up 1
8 | fi
9 | sleep 2
10 |
--------------------------------------------------------------------------------
/sh_rstudio/template/before.sh.erb:
--------------------------------------------------------------------------------
1 | # Export the module function if it exists
2 | [[ $(type -t module) == "function" ]] && export -f module
3 |
4 | # Find available port to run server on
5 | port=$(find_port $host)
6 |
7 | # Define a password and export it for RStudio authentication
8 | password=$(create_passwd 16)
9 | export RSTUDIO_PASSWORD=$password
10 |
11 | # Generate CSRF token for RStudio
12 | <%- require 'securerandom'
13 | csrftoken = SecureRandom.uuid -%>
14 | export csrftoken=<%= csrftoken %>
15 |
--------------------------------------------------------------------------------
/sh_rstudio/template/bin/auth:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Confirm username is supplied
4 | if [[ $# -lt 1 ]]; then
5 | echo "Usage: auth USERNAME"
6 | exit 1
7 | fi
8 | USERNAME="${1}"
9 |
10 | # Confirm password environment variable exists
11 | if [[ -z ${RSTUDIO_PASSWORD} ]]; then
12 | echo "The environment variable RSTUDIO_PASSWORD is not set"
13 | exit 1
14 | fi
15 |
16 | # Read in the password from user
17 | read -s -p "Password: " PASSWORD
18 | echo ""
19 |
20 | if [[ ${USERNAME} == ${USER} && ${PASSWORD} == ${RSTUDIO_PASSWORD} ]]; then
21 | echo "Successful authentication"
22 | exit 0
23 | else
24 | echo "Invalid authentication"
25 | exit 1
26 | fi
27 |
28 |
--------------------------------------------------------------------------------
/sh_rstudio/template/script.sh.erb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # load modules
4 | module reset
5 | module load rstudio/2023
6 | module load <%= context.auto_modules_R %>
7 | <%- unless context.sh_modules.blank? -%>
8 | module load <%= context.sh_modules %>
9 | <%- end -%>
10 |
11 | # create server configuration
12 | export RSTUDIO_CONFIG_DIR=$PWD # system config
13 | export RSTUDIO_DATA_HOME=$PWD # per-session storage
14 | export RSTUDIO_AUTH="$PWD/bin/auth"
15 |
16 | _workspace_dir=<%= context.sh_workspace.blank? ? "$HOME" : context.sh_workspace %>
17 |
18 | cat <<-EOF > $RSTUDIO_CONFIG_DIR/rserver.conf
19 | server-user=$USER
20 | www-port=$port
21 | auth-none=0
22 | auth-pam-helper-path=$RSTUDIO_AUTH
23 | auth-encrypt-password=0
24 | auth-timeout-minutes=0
25 | database-config-file=$RSTUDIO_CONFIG_DIR/database.conf
26 | server-data-dir=$L_SCRATCH_JOB
27 | server-app-armor-enabled=0
28 | EOF
29 |
30 | cat <<-EOF > $RSTUDIO_CONFIG_DIR/rsession.conf
31 | session-timeout-minutes=0
32 | session-timeout-suspend=0
33 | session-save-action-default=no
34 | session-quit-child-processes-on-exit=1
35 | r-restore-workspace=0
36 | session-default-working-dir=$_workspace_dir
37 | EOF
38 | cat <<-EOF > $RSTUDIO_CONFIG_DIR/logging.conf
39 | [*]
40 | log-level=info
41 | logger-type=file
42 | log-dir=$RSTUDIO_CONFIG_DIR/sessions
43 | EOF
44 | cat <<-EOF > $RSTUDIO_CONFIG_DIR/database.conf
45 | provider=sqlite
46 | directory=$RSTUDIO_CONFIG_DIR
47 | pool-size=$SLURM_CPUS_ON_NODE
48 | EOF
49 | mkdir $RSTUDIO_CONFIG_DIR/sessions
50 |
51 | # start server
52 | rserver 2>&1
53 |
54 |
55 |
--------------------------------------------------------------------------------
/sh_rstudio/view.html.erb:
--------------------------------------------------------------------------------
1 |
11 |
12 |
23 |
--------------------------------------------------------------------------------
/sh_tensorboard/README.md:
--------------------------------------------------------------------------------
1 | ## `sh_ondemand`
2 |
3 | This [Tensorboard](https://www.tensorflow.org/tensorboard) OnDemand app runs through an authenticating reverse proxy.
4 |
5 | Tensorboard doesn't provide any kind of authentication for its web interface, so on a shared environment, anybody
6 | knowing the hostname and port number of a running Tensorboard instance can connect to it.
7 |
8 | To mitigate this, we implemented an authentication mechanism that basically sets a browser cookie in the OnDemand
9 | interactive app page (through the "Connect to Tensorboard" button), which is then checked by the authenticating
10 | reverse proxy to control access to the Tensorboard web interface.
11 |
12 | Without that cookie, access to the Tensorboard
13 | web interface is refused. And if the cookie is ever lost, users can re-create it by visiting the
14 | "My Interactive Sessions" page and clicking the "Connect" button again.
15 |
--------------------------------------------------------------------------------
/sh_tensorboard/form.js:
--------------------------------------------------------------------------------
1 | ../_common/form.js
--------------------------------------------------------------------------------
/sh_tensorboard/form.yml.erb:
--------------------------------------------------------------------------------
1 | cluster: "sherlock"
2 |
3 | form:
4 | - auto_modules_py-tensorflow
5 | - tb_logdir
6 | - tb_extra_args
7 | <%- IO.foreach(File.expand_path(File.dirname(__FILE__))+"/../_common/form/form.yml") do |line| %>
8 | <%= line %>
9 | <%- end -%>
10 |
11 |
12 | attributes:
13 |
14 | auto_modules_py-tensorflow:
15 | label: "Tensorflow version"
16 | default: false
17 |
18 | tb_logdir:
19 | label: "Tensorboard logdir"
20 | required: true
21 | help: "The directory that contains data to visualize."
22 |
23 | tb_extra_args:
24 | label: "Additional TensorBoard arguments (optional)"
25 |
26 | <%- IO.foreach(File.expand_path(File.dirname(__FILE__))+"/../_common/form/attributes.yml") do |line| %>
27 | <%= line %>
28 | <%- end -%>
29 |
--------------------------------------------------------------------------------
/sh_tensorboard/icon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stanford-rc/sh_ood-apps/4c5cf6a4b5ed63813c61c7de32a68168d97787dc/sh_tensorboard/icon.jpg
--------------------------------------------------------------------------------
/sh_tensorboard/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stanford-rc/sh_ood-apps/4c5cf6a4b5ed63813c61c7de32a68168d97787dc/sh_tensorboard/icon.png
--------------------------------------------------------------------------------
/sh_tensorboard/manifest.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: TensorBoard
3 | category: Interactive Apps
4 | subcategory: Viz
5 | role: batch_connect
6 | description: |
7 | This app will launch [TensorBoard], [TensorFlow]'s Visualization Toolkit, on [Sherlock].
8 | [TensorBoard]: https://www.tensorflow.org/guide/summaries_and_tensorboard
9 | [TensorFlow]: https://www.tensorflow.org/
10 | [Sherlock]: https://www.sherlock.stanford.edu
11 |
--------------------------------------------------------------------------------
/sh_tensorboard/submit.yml.erb:
--------------------------------------------------------------------------------
1 | batch_connect:
2 | template: "basic"
3 |
4 | script:
5 | native: [
6 | "-N", "1",
7 | "-c", "<%= sh_cpus.blank? ? 1 : sh_cpus.to_i %>",
8 | <%- if not sh_gpus.blank? -%>
9 | "-G", "<%= sh_gpus.to_i %>",
10 | <%- end -%>
11 | <%- if not sh_mem.blank? -%>
12 | "--mem", "<%= sh_mem.to_i %>G",
13 | <%- end -%>
14 | <%- if not sh_features.blank? -%>
15 | "--constraint", "<%= sh_features %>"
16 | <%- end -%>
17 | ]
18 |
--------------------------------------------------------------------------------
/sh_tensorboard/template/after.sh:
--------------------------------------------------------------------------------
1 | # wait for the Tensorboard server to start
2 | echo "$(date): waiting for Tensorboard server to open port ${app_port}..."
3 |
4 | if wait_until_port_used "127.0.0.1:${port}" 300; then
5 | echo "$(date): discovered Tensorboard server listening on port ${app_port}!"
6 |
7 | # wait for the authenticating proxy to start
8 | echo "$(date): waiting for authrevproxy server to open port ${proxy_port}..."
9 |
10 | if wait_until_port_used "${node}:${proxy_port}" 60; then
11 | echo "$(date): discovered authrevproxy server listening on port ${proxy_port}!"
12 | fi
13 |
14 | else
15 | echo "$(date): timed out waiting for Tensorboard server to open port ${app_port}!"
16 | echo "- wait ended at: $(date)"
17 | pkill -P ${SCRIPT_PID}
18 | clean_up 1
19 | fi
20 |
21 | sleep 2
22 |
--------------------------------------------------------------------------------
/sh_tensorboard/template/before.sh.erb:
--------------------------------------------------------------------------------
1 | # export the module function if it exists
2 | [[ $(type -t module) == "function" ]] && export -f module
3 |
4 | # find available port to run server on
5 | export app_port=$(find_port "$host")
6 |
7 | # find another available port to run the AuthRevProxy on
8 | port=$(find_port "$host")
9 | export proxy_port=$port
10 |
11 | # generate password
12 | password=$(create_passwd 32)
13 |
14 | # export token for cookie verification by authrevproxy
15 | # replace dashes by underscores in session.id
16 | export _ood_token_<%= session.id.gsub("-","_") %>=$password
17 |
18 | # background start authrevproxy, to authentify web requests to the application
19 | bin/authrevproxy.py --app-port="$app_port" --proxy-port="$proxy_port" &
20 |
--------------------------------------------------------------------------------
/sh_tensorboard/template/bin/authrevproxy.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | # provides a reverse proxy that only allows requests coming from the same
4 | # user it's running as
5 | #
6 | # grant access based on the presence of a _ood_token_=
7 | # cookie, where:
8 | # is the OnDemand Session id
9 | # is the password defined in the template/before.sh script
10 |
11 | from twisted.internet import reactor, endpoints
12 | from twisted.web import proxy, server
13 | from twisted.web.resource import Resource
14 | from twisted.web.error import ForbiddenResource
15 |
16 | import argparse
17 | import getpass
18 | import sys, os
19 |
20 |
21 | #
22 | # ReverseProxy Resource that checks cookie before forwarding requests
23 | #
24 | class TokenResource(Resource):
25 |
26 | def __init__(self, host, port, path):
27 | Resource.__init__(self)
28 | self.host = host
29 | self.port = port
30 | self.path = path
31 |
32 | def getChild(self, path, request):
33 |
34 | # get username from headers
35 | # - this should be set on authenticated web sessions
36 | try:
37 | user = request.getHeader("x-forwarded-user")
38 | except:
39 | user = None
40 |
41 | # check if the request comes from the right user (note: can be forged)
42 | if user == getpass.getuser():
43 |
44 | # get ood token cookie
45 | # - cookie name depends on the ood interactive session id ($PWD)
46 | ood_session_id = os.path.basename(os.getcwd())
47 | try:
48 | cookie = request.getCookie('_ood_token_' + ood_session_id)
49 |
50 | except:
51 | cookie = None
52 |
53 | # get token from environment
54 | # - $_ood_token_ is set in template/before.sh script
55 | try:
56 | ood_token = os.environ.get("_ood_token_" +
57 | ood_session_id.replace("-", "_"))
58 | except:
59 | ood_token = None
60 |
61 | # check that cookie matches the local token
62 | if cookie == ood_token and cookie != None:
63 | return proxy.ReverseProxyResource(self.host,
64 | self.port,
65 | '/' + path)
66 |
67 | # no cheese for you
68 | request.setResponseCode(403)
69 | return ForbiddenResource()
70 |
71 |
72 | #
73 | # parse arguments
74 | #
75 | def parse_args(argv=sys.argv[1:]):
76 | parser = argparse.ArgumentParser(description='Token Revproxy')
77 | parser.add_argument('--app-port', dest='app_port', type = int,
78 | required = True, help='application port, to forward requests to')
79 | parser.add_argument('--proxy-port', dest='proxy_port', type = int,
80 | required = True, help='proxy port, to listen for requests on')
81 | args = parser.parse_args(argv)
82 | return args
83 |
84 | #
85 | # entry point
86 | #
87 | def main(argv=sys.argv[1:]):
88 | args = parse_args(argv)
89 | print('authrevproxy is starting on port {} -> {}'.format(args.proxy_port,
90 | args.app_port) )
91 | dest = TokenResource('127.0.0.1', args.app_port, '')
92 | site = server.Site(dest)
93 |
94 | endpoint = endpoints.TCP4ServerEndpoint(reactor, args.proxy_port)
95 | endpoint.listen(site)
96 | reactor.run()
97 |
98 |
99 | if __name__ == '__main__':
100 | main()
101 |
102 |
--------------------------------------------------------------------------------
/sh_tensorboard/template/script.sh.erb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # load modules
4 | module reset
5 | module load <%= context.auto_modules_py_tensorflow %>
6 | <%- unless context.sh_modules.blank? -%>
7 | module load <%= context.sh_modules %>
8 | <%- end -%>
9 |
10 | # set workspace
11 | cd <%= context.sh_workspace.blank? ? "$HOME" : context.sh_workspace %>
12 |
13 | # start server
14 | # start on 127.0.0.1, since TensorBoard doesn't support any kind of authentication
15 | # and we rely on authrevproxy to only allow authentified requests
16 | tensorboard --logdir=<%= context.tb_logdir %> <%= context.tb_extra_args %> \
17 | --host=127.0.0.1 \
18 | --port="${app_port}"
19 |
--------------------------------------------------------------------------------
/sh_tensorboard/view.html.erb:
--------------------------------------------------------------------------------
1 | <%-
2 | # generate form id, based on host and port
3 | form_id = Digest::SHA1.hexdigest("--" + host.to_s + "--" + port.to_s + "--")
4 | -%>
5 |
6 |
17 |
18 |
23 |
--------------------------------------------------------------------------------