-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbrywidgets.brython.js
3 lines (3 loc) · 47.1 KB
/
brywidgets.brython.js
1
2
3
__BRYTHON__.use_VFS = true;
var scripts = {"$timestamp": 1622995411919, "brywidgets": [".py", "\nfrom .widgetset import *\n", ["brywidgets.widgetset"], 1], "brywidgets.images": [".py", "whitemask_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAADHUlEQVR4nO3UAQ3AQBDDsP74c74BiS2FQt7dbduT1OsbkGUAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEGYAEPYDIJIF/AcNZY8AAAAASUVORK5CYII='\nblackmask_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAADIklEQVR4nO3UsQ3AMADDMAfo/y+3S3/IIBLw7kkbkHX+AUHPBACyBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCBADCzrb39gngjg8B5QX0c+LYJAAAAABJRU5ErkJggg=='\nfile_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAC4SURBVCjPdZFbDsIgEEWnrsMm7oGGfZrohxvU+Iq1TyjU60Bf1pac4Yc5YS4ZAtGWBMk/drQBOVwJlZrWYkLhsB8UV9K0BUrPGy9cWbng2CtEEUmLGppPjRwpbixUKHBiZRS0p+ZGhvs4irNEvWD8heHpbsyDXznPhYFOyTjJc13olIqzZCHBouE0FRMUjA+s1gTjaRgVFpqRwC8mfoXPPEVPS7LbRaJL2y7bOifRCTEli3U7BMWgLzKlW/CuebZPAAAAAElFTkSuQmCC'\nlogin_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH5AQRDyIA8MpkEwAAAZNJREFUWMPtlr1Ow0AQhL87m/w8AKFIS4fEiyNAQElBgWhCAaI0YBAFD0AiIXBi00ykU3IW2Nw5FKy0Suyzb2d3dscH/7ZuFhgDx8AUKIFFQJ9q7zFgjAfANvAKpAr+GTA5A/T0OxeINTsHKuAIGApISB8Ch4px5iv/TIvL6xgUG8V4W13sq+RVB71WAZX9Cx0fwg6ACTDQnknbjQbAewsKbvVOJn7tTynwLfTlTaq4BeSa8yd1+3dAqlC9Zp2yP2i+MyXRCQAXSAo8qxKPzv2kKwAuHXOB6IsOLwDjNF8ZUG4NcAfsipY9oPAAAOBSi/NAXsg/REUJXNdVINVDaSSdKTtSVa9NBCCvSTBaE1ppwUIT0asZx+AAjD61mXrhXpknsQEkzqxnyjx3grcWItMgc1eKc13bNgAGLUtzo4Zblv3HH6PUc7NQBk3sRYq3LyCmLZ+/PRE1CRzlRFS1mV3XihXNjnFkcxtzZj3SeaX/J5EAGO0NcOF7YCQhKZ2JCO2lYuzU0TISylgAThVj46fyzdsXtrrGy/mieuYAAAAASUVORK5CYII='\nsave_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gcCEA0AJvnZjwAAAXdJREFUWMNj/MzwlZEBBXAjmF8Z0KS+YlXHy8QEZ3/+948BF0BV95mBgYGBgYlhgMGoAxjR0wAvAzdKJNrb21NkwcGDB9G8DEkIsDTAgk3Tmr2/4Oyd874yzFoiQJblaTEfGHL3QhLrtet/GepyODHUsJyfzM2y/TnDf7hIGwNcAwMDA8OXLxcYPn8yIssBX75cYLh23YKBgYGB4fHxHwwMDAwMEyf+Y2FgYGA4D81Fo4lw1AGjDhh1AAshBZquFgzpcSfIMlzT1YJyBxBrENkhcP85A6MGAwMjvYL8xXOIXfeHTBqAgSPbU0ky2MZzNnUdwMDAwFBXU4xVvKmll2HNsqlwfkhU9mg5MOqAIV4UX7v+F96GQwZ37tzHadCla/dQ+Nj0Y22WL6xiYEMXjG9j+EkrH1dWMbAzMDAwaOALgYVQRejgwwtE61lAgvTi+wbWKOBjYJZBErj1CWGJGh+qJTJ8CPYTZHEcFj5B42sgc56O5gIIAADUZGN7H3Li0AAAAABJRU5ErkJggg=='\nopen_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gcCEAg2lDS4UwAAAw1JREFUWMPtl0FIFFEYx//zxt2l3TYESddD6KHWxb2UoXgpCBSShGrLUynRsUgiAwkJgsBLIGTsKTrYUgSKqKdAD4E32cxDu6kVZeSmrNnmOkvs7ryvw87OzuqMO+qKF99l5r157/v9v+9975sZIS5RZSIB3Wa3J35pepXaZ05nYkntxHPjcYe+LSfL78d55sqwz+1AwL4LKCmWoZVwmJfV1yPs8apjtbMhrEPa0klhwAfxqAfCbuAtvUhpwdpWOxtC/zNYAaDJ701O3A5ZAeBUMSMQ9nhRMfACU6ONlsmzufHrd72psMeLzjuhpJHAouTAgi9kmRpttGwcz3prBNeNQHXHfGpoeNxwwVVfM76/dFv2LAmHhsfx8MEt3cmS1IbuniguOMwZb/J7k9sSUN0xnwqq3o8ZLqrumE+ZiUJ2C0yfguBhfyrjvTFckgLo6z9X0PsrvmZMjLsNBez4FDgc7bjXGSg4r7snCvfxPSpEDkf7ls8lKWDa1p6V4p+Li0Uuxavm4UtzXgARcwJipWCzkyAAONRiDP86N43X78pNSijH6bpy/I37Nx3D5eUoGhyPbN9MR0CBd/VFMDJYt+utudQ2gwa32S3Ig7cWTC4iAcQZiDNwzgDOQGkRXGaI/TiGrr4Ieh93IRh4bkKAWTgJ4JyBuAAulwBcAMmiKoLkEqxFKjRwj61wEhaAEwkgmYFI8VRmIC6CpxmIMh6TLIJkBmmlzBCuL2B1TBeuDS9xlhEgZ2CcREBmKphT5vovdkSB30cwUGMzdQy18PX4KxCJeVAuZ/uiKkANd1pU5yUTdhU+8aTGWurS/+jZJCALX4u9AecWxbOsYVHZVxEkC+CUEUFpZQsUoXLSkgc3XYjeT89gZLAVsegQiNvA00yBKCHPQtL5EeCkZLzMQCSYhutGQJIC+P3Fu+Nzvh34JgGXL57HtRtvTZdRvbYdOAAIT2/CsvQ5U4oBwHVi+1/IH3Te8xubYRJaXRDPuHIDH//kxDhP5hZVLRgLsFbl7jW3iNpz6xOfcna18w5+zf4DPXKrvrM0c5AAAAAASUVORK5CYII='\nuparrow_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4gYSDiAYbn7rYwAAAahJREFUOMu1kz1LHGEQx//z8uzeeXfGezGgW1gELFQkYJsmBgQbO4srkhQpBD9CvoSlXZqAH8AXUOzPQgwpkkJMCgs1t3rooXfmbp/dx8KAxHhrYwammZc/zG9mgP9pwxiVx2q4V2LgTanaWQzts6nB8TQBfbB5plzNvqYVfziP62L7G+H5xMVe+P2hWrofKM5WqrlpWfGH+kAASBjt/Su0NtzExe6/In/NWJ6vvM+8cp/zI0UQM1gFsY2BgoMrtRf9zMDa9c/WSU8G3PHOO1u6lNgIxiicTZBEFnEjht3OLRAjkwrxdPV4Fco7LAIWRWwjqCqEBc7SemOzXnt8CwyICuAc1BiwUbBh4OqO9+DcUMoWBMQiEGaoKogAE+QQv708LERBvRva+q/lk6meAmK5RSCI8ZDECZgIRITyZEWZJWh8OfPSR2j21br1CJ6XgaqB/HEVhYiAhV2qQFg7OG9+bX6ytotsvh+q5hakMbdMhFzqJQbvAhwtH31wHfzoHyt89EvZPBsHuAQAYFs2m3qJ963y8kUOpd9FInaIAfK5G24dnj7Zx94ADimDkToKgnYAAAAASUVORK5CYII='\nsaveas_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gcCEAs4WKHGlwAAAZpJREFUWMNj/MzAwMiAAqpR+LxM7f9h7Mp/lXC5diRxZICsBmJcK5xZhSwOFWZiGGAw6gBG9DTAy8DwD5lvb29PkQUHDx5E4X+uZmBGTgMs2DSt2fsLzt457yvDrCUCZFmeFvOBIXcvNwMDAwPDtet/GepyODHUsJyfzMByHlkklwGugYGBgeHLlwsMnz8ZkeWAL18uMFy7bsHAwMDA8Pj4DwYGBgaG6/8hnr6+GE8I4AK8/PxEqfv88SPRZpLkgEuKKkSpUyTBTJIcoHjh7PDLhlRNA6TEPU3SgCKtQ2BkpgFNVwuG9LgTZBmu6WpBnSggxiCyQ+D+cwZGGSH0RgntwGOoXS+PDbVy4Mj2VJIMtvGcTf1sWFdTjFW8qaWXYc2yqXB+SFT2aJNs1AFDvCi+dv0vvA2HDO7cuY+7prx2D7XAwaIfa7N8YRUDGw9SSXjmHcP/9jaGn7Ty8doeBg4GBgaGu3fxhEBlFQM7jK2BJH4DiW1CpeKbRYaPgZnhD0LAhQ9Pe4CbsKX3vzL8x6nnBUL8r9ZoLoAAAM8Qb3qVzu5AAAAAAElFTkSuQmCC'\nclosebutton_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAA9CAQAAAC33KdKAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBA8JKxSPmVc5AAAD3UlEQVRYw+2ZTWhcVRTHfy9IbSwiSbGgpbW6EqW40KhQRGrrx6Yoii4rxU0LiuLCrSgIKtRFF4K6KEjFgoVSR0q/FIQagy0ltjYxVNsUpdPEiZMYUzOZTP4ukmmSN+e+e+/Mm4XgvYtM3jvv/M4997x7zr0Pmmx9qf+LTepJmnlInckaurmTu+gGahS5QJGSRhLBIZ6mDW0PILiZ7VxEzl7gPla2Af86wBbK1DLg9V6jV2vytuAV/gxAL+0/czfsbJW7G+AhfomE1/sxJXlMvlrqz8HepuFdDLWIF2IPbGoKf3sO8Pnep2RrDPm1fPFCXIpdalYxk6sB4leI8cJfOeOFOEKII3YjON8GvBAvhY3+ZecKNxUIcvvvDj9+vePROZU1FBQZNVU57rg3BGWPAd/aj6okSRpkzmeA/pEkDjjub89OOY9m4gNM0ExdkH2mRCV7/L0evCQNUHXiK0sF+cKUesPB/g3uMed+OX7eCxVz7q+lBTlqyF12j99y2rSsNsh0Sm5Wk5Ygo4bOnkmHAeOmy74xTRhY9kbMasLE/2Fq/NrG9zhD67BpwvnFcHSMvujQNwqFNP0r+DQjuo86TJjHX4vCC6nT8sBA5vv9ncsETQfP/WJ/1TJgzLPEnDFNGDPxPl191jbDv8jaJjTiy15Npf0NFUBXUJo5GYAfC9Az0dNgwIOhWd2DHw3SMlXfk3Vc36PdGliqPJkUMnZ6RcL0dDT8WPLL17Ylxx34EW6LrXwXsdWIivER+7JK8aX3dQP0ezD+b8f2M+Fe/YSClNQ603K6ISwIVfa8BOeYDdAz/rxxvFD1PjZnLzupdjZgD3110HDLFe/ox8IWIp31GnDQiv0rnrmfoNu4fMa4tlHnPDGwr+HKZ/BW5ujNhKurSMccsZDlAXOEt0TjSwt3eyMnYtjlmAsO/LgJWJJydDrKhE9cBrwTWJSm8Ajpe1PqR+ulVJfz+M0sSitu5y9TeyIwNZ/Mis6PDBNOqZrSOuKYqi+DUvMTB130p2Ctqfr0Mi9k1XoFL/6Ub5V+21EL1QtPT75XvYifcxQmD2TSd6IbHXu/fk1JCjgt1A+Sag78xyGZaqNDdb8qgQlryHGsWdHKHUHJ8sM2nZCsD6LvBRhsA/6FuFJlOGf8u/BYOP1x1JGrF96DdXEO2II6OJITfhdMxpeLWwHebxk+w+amz6ovATwcuNWQYw1dkcfnis+DCs10L/Ms7GidvnCudzgKXmNX/h+ObuLFIE/0cz8rWvlM4Whvzv/ZwDPsNw9tL/IBm1gNMTEf/U2nwLaFjUyyjtWsAsSERpMi/7f/ZvsXgZFyMZwaSZIAAAAASUVORK5CYII='\nhues_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAwCAYAAAD+f6R/AAABIklEQVR4nO3aMW7DMBBE0ZWS+P7nDZIohXubjbAk5z1gLzDFhwDxuKquelStcH8fVd+1xl312T/Y0H31jzV452//WqN31E//YAN3FhBLACCYAEAwAYBgAgDBBACCCQAEO+uoWuWuWufax9pw1AnWGr72sQbPFwAEEwAIJgAQTAAgmABAMAGAYAIAwbwDuOGeJhhsp1EXegfwNMFg3gEArwgABBMACCYAEEwAIJgAQDABgGDeAdxw7UPtOOpS7wAmGMs7AOAdAYBgAgDBBACCCQAEEwAIJgAQbJ13ANX9x9Q7gOZRu5fyDgDYiwBAMAGAYAIAwQQAggkABBMACLbMO4D+P6beAXTeBEt5BwDsRQAgmABAMAGAYAIAwQQAggkABPsHW+IBkGJm7agAAAAASUVORK5CYII='\nminus_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAADzZAAA82QHNHPbHAAAAB3RJTUUH5AQPCQkWxiVwNQAAAGlJREFUeNrt2LERgCAQRUHObuyA/iM7sByIzmFs4e9GEPKA5MYAAAAAACBHnZt5r5Vy8Oet+gIkHfwf4Yr/Aqm33+JfgAACCCCAAAIIIIAAAgggQOY8oCcjsfOAXqTNBdIvHgAAAAAg0wbIrBHGR5+81AAAAABJRU5ErkJggg=='\ncopy_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gcCEzsDNKqnGQAAAZpJREFUWMPtlz9Lw0AYh3+RbtLQ4tfwQ/gRpDiULh0UBKlQKIgoSJdmc1MnHfyDdauLYDfBVcQPIE4Wl0LbC6ZY7+51kBTT2OaSS8ziOyWBlzw8d+8vF+MtO480aw4pV+oAmckH7aNz6vXZ1IZ8zsTD4xN2j/eNRAAAoFopT204vWjBqtewA1AcEJGWIGuasOo1NNZqlNoeiAtCaxPGAZEJ29DrM6yubyc3BUFVrZRhM++UnJy1gGYCAKXlO8/95fXSWP2fGHBfOGsk3cy4sg4pSmaEMvCz7JdnrGwtaGdGZAPd7iJubu+VJ2UahLaBMOP6G0TiBoIgfACOM4zNgEpm+AAGzI7NgEpm+ABs+z3SPKtmRj5nzjbAmI2P0QgAQFJACoKQEiAJSQRJEiRl6MxQXgLHGWJjcy+w8bXTQalYUNovLiARBQM0mgfKh4x2sUBhDAgh9D9GUTLDBUwUQMUA5zxeANXMGBvgwtOjDaCaGWMDknt6tI9kYTODf3Jfj5YB1cyQ8vvaMAywCQPae0AlM2aV8f9zmjbAFxVWCezT1eQrAAAAAElFTkSuQmCC'\ncircle_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAARElEQVR4nI2QwQkAMQzDrO6/s+7VkpYLxE8h4mDUAKaJSpKQxApq9gGV1UkvX13lm5EIOBLPj+Pqbp7KGe+otwP4N9cH/OwpBV7e2E4AAAAASUVORK5CYII='\nplus_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAADzZAAA82QHNHPbHAAAAB3RJTUUH5AQPCQYbPwwQRwAAALZJREFUeNrt20EOQDAQBVDjNm7g/is3cJxaSbBEmzbz/spGYp7q4qdiapB1KeXNfdseUfvZosfBW0JE78PXRpin5AEAAAAAAAAAAAAAAAAAAAAAAACQLbee7e8er+ecHWNkG/yJ4BPI+vZtggAAAAAAAAAAAAAAAACQNdseMbc4i9d1H3BeZOsFbpVYjTgnaBMEAAAAAAAAAAAAAAAAAAAAAABIBjBK2TrEChjy5+lrvhSktVfSAYIsKVsYNMYvAAAAAElFTkSuQmCC'\nfolder_b64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGrSURBVDjLxZO7ihRBFIa/6u0ZW7GHBUV0UQQTZzd3QdhMQxOfwMRXEANBMNQX0MzAzFAwEzHwARbNFDdwEd31Mj3X7a6uOr9BtzNjYjKBJ6nicP7v3KqcJFaxhBVtZUAK8OHlld2st7Xl3DJPVONP+zEUV4HqL5UDYHr5xvuQAjgl/Qs7TzvOOVAjxjlC+ePSwe6DfbVegLVuT4r14eTr6zvA8xSAoBLzx6pvj4l+DZIezuVkG9fY2H7YRQIMZIBwycmzH1/s3F8AapfIPNF3kQk7+kw9PWBy+IZOdg5Ug3mkAATy/t0usovzGeCUWTjCz0B+Sj0ekfdvkZ3abBv+U4GaCtJ1iEm6ANQJ6fEzrG/engcKw/wXQvEKxSEKQxRGKE7Izt+DSiwBJMUSm71rguMYhQKrBygOIRStf4TiFFRBvbRGKiQLWP29yRSHKBTtfdBmHs0BUpgvtgF4yRFR+NUKi0XZcYjCeCG2smkzLAHkbRBmP0/Uk26O5YnUActBp1GsAI+S5nRJJJal5K1aAMrq0d6Tm9uI6zjyf75dAe6tx/SsWeD//o2/Ab6IH3/h25pOAAAAAElFTkSuQmCC'\n", []], "brywidgets.widgetset": [".py", "#!/usr/bin/python\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nfrom browser import document,window,alert,confirm\nimport browser.html as html\nimport browser.ajax as ajax\nfrom .images import *\n\n\n\n\n\ndef delete(element):\n element.parentNode.removeChild(element)\n del element\n \ndef gettextwidth(text,font=\"12pt Arial\"):\n canvas=html.CANVAS()\n ctx=canvas.getContext(\"2d\")\n ctx.font=font\n return ctx.measureText(text).width\n \n \n \ndef rgbtotuple(colour):\n return tuple([int(x)for x in colour[4:-1].split(\",\")])\n \ndef tupletohex(colourtuple):\n return \"#\"+''.join(format(n,'02x')for n in colourtuple)\n \ndef hextotuple(hexcolour):\n return tuple(int(hexcolour[i:i+2],16)for i in [1,3,5])\n \ndef rgbtohwb(colour):\n if isinstance(colour,str):colour=rgbtotuple(colour)\n maxc=max(colour);maxi=colour.index(maxc)\n minc=min(colour);mini=colour.index(minc)\n whitealpha=1 if maxc ==0 else minc /maxc\n blackalpha=1 -maxc /255\n \n hue=(R,G,B)=(0,255,255)if maxc ==minc else tuple(int(255 *(c -minc)/(maxc -minc))for c in colour)\n if R ==255:huenumber=G if B ==0 else (256 *5)+255 -B\n elif G ==255:huenumber=(256 *2)+B if R ==0 else (256)+255 -R\n elif B ==255:huenumber=(256 *4)+R if G ==0 else (256 *3)+255 -G\n \n return hue,huenumber,whitealpha,blackalpha\n \ndef hwbtorgb(hue,whitealpha,blackalpha):\n if isinstance(hue,int):\n i=hue %256\n if hue <256:(R,G,B)=(255,i,0)\n elif 256 <=hue <256 *2:(R,G,B)=(255 -i,255,0)\n elif 256 *2 <=hue <256 *3:(R,G,B)=(0,255,i)\n elif 256 *3 <=hue <256 *4:(R,G,B)=(0,255 -i,255)\n elif 256 *4 <=hue <256 *5:(R,G,B)=(i,0,255)\n elif 256 *5 <=hue <256 *6:(R,G,B)=(255,0,255 -i)\n hue=(R,G,B)\n colour=tuple(int((1 -blackalpha)*(C *(1 -whitealpha)+255 *whitealpha))for C in hue)\n return hue,colour\n \nclass Global():\n ''\n alertStyle=\"standard\"\n promptStyle=\"standard\"\n \nclass Notebook(html.DIV):\n ''\n\n\n\n\n\n\n\n \n \n def __init__(self,pagelist=[],tabheight=\"2em\",className=None ,id=None ):\n html.DIV.__init__(self,\"\",Class=\"notebook\")\n self.clearfloat=html.DIV(style={\"clear\":\"both\"})\n self.tabrow=html.DIV(self.clearfloat,Class=\"notebooktabrow\",style={\"text-align\":\"center\"})\n self.tabheight=tabheight\n self <=self.tabrow\n self.pagelist=[]\n for page in pagelist:self.addpage(page)\n if className:self.classList.add(className)\n if id:self.id=id\n \n def addpage(self,page):\n self <=page\n page.tab=NotebookTab(self,len(self.pagelist),page.tabtitle,self.tabheight,page.tabwidth)\n page.tab.style.backgroundColor=page.style.backgroundColor\n if page.id:page.tab.id=page.id+\"_tab\"\n self.tabrow.insertBefore(page.tab,self.clearfloat)\n page.style.display=\"block\"if len(self.pagelist)==0 else \"none\"\n self.pagelist.append(page)\n \nclass NotebookPage(html.DIV):\n ''\n \n def __init__(self,title,bgcolour,content=None ,tabwidth=\"10%\",className=None ,id=None ):\n html.DIV.__init__(self,\"\",style={\"background-color\":bgcolour},Class=\"notebookpage\")\n self.tabtitle=title\n self.tabwidth=tabwidth\n if className:self.classList.add(className)\n if id:self.id=id\n if content:self <=content\n \n def update(self):\n pass\n \nclass NotebookTab(html.DIV):\n ''\n \n def __init__(self,notebook,index,title,height,width):\n html.DIV.__init__(self,html.P(title,style={\"margin\":\"0.4em\"}),Class=\"notebooktab\",style={\"height\":height,\"float\":\"left\",\"cursor\":\"pointer\"})\n if width:self.style.width=width\n self.notebook=notebook\n self.tabindex=index\n self.bind(\"click\",self.select)\n \n def select(self,event=None ):\n for p in self.notebook.pagelist:\n p.style.display=\"none\"\n self.notebook.pagelist[self.tabindex].style.display=\"block\"\n self.notebook.pagelist[self.tabindex].update()\n \nclass DropDown(html.SELECT):\n ''\n\n\n\n\n \n def __init__(self,choices,onchange,initialchoice=None ,className=None ,id=None ):\n html.SELECT.__init__(self,\"\",Class=\"dropdown\")\n self <=(html.OPTION(text)for text in choices)\n self.bind(\"change\",onchange)\n if initialchoice:self.selectedIndex=initialchoice\n if className:self.classList.add(className)\n if id:self.id=id\n \nclass ListBox(html.SELECT):\n ''\n\n\n\n\n\n \n def __init__(self,choices,onchange,size=None ,initialchoice=None ,className=None ,id=None ):\n html.SELECT.__init__(self,\"\",Class=\"listbox\")\n self <=(html.OPTION(text)for text in choices)\n self.bind(\"change\",onchange)\n self.size=size if size else len(choices)\n self.selectedIndex=initialchoice if initialchoice else -1\n if className:self.classList.add(className)\n if id:self.id=id\n \nclass InputBox(html.INPUT):\n ''\n\n \n def __init__(self,enterkeyaction,className=None ,id=None ):\n html.INPUT.__init__(self,Class=\"inputbox\")\n self.enterkeyaction=enterkeyaction\n self.bind(\"keypress\",self.onKeypress)\n if className:self.classList.add(className)\n if id:self.id=id\n \n def onKeypress(self,event):\n if event.keyCode !=13:return\n self.enterkeyaction(self.value)\n \nclass SpinControl(html.DIV):\n ''\n\n\n\n\n\n \n def __init__(self,initialvalue,minvalue,maxvalue,action=None ,stepvalue=1,className=None ,id=None ):\n decrease=html.IMG(src=minus_b64,id=\"minus\",style={\"height\":\"100%\",\"float\":\"left\"})\n decrease.bind(\"click\",self.ondecrease)\n increase=html.IMG(src=plus_b64,id=\"plus\",style={\"height\":\"100%\",\"float\":\"right\"})\n increase.bind(\"click\",self.onincrease)\n self.currentvalue=initialvalue\n self.stepvalue=stepvalue\n self.minvalue=minvalue\n self.maxvalue=maxvalue\n widthems=max(len(str(minvalue)),len(str(maxvalue)))*0.6+3\n self.valuespan=html.SPAN(str(self.currentvalue),style={\"cursor\":\"default\"})\n styledict={\"border\":\"1px solid blue\",\"height\":\"1.1em\",\"width\":f\"{widthems}em\",\"text-align\":\"center\"}\n html.DIV.__init__(self,[decrease,self.valuespan,increase],Class=\"spincontrol\",style=styledict)\n self.action=action\n if className:self.classList.add(className)\n if id:self.id=id\n \n def setValue(self,n):\n self.currentvalue=n\n self.valuespan.text=str(self.currentvalue)\n \n def ondecrease(self,event):\n if self.currentvalue -self.stepvalue >=self.minvalue:self.currentvalue -=self.stepvalue\n self.valuespan.text=str(self.currentvalue)\n if self.action:self.action(self.currentvalue)\n \n def onincrease(self,event):\n if self.currentvalue+self.stepvalue <=self.maxvalue:self.currentvalue +=self.stepvalue\n self.valuespan.text=str(self.currentvalue)\n if self.action:self.action(self.currentvalue)\n \nclass Panel(html.DIV):\n ''\n\n\n\n \n def __init__(self,items=None ,border=\"1px solid white\",align=None ,title=None ,className=None ,id=None ):\n html.DIV.__init__(self,\"\",Class=\"panel\")\n if className:self.classList.add(className)\n if id:self.id=id\n if border:self.style.border=border\n if align:self.style.textAlign=align\n if title:self <=html.P(title,Class=\"paneltitle\")\n if items:self <=items\n \nclass RowPanel(html.DIV):\n ''\n \n def __init__(self,items=None ,className=None ,id=None ):\n html.DIV.__init__(self,\"\",Class=\"rowpanel\",style={\"display\":\"flex\"})\n if items:self <=items\n if className:self.classList.add(className)\n if id:self.id=id\n \nclass ColumnPanel(html.DIV):\n ''\n \n def __init__(self,items=None ,className=None ,id=None ):\n html.DIV.__init__(self,\"\",Class=\"columnpanel\",style={\"display\":\"flex\",\"flex-direction\":\"column\"})\n if items:self <=items\n if className:self.classList.add(className)\n if id:self.id=id\n \nclass GridPanel(html.DIV):\n ''\n\n\n\n \n def __init__(self,columns,rows,items=None ,className=None ,id=None ):\n html.DIV.__init__(self,\"\",Class=\"gridpanel\",style={\"display\":\"grid\",\"justify-content\":\"center\",\"align-items\":\"center\"})\n self.style.gridTemplateColumns=\" \".join([\"auto\"]*columns)\n self.style.gridTemplateRows=\" \".join([\"auto\"]*rows)\n if items:self <=items\n if className:self.classList.add(className)\n if id:self.id=id\n \nclass Button(html.BUTTON):\n ''\n\n\n\n\n\n \n def __init__(self,text,handler,bgcolour=None ,tooltip=None ,className=None ,id=None ):\n html.BUTTON.__init__(self,text,type=\"button\",Class=\"button\")\n self.bind(\"click\",handler)\n if bgcolour:self.style.backgroundColor=bgcolour\n if tooltip:self.title=tooltip\n if className:self.classList.add(className)\n if id:self.id=id\n \nclass ImageButton(Button):\n ''\n\n\n\n\n\n \n def __init__(self,icon,handler,bgcolour=None ,tooltip=None ,className=None ,id=None ):\n Button.__init__(self,\"\",handler,bgcolour,tooltip,className,id)\n self <=html.IMG(src=icon,style={\"margin\":\"0px\"})\n self.classList.add(\"imagebutton\")\n \nclass ToggleButton(Button):\n ''\n \n def __init__(self,text,handler,bgcolour=None ,tooltip=None ,className=None ,id=None ):\n Button.__init__(self,text,self.onClick,bgcolour,tooltip,className,id)\n self.classList.add(\"togglebutton\")\n \n self.selected=False\n self.handler=handler\n \n @property\n def selected(self):\n return self._selected\n \n @selected.setter\n def selected(self,selected):\n self._selected=selected\n if self.selected:\n self.style.borderTopColor=self.style.borderLeftColor=\"grey\"\n self.style.borderBottomColor=self.style.borderRightColor=\"white\"\n else :\n self.style.borderTopColor=self.style.borderLeftColor=\"white\"\n self.style.borderBottomColor=self.style.borderRightColor=\"grey\"\n \n def onClick(self,event):\n self.selected=False if self.selected else True\n self.handler(event)\n \nclass ToggleImageButton(ToggleButton):\n ''\n \n def __init__(self,icon,handler,bgcolour=None ,tooltip=None ,className=None ,id=None ):\n ToggleButton.__init__(self,\"\",handler,bgcolour,tooltip,className,id)\n \n self <=html.IMG(src=icon)\n self.classList.add(\"toggleimagebutton\")\n \nclass RadioButton(html.SPAN):\n ''\n\n\n\n\n\n\n\n \n def __init__(self,radiogroup,radioid,label,selected=False ,tooltip=None ,action=None ,className=None ,id=None ):\n html.SPAN.__init__(self)\n if className:self.classList.add(className)\n objid=id if id else f\"{radiogroup}_{radioid}\"\n self.button=html.INPUT(type=\"radio\",name=radiogroup,value=radioid,id=objid)\n self.label=html.LABEL(label)\n self.label.attrs[\"for\"]=objid\n self <=[self.button,self.label]\n if selected:self.button.checked=True\n if tooltip:\n self.button.title=tooltip\n self.label.title=tooltip\n if action:self.button.bind(\"change\",action)\n \nclass CheckBox(html.SPAN):\n ''\n\n\n\n\n\n\n \n def __init__(self,label,objid,selected=False ,tooltip=None ,action=None ,className=None ):\n html.SPAN.__init__(self)\n self.button=html.INPUT(type=\"checkbox\",name=objid,id=objid)\n self.label=html.LABEL(label)\n self.label.attrs[\"for\"]=objid\n self <=[self.button,self.label]\n if selected:self.button.checked=True\n if tooltip:\n self.button.title=tooltip\n self.label.title=tooltip\n if action:self.button.bind(\"change\",action)\n if className:self.classList.add(className)\n \nclass ColourPickerButton(html.BUTTON):\n ''\n\n\n\n\n\n \n def __init__(self,returnaction,label=\"\",initialcolour=None ,className=None ,id=None ):\n html.BUTTON.__init__(self,label,type=\"button\",title=\"Open Colour Picker...\",Class=\"button\")\n self.classList.add(\"colourpickerbutton\")\n if className:self.classList.add(className)\n self.style.backgroundColor=initialcolour if initialcolour else \"rgb(242, 241, 240)\"\n if id:self.id=id\n self.bind(\"click\",self.onClick)\n self.returnaction=returnaction\n \n def onClick(self,event):\n global colourpickerdialog\n if not colourpickerdialog:\n colourpickerdialog=ColourPickerDialog()\n colourpickerdialog.recentcolours[0].style.backgroundColor=self.style.backgroundColor\n colourpickerdialog.recent[0]=rgbtotuple(self.style.backgroundColor)\n colourpickerdialog.returnaction=self.onChange\n colourpickerdialog.setupfromtuple(rgbtotuple(self.style.backgroundColor))\n colourpickerdialog.show()\n \n def onChange(self,colour):\n self.style.backgroundColor=colour\n self.returnaction(colour,self.id)\n \nclass ColourPickerImageButton(html.BUTTON):\n ''\n\n\n \n def __init__(self,icon,returnaction,className=None ,id=None ):\n html.BUTTON.__init__(self,html.IMG(src=icon),type=\"button\",title=\"Open Colour Picker...\",Class=\"imagebutton\")\n self.classList.add(\"colourpickerimagebutton\")\n if className:self.classList.add(className)\n self.bind(\"click\",self.onClick)\n self.returnaction=returnaction\n if id:self.id=id\n \n def onClick(self,event):\n global colourpickerdialog\n if not colourpickerdialog:colourpickerdialog=ColourPickerDialog()\n colourpickerdialog.returnaction=self.returnaction\n colourpickerdialog.show()\n \nclass ImageFromSVGButton(html.BUTTON):\n ''\n\n \n def __init__(self,svgimage,preprocess=None ,className=None ,id=None ):\n html.BUTTON.__init__(self,html.IMG(src=copy_b64),type=\"button\",title=\"Copy or Save...\",Class=\"imagebutton\")\n self.bind(\"click\",self.onClick)\n self.svgimage=svgimage\n self.preprocess=preprocess if preprocess else None\n if className:self.classList.add(className)\n if id:self.id=id\n \n def onClick(self,event):\n global imagefromsvg\n if self.preprocess:self.preprocess()\n if not imagefromsvg:imagefromsvg=ImageFromSVG()\n imagefromsvg.show()\n imagefromsvg.SVGtoPNG(self.svgimage)\n \nclass Overlay(html.DIV):\n ''\n def __init__(self,contents):\n styledict={\"position\":\"fixed\",\"top\":\"0px\",\"bottom\":\"0px\",\"left\":\"0px\",\"right\":\"0px\",\"visibility\":\"hidden\",\"background-color\":\"transparent\",\"display\":\"flex\",\"align-items\":\"center\"}\n html.DIV.__init__(self,contents,style=styledict,Class=\"overlay\")\n \nclass OverlayPanel(html.DIV):\n ''\n\n\n\n\n \n def __init__(self,title,style=None ,id=None ):\n overlaystyle={\"position\":\"absolute\",\"top\":\"0px\",\"left\":\"0px\",\"width\":\"100%\",\"height\":\"100%\"}\n titlebarstyle={\"position\":\"relative\",\"width\":\"100%\",\"height\":\"1.2em\",\"text-align\":\"center\"}\n if style:\n if style ==\"standard\":\n style={\"background-color\":\"lightgrey\",\"text-align\":\"center\",\"padding-bottom\":\"0.5em\"}\n titlebarstyle.update({\"background-color\":\"grey\",\"color\":\"white\"})\n overlaystyle.update(style)\n html.DIV.__init__(self,\"\",style=overlaystyle,Class=\"overlaypanel\")\n if id:self.id=id\n self.overlay=Overlay(self)\n closebuttonstyle={\"position\":\"absolute\",\"top\":\"0px\",\"right\":\"0px\",\"height\":\"100%\"}\n closebutton=html.IMG(src=closebutton_b64,style=closebuttonstyle,Class=\"closebutton\")\n closebutton.bind(\"click\",self.close)\n titlebar=html.DIV([title,closebutton],style=titlebarstyle,Class=\"titlebar\")\n self <=titlebar\n document <=self.overlay\n \n def show(self):\n self.overlay.style.visibility=\"visible\"\n \n def hide(self):\n self.overlay.style.visibility=\"hidden\"\n \n def close(self,event):\n self.hide()\n \nclass ImageFromSVG(OverlayPanel):\n ''\n def __init__(self):\n OverlayPanel.__init__(self,\"Right click to copy or save image\",style=\"standard\")\n self.canvas=html.CANVAS(id=\"canvascopy\")\n \n \n \n \n def drawimage(self,event):\n ctx=self.canvas.getContext(\"2d\")\n ctx.drawImage(self.svgimage,0,0)\n self.canvas.toBlob(self.copyimage)\n \n def copyimage(self,blob):\n \n \n \n \n blobURL=window.URL.createObjectURL(blob)\n self.pngimage=html.IMG(src=blobURL,id=\"pngcopy\")\n self <=self.pngimage\n \n \n \n \n \n \n \n \n def SVGtoPNG(self,SVG):\n xmls=window.XMLSerializer.new()\n svgString=xmls.serializeToString(SVG)\n self.canvas.attrs[\"width\"]=SVG.attrs[\"width\"]\n self.canvas.attrs[\"height\"]=SVG.attrs[\"height\"]\n self.svgimage=html.IMG()\n self.svgimage.bind(\"load\",self.drawimage)\n self.svgimage.attrs[\"src\"]='data:image/svg+xml; charset=utf8, '+window.encodeURIComponent(svgString);\n \n def close(self,event):\n delete(self.pngimage)\n self.hide()\n \nclass DialogBox(html.DIV):\n ''\n\n\n\n\n\n\n\n \n def __init__(self,title,returnaction=None ,content=None ,style=None ,size=None ,id=None ):\n dialogstyle={\"position\":\"relative\",\"z-index\":\"1\",\"margin\":\"auto\"}\n titlebarstyle={\"position\":\"relative\",\"width\":\"100%\",\"height\":\"1.3em\",\"text-align\":\"center\"}\n if style:\n if style ==\"standard\":\n style={\"width\":\"33%\",\"background-color\":\"lightgrey\",\"border\":\"1px solid grey\",\"text-align\":\"center\",\"padding-bottom\":\"0.5em\"}\n titlebarstyle.update({\"background-color\":\"grey\",\"color\":\"white\"})\n dialogstyle.update(style)\n if size:\n (width,height)=size\n dialogstyle[\"width\"]=width\n dialogstyle[\"height\"]=height\n html.DIV.__init__(self,\"\",style=dialogstyle,Class=\"dialogbox\")\n closebuttonstyle={\"position\":\"absolute\",\"top\":\"0px\",\"right\":\"0px\",\"height\":\"100%\"}\n self.closebutton=html.IMG(src=closebutton_b64,style=closebuttonstyle,Class=\"closebutton\",id=\"closebutton\")\n self.closebutton.bind(\"click\",self.close)\n self.titletext=html.SPAN(title)\n titlebar=html.DIV([self.titletext,self.closebutton],style=titlebarstyle,Class=\"titlebar\")\n self <=titlebar\n if content:self <=content\n self.returnaction=returnaction\n if id:self.id=id\n self.overlay=Overlay(self)\n document <=self.overlay\n \n def show(self,event=None ):\n self.overlay.style.visibility=\"visible\"\n \n def hide(self,event=None ):\n self.overlay.style.visibility=\"hidden\"\n \n def close(self,event=None ):\n self.hide()\n \nclass AlertDialog(DialogBox):\n ''\n def __init__(self):\n self.messagediv=html.DIV(style={\"background-color\":\"inherit\",\"margin\":\"1em 1em 3em 1em\"})\n super().__init__(\"Message\",content=self.messagediv,style=Global.alertStyle,id=\"alertdialog\")\n self.okbutton=Button(\"OK\",self.close)\n self.okbutton.style={\"position\":\"absolute\",\"right\":\"5px\",\"bottom\":\"5px\"}\n self <=self.okbutton\n \n def showmessage(self,message,title=None ):\n self.messagediv.innerHTML=message.replace(\"\\n\",\"<br/>\\n\")\n if title:self.titletext.innerHTML=title\n self.show()\n self.okbutton.focus()\n \nclass PromptDialog(DialogBox):\n ''\n def __init__(self):\n self.question=html.P(style={\"margin-right\":\"1em\"},id=\"query\")\n self.entrybox=html.INPUT(id=\"reply\")\n self.entrybox.bind(\"keypress\",self.onKeypress)\n self.querydiv=html.DIV([self.question,self.entrybox],style={\"background-color\":\"inherit\",\"margin-top\":\"1em\",\"margin-bottom\":\"3em\"})\n super().__init__(\"Query\",content=self.querydiv,style=Global.promptStyle,id=\"promptdialog\")\n okbutton=Button(\"OK\",self.respond)\n okbutton.style={\"position\":\"absolute\",\"right\":\"5px\",\"bottom\":\"5px\"}\n self <=okbutton\n self.closebutton.unbind(\"click\")\n self.closebutton.bind(\"click\",self.respond)\n \n def onKeypress(self,event):\n if event.keyCode ==13:self.respond(event)\n \n def showquery(self,message,action=None ,title=None ,default=None ):\n self.question.innerHTML=message\n if title:self.titletext.innerHTML=title\n if default:self.entrybox.value=default\n self.action=action\n self.show()\n self.entrybox.focus()\n \n def respond(self,event):\n if event.target.id ==\"closebutton\":\n userinput=False\n else :\n userinput=self.entrybox.value\n if not userinput:return\n super().close(event)\n if self.action:self.action(userinput)\n \nclass ColourPickerDialog(DialogBox):\n ''\n def __init__(self,returnaction=None ):\n def position(left,top,width=None ,height=None ):\n posdict={\"position\":\"absolute\",\"top\":f\"{top}px\",\"left\":f\"{left}px\"}\n if width:posdict[\"width\"]=f\"{width}px\"\n if height:posdict[\"height\"]=f\"{height}px\"\n return posdict\n DialogBox.__init__(self,\"Colour Picker\",returnaction,size=(\"380px\",\"360px\"),style=\"standard\")\n imgstyle=position(0,0)\n self.basecolourbox=html.DIV(\"\",style=position(10,30,256,256))\n self.basecolourbox <=html.IMG(src=whitemask_b64,style=imgstyle)\n self.basecolourbox <=html.IMG(src=blackmask_b64,style=imgstyle)\n self.colourpointer=html.IMG(src=circle_b64,style=imgstyle)\n self.basecolourbox <=self.colourpointer\n self.basecolourbox.bind(\"click\",self.selectcolour)\n self <=self.basecolourbox\n \n hueswatch=html.DIV(html.IMG(src=hues_b64,style=imgstyle),style=position(10,300,256,48))\n self.huepointer=html.IMG(src=circle_b64,style=imgstyle)\n hueswatch <=self.huepointer\n hueswatch.bind(\"click\",self.selecthue)\n self <=hueswatch\n \n self.hexcolourbox=InputBox(self.onhexinput)\n self.hexcolourbox.style=position(280,30,80)\n self <=self.hexcolourbox\n self.colourdemo=html.DIV(\"\",style=position(286,70,70,30))\n self <=self.colourdemo\n self <=(selectbutton :=Button(\"Select\",self.onSelect))\n selectbutton.style=position(286,110,70)\n selectbutton.style.margin=\"0px\"\n self.recentcolours=[html.DIV(\"\",id=f\"recent{i}\",style=position(280+30 *(i %3),150+30 *(i //3),25,25))for i in range(15)]\n for i in range(15):\n self.recentcolours[i].style={\"border\":\"1px solid black\",\"background-color\":\"white\"}\n self.recentcolours[i].bind(\"click\",self.onrecentchoice)\n self <=self.recentcolours\n self.recent=[(255,255,255)]*15\n self.setupfromtuple((0,255,255))\n \n def onhexinput(self,hexcolour):\n self.setupfromtuple(hextotuple(hexcolour))\n \n def onrecentchoice(self,event):\n i=int(event.target.id[6:])\n self.setupfromtuple(self.recent[i])\n \n \n def selecthue(self,event):\n hueswatch=event.currentTarget.getBoundingClientRect()\n x,y=int(event.clientX -hueswatch.left),int(event.clientY -hueswatch.top)\n (self.huepointer.left,self.huepointer.top)=(x -5,y -5)\n huenumber=x *6+y //8\n \n self.hue,self.colour=hwbtorgb(huenumber,self.whitealpha,self.blackalpha)\n self.basecolourbox.style.backgroundColor=\"rgb({},{},{})\".format(*self.hue)\n self.colourdemo.style.backgroundColor=\"rgb({},{},{})\".format(*self.colour)\n self.hexcolourbox.value=tupletohex(self.colour)\n \n def selectcolour(self,event):\n x,y=event.clientX -event.currentTarget.getBoundingClientRect().left,event.clientY -event.currentTarget.getBoundingClientRect().top\n (self.colourpointer.left,self.colourpointer.top)=(int(x)-5,int(y)-5)\n (self.whitealpha,self.blackalpha)=(x /255,y /255)\n hue,self.colour=hwbtorgb(self.hue,self.whitealpha,self.blackalpha)\n self.colourdemo.style.backgroundColor=\"rgb({},{},{})\".format(*self.colour)\n self.hexcolourbox.value=tupletohex(self.colour)\n \n def setupfromtuple(self,colour):\n self.colour=colour\n self.colourdemo.style.backgroundColor=\"rgb({},{},{})\".format(*colour)\n self.hexcolourbox.value=tupletohex(self.colour)\n \n self.hue,huenumber,self.whitealpha,self.blackalpha=rgbtohwb(colour)\n \n self.basecolourbox.style.backgroundColor=\"rgb({},{},{})\".format(*self.hue)\n (x,y)=(int(self.whitealpha *255),int(self.blackalpha *255))\n (self.colourpointer.left,self.colourpointer.top)=(x -5,y -5)\n \n (x,y)=(huenumber //6,(huenumber %6)*8)\n (self.huepointer.left,self.huepointer.top)=(x -5,y -5)\n \n def onSelect(self,event):\n if self.colour not in self.recent:self.recent=[self.colour]+self.recent[:-1]\n for i in range(15):\n self.recentcolours[i].style.backgroundColor=\"rgb({},{},{})\".format(*self.recent[i])\n self.hide()\n self.returnaction(\"rgb({}, {}, {})\".format(*self.colour))\n \nclass FileOpenButton(html.BUTTON):\n ''\n\n\n\n\n\n \n def __init__(self,returnaction,extlist=[],initialfolder=\".\",id=None ):\n global fileopendialog\n html.BUTTON.__init__(self,html.IMG(src=open_b64),type=\"button\",title=\"Open File...\",id=id,Class=\"imagebutton\")\n self.classList.add(\"fileopenbutton\")\n self.bind(\"click\",self.onClick)\n if not fileopendialog:fileopendialog=FileOpenDialog(returnaction,extlist)\n self.initialfolder=initialfolder\n if id:self.id=id\n \n def onClick(self,event):\n fileopendialog.open(self.initialfolder)\n \nclass FileSaveAsButton(html.BUTTON):\n ''\n\n\n\n\n\n\n\n \n def __init__(self,preparefile,returnaction=None ,extlist=[],defaultextension=None ,initialfolder=\".\",id=None ):\n global filesavedialog\n html.BUTTON.__init__(self,html.IMG(src=saveas_b64),type=\"button\",title=\"Save File As...\",id=id,Class=\"imagebutton\")\n self.classList.add(\"filesaveasbutton\")\n self.bind(\"click\",self.onClick)\n if not filesavedialog:filesavedialog=FileSaveDialog(returnaction,extlist,defaultextension)\n self.initialfolder=initialfolder\n self.preparefile=preparefile\n if id:self.id=id\n \n def onClick(self,event):\n filesavedialog.filetosave=self.preparefile()\n filesavedialog.open(self.initialfolder)\n \nclass FileSaveButton(html.BUTTON):\n ''\n\n \n def __init__(self,preparefile,returnaction=None ,extlist=[],defaultextension=None ,initialfolder=\".\",id=None ):\n global filesavedialog\n html.BUTTON.__init__(self,html.IMG(src=save_b64),type=\"button\",title=\"Save File\",id=id,Class=\"imagebutton\")\n self.classList.add(\"filesavebutton\")\n self.bind(\"click\",self.onClick)\n if not filesavedialog:filesavedialog=FileSaveDialog(returnaction,extlist,defaultextension)\n self.initialfolder=initialfolder\n self.preparefile=preparefile\n if id:self.id=id\n \n def onClick(self,event):\n filesavedialog.filetosave=self.preparefile()\n if filesavedialog.filename:\n filesavedialog.autosave()\n else :\n filesavedialog.open(self.initialfolder)\n \nclass UserFileOpenButton(FileOpenButton):\n ''\n \n def __init__(self,returnaction,extlist=[],id=None ):\n FileOpenButton.__init__(self,returnaction,extlist,id=id)\n self.classList.add(\"userfilebutton\")\n \n def onClick(self,event):\n if currentuser is None :\n showalert(\"In order to save or open files, you need to log in.\\nPlease click the login button.\")\n else :\n fileopendialog.open(\"./users/\"+currentuser)\n \nclass UserFileSaveAsButton(FileSaveAsButton):\n ''\n \n def __init__(self,preparefile,returnaction=None ,extlist=[],defaultextension=None ,id=None ):\n FileSaveAsButton.__init__(self,preparefile,returnaction,extlist,defaultextension,id=id)\n self.classList.add(\"userfilebutton\")\n \n def onClick(self,event):\n if currentuser is None :\n showalert(\"In order to save or open files, you need to log in.\\nPlease click the login button.\")\n else :\n filesavedialog.filetosave=self.preparefile()\n filesavedialog.open(\"./users/\"+currentuser)\n \nclass UserFileSaveButton(FileSaveButton):\n ''\n \n def __init__(self,preparefile,returnaction=None ,extlist=[],defaultextension=None ,id=None ):\n FileSaveButton.__init__(self,preparefile,returnaction,extlist,defaultextension,id=id)\n self.classList.add(\"userfilebutton\")\n \n def onClick(self,event):\n if currentuser is None :\n showalert(\"In order to save or open files, you need to log in.\\nPlease click the login button.\")\n else :\n filesavedialog.filetosave=self.preparefile()\n if filesavedialog.filename:\n filesavedialog.autosave()\n else :\n filesavedialog.open(\"./users/\"+currentuser)\n \nclass LoginButton(html.BUTTON):\n ''\n\n\n \n def __init__(self,returnaction=None ,id=None ):\n global logindialog\n html.BUTTON.__init__(self,html.IMG(src=login_b64),type=\"button\",title=\"Log In...\",Class=\"imagebutton\")\n self.classList.add(\"loginbutton\")\n self.bind(\"click\",self.onClick)\n if not logindialog:logindialog=LoginDialog(\"Please type your username below:\",returnaction)\n if id:self.id=id\n \n def onClick(self,event):\n logindialog.open()\n \nclass LoginDialog(DialogBox):\n ''\n def __init__(self,loginmessage,returnaction=None ,id=None ):\n DialogBox.__init__(self,\"Log In\",style=\"standard\",id=id)\n self.returnaction=returnaction\n self <=html.P(loginmessage)\n self.loginbox=InputBox(self.checkuserexists,id=\"loginbox\")\n self <=self.loginbox\n self <=Button(\"Log In\",self.checkuserexists)\n self <=html.HR()\n self <=html.P(\"Don't have a username?\\nClick below to create one\")\n self <=Button(\"Create username\",self.openusernamedialog)\n \n def open(self):\n self.show()\n self.loginbox.focus()\n \n def checkuserexists(self,event):\n def oncomplete(request):\n global currentuser\n response=request.text.strip()\n if response ==\"True\":\n self.hide()\n currentuser=username\n if self.returnaction:self.returnaction(username)\n else :\n showalert(\"Sorry - this username does not exist.\")\n username=self.loginbox.value\n request=ajax.ajax()\n request.bind(\"complete\",oncomplete)\n request.open(\"POST\",\"brywidgets/checkfolderexists.cgi\",True )\n \n request.send({\"username\":username})\n \n def openusernamedialog(self,event):\n global usernamedialog\n message=\"\"\"Your username should consist of letters and numbers only.<br />\n Choose something which you will remember but other people will not guess\"\"\"\n if not usernamedialog:usernamedialog=UsernameDialog(message,self.returnaction)\n self.hide()\n usernamedialog.open()\n \nclass UsernameDialog(DialogBox):\n ''\n def __init__(self,message,returnaction=None ,id=None ):\n DialogBox.__init__(self,\"Create User Name\",style=\"standard\",id=id)\n self.returnaction=returnaction\n self <=html.P(message)\n self.usernamebox=InputBox(self.checkuserexists,id=\"usernamebox\")\n self <=self.usernamebox\n self <=Button(\"Create Username\",self.checkuserexists)\n \n def open(self):\n self.show()\n self.usernamebox.focus()\n \n def checkuserexists(self,event):\n def oncomplete(request):\n response=request.text.strip()\n if response ==\"True\":\n showalert(\"Sorry - this username is already in use.\")\n else :\n self.hide()\n self.createusername(username)\n username=self.usernamebox.value\n request=ajax.ajax()\n request.bind(\"complete\",oncomplete)\n request.open(\"POST\",\"brywidgets/checkfolderexists.cgi\",True )\n \n request.send({\"username\":username})\n \n def createusername(self,username):\n def oncomplete(request):\n global currentuser\n response=request.text.strip()\n if response ==\"OK\":\n currentuser=username\n if self.returnaction:self.returnaction(username)\n showalert(\"Username created. You are now logged in.\")\n request=ajax.ajax()\n request.bind(\"complete\",oncomplete)\n request.open(\"POST\",\"brywidgets/createfolder.cgi\",True )\n \n request.send({\"username\":username})\n \nclass FileDialog(DialogBox):\n ''\n def __init__(self,title,returnaction=None ,extlist=[],id=None ):\n DialogBox.__init__(self,title,returnaction,style=\"standard\",id=id)\n self.path=None\n self.extlist=extlist\n basestyle={\"display\":\"block\",\"width\":\"90%\",\"padding\":\"0.1em\",\"margin\":\"0.1em auto\"}\n self.fileinput=html.INPUT(style=basestyle)\n liststyle={**basestyle,\"background-color\":\"white\",\"border\":\"1px solid black\",\"height\":\"70vh\",\"overflow\":\"auto\",\"white-space\":\"nowrap\"}\n self.filelistbox=html.UL(style=liststyle)\n self.buttonarea=html.DIV(style={**basestyle,\"text-align\":\"right\"})\n self <=(self.fileinput,self.filelistbox,self.buttonarea)\n \n def open(self,initialfolder=\".\"):\n if currentuser or self.path is None :self.path=[initialfolder]\n self.getfilelist(\"/\".join(self.path))\n self.show()\n self.fileinput.focus()\n \n def onitemclick(self,event):\n for item in self.filelistbox.select(\"li\"):item.style.backgroundColor=\"white\"\n event.target.style.backgroundColor=\"skyblue\"\n if event.target.className !=\"parentfolder\":\n self.fileinput.value=event.target.text\n \n def onfolderdoubleclick(self,event):\n self.path.append(event.target.text)\n self.getfilelist(\"/\".join(self.path))\n self.fileinput.value=\"\"\n \n def onfiledoubleclick(self,event):\n pass\n \n def onupdoubleclick(self,event):\n self.path.pop()\n self.getfilelist(\"/\".join(self.path))\n self.fileinput.value=\"\"\n \n def getfilelist(self,folder):\n request=ajax.ajax()\n request.bind(\"complete\",self.populatebox)\n request.open(\"POST\",\"brywidgets/sendfilelist.cgi\",True )\n \n request.send({\"folder\":folder})\n \n def populatebox(self,request):\n folderlist,filelist=request.text.strip().split(chr(30))\n self.folderlist=folderlist.split(chr(31))\n self.filelist=filelist.split(chr(31))\n if self.extlist:self.filelist=[filename for filename in self.filelist if filename.split(\".\")[-1]in self.extlist]\n \n self.filelistbox.text=\"\"\n listitemstyle={\"text-align\":\"left\",\"list-style\":\"none\",\"padding\":\"0px 0px 0px 20px\",\"margin\":\"0px\",\"cursor\":\"default\"}\n if len(self.path)>1:\n listitemstyle[\"background\"]=f\"url({uparrow_b64}) no-repeat left top\"\n self.filelistbox <=(upalevel :=html.LI(\"[Up a level]\",Class=\"parentfolder\",style=listitemstyle))\n upalevel.bind(\"dblclick\",self.onupdoubleclick)\n listitemstyle[\"background\"]=f\"url({folder_b64}) no-repeat left top\"\n for x in self.folderlist:\n self.filelistbox <=(item :=html.LI(x,style=listitemstyle))\n item.bind(\"click\",self.onitemclick)\n item.bind(\"dblclick\",self.onfolderdoubleclick)\n listitemstyle[\"background\"]=f\"url({file_b64}) no-repeat left top\"\n for x in self.filelist:\n self.filelistbox <=(item :=html.LI(x,style=listitemstyle))\n item.bind(\"click\",self.onitemclick)\n item.bind(\"dblclick\",self.onfiledoubleclick)\n \nclass FileOpenDialog(FileDialog):\n ''\n def __init__(self,returnaction=None ,extlist=[]):\n FileDialog.__init__(self,\"Open File\",returnaction,extlist,id=\"fileopendialog\")\n self.buttonarea <=Button(\"Open\",self.onopenbutton)\n \n def onfiledoubleclick(self,event):\n filename=event.target.text\n self.path.append(filename)\n filepath=\"/\".join(self.path)\n f=open(filepath).read()\n self.path.pop()\n filesavedialog.filename=filename\n filesavedialog.path=self.path\n self.hide()\n self.returnaction(f,filename)\n \n def onopenbutton(self,event):\n filename=self.fileinput.value\n if filename ==\"\":return\n self.path.append(filename)\n filepath=\"/\".join(self.path)\n if filename in self.folderlist:\n self.getfilelist(filepath)\n else :\n f=open(filepath).read()\n self.path.pop()\n filesavedialog.filename=filename\n filesavedialog.path=self.path\n self.hide()\n self.returnaction(f,filename)\n \nclass FileSaveDialog(FileDialog):\n ''\n def __init__(self,returnaction=None ,extlist=[],defaultextension=None ):\n FileDialog.__init__(self,\"Save File\",returnaction,extlist,id=\"filesavedialog\")\n self.buttonarea <=Button(\"Save\",self.onsavebutton)\n self.filename=None\n self.filetosave=None\n self.defaultextension=defaultextension\n \n def onsavebutton(self,event):\n filename=self.fileinput.value\n if filename ==\"\":\n showalert(\"No name given for the file\")\n return\n if self.defaultextension:\n ext=\".\"+self.defaultextension\n if filename[-4:]!=ext:filename +=ext\n self.path.append(filename)\n filepath=\"/\".join(self.path)\n if filename in self.folderlist:\n self.getfilelist(filepath)\n else :\n if filename in self.filelist:\n response=confirm(\"File exists. Overwrite?\")\n if response is False :\n self.path.pop()\n return\n self.savefile(filepath,self.filetosave)\n self.filename=filename\n self.path.pop()\n self.hide()\n self.returnaction(filename)\n \n def autosave(self):\n self.path.append(self.filename)\n filepath=\"/\".join(self.path)\n self.savefile(filepath,self.filetosave)\n self.path.pop()\n self.hide()\n self.returnaction(self.filename)\n \n def savefile(self,filepath,filetosave):\n request=ajax.ajax()\n \n request.open(\"POST\",\"brywidgets/savefile.cgi\",True )\n \n request.send({\"filepath\":filepath,\"filetosave\":filetosave})\n \n def closedialog(self,request):\n self.hide()\n \ndef showalert(message,title=None ):\n ''\n\n\n \n global alertdialog\n try :\n alertdialog.showmessage(message,title)\n except NameError:\n alertdialog=AlertDialog()\n alertdialog.showmessage(message,title)\n \ndef showprompt(message,action=None ,title=None ,default=None ):\n ''\n\n\n\n\n\n\n \n global promptdialog\n try :\n promptdialog.showquery(message,action,title,default)\n except NameError:\n promptdialog=PromptDialog()\n promptdialog.showquery(message,action,title,default)\n \ncolourpickerdialog=None\nfileopendialog=None\nfilesavedialog=None\nlogindialog=None\nusernamedialog=None\ncurrentuser=None\nimagefromsvg=None\n", ["browser", "browser.ajax", "browser.html", "brywidgets.images"]]}
__BRYTHON__.update_VFS(scripts)