├── 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="".concat(r,"");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 |
27 | 28 | 31 |
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 |
21 | 22 | 25 |
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 |
7 | 10 |
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 |
2 | 3 | 6 |
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 |
13 | "> 14 | 15 | 16 | 17 | 18 | 19 | 22 |
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 |
19 | 22 |
23 | --------------------------------------------------------------------------------