diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 3ebcbde..cada875 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -28,9 +28,9 @@ jobs: ASSET_MIME: application/vnd.microsoft.portable-executable POETRY_FOLDER: C:\Users\runneradmin\.local steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Set up Python 3.9 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 #- name: cache poetry install @@ -38,13 +38,13 @@ jobs: # with: # path: ${{matrix.POETRY_FOLDER}} # key: poetry-1.3.3-0 - - uses: snok/install-poetry@v1.3.3 + - uses: snok/install-poetry@v1 with: virtualenvs-create: true virtualenvs-in-project: true - name: cache deps id: cache-deps - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: simulator/.venv key: pydeps-${{ hashFiles('**/poetry.lock') }} @@ -60,7 +60,7 @@ jobs: working-directory: ./simulator run: ${{matrix.POETRY_FOLDER}}/bin/poetry run ${{matrix.CMD_BUILD}} - name: Upload artifact - uses: actions/upload-artifact@v1.0.0 + uses: actions/upload-artifact@v4 with: name: ledeffect-simulator_${{matrix.TARGET}} path: simulator/dist/${{matrix.OUT_FILE_NAME}} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 8a136f6..021b554 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -23,7 +23,7 @@ jobs: - name: Output Release URL File run: echo "${{ steps.create_release.outputs.upload_url }}" > release_url.txt - name: Save Release URL File for publish - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v4 with: name: release_url path: release_url.txt @@ -50,9 +50,9 @@ jobs: ASSET_MIME: application/vnd.microsoft.portable-executable POETRY_FOLDER: C:\Users\runneradmin\.local steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Set up Python 3.9 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 #- name: cache poetry install @@ -60,13 +60,13 @@ jobs: # with: # path: ${{matrix.POETRY_FOLDER}} # key: poetry-1.3.3-0 - - uses: snok/install-poetry@v1.3.3 + - uses: snok/install-poetry@v1 with: virtualenvs-create: true virtualenvs-in-project: true - name: cache deps id: cache-deps - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: simulator/.venv key: pydeps-${{ hashFiles('**/poetry.lock') }} @@ -82,7 +82,7 @@ jobs: working-directory: ./simulator run: ${{matrix.POETRY_FOLDER}}/bin/poetry run ${{matrix.CMD_BUILD}} - name: Load Release URL File from release job - uses: actions/download-artifact@v1 + uses: actions/download-artifact@v4 with: name: release_url - name: Get Release File Name & Upload URL diff --git a/README.md b/README.md index 6d7c682..f465fed 100644 --- a/README.md +++ b/README.md @@ -18,14 +18,21 @@ And this one (in french) from Tom's Basement: [![Klipper LED EFFECTS : C'est Noël avant l'heure dans votre imprimante 3D ! (Tuto Leds)](http://i3.ytimg.com/vi/6rGjlBjFhss/hqdefault.jpg)](https://www.youtube.com/watch?v=6rGjlBjFhss) ## Disclaimer -**This is work in progress and currently in "alpha" state.** +**This is work in progress and currently in "beta" state.** +I don't take any responsibility for any damage that happens while using this software. -If you encounter any problems, feel free to open an issue. +## Support + +For questions and support use the Q&A section on the [Discussions](https://github.com/julianschill/klipper-led_effect/discussions) page. + +If you found a bug or you want to file a feature request open an [issue](https://github.com/julianschill/klipper-led_effect/issues). -If you need support or want to help by testing or contributing, please contact me on the [Klipper](https://discord.klipper3d.org/) or [Voron](https://discord.com/channels/460117602945990666/460172848565190667) Discord: Hagbard#7867 +If you need direct support or want to help by testing or contributing, please contact me on the [Klipper](https://discord.klipper3d.org/) or [Voron](https://discord.gg/voron) Discord. User: 5hagbard23 ## Installation +### Automatic installation + The module can be installed into a existing Klipper installation with an install script. cd ~ @@ -33,6 +40,53 @@ The module can be installed into a existing Klipper installation with an install cd klipper-led_effect ./install-led_effect.sh +If your directory structure differs from the usual setup you can configure the +installation script with parameters: + ./install-led_effect.sh [-k ] [-s ] [-c ] + +### Manual installation +Clone the repository: + cd ~ + git clone https://github.com/julianschill/klipper-led_effect.git + +Stop Klipper: + systemctl stop klipper + +Link the file in the Klipper directory (adjust the paths as needed): + ln -s klipper-led_effect/led_effect.py ~/klipper/extras/led_effect.py + +Start Klipper: + systemctl start klipper + +Add the updater section to moonraker.conf and restart moonraker to receive +updates: + + [update_manager led_effect] + type: git_repo + path: ~/klipper-led_effect + origin: https://github.com/julianschill/klipper-led_effect.git + is_system_service: False + +## Uninstall + +Remove all led_effect definitions in your Klipper configuration and the updater +section in the Moonraker configuration. Then run the script to remove the link: + + cd ~ + cd klipper-led_effect + ./install-led_effect.sh -u + +If your directory structure differs from the usual setup you can configure the +installation script with parameters: + ./install-led_effect.sh -u [-k ] [-s ] [-c ] + +If that fails, you can delete the link in Klipper manually: + rm ~/klipper/extras/led_effect.py + +Delete the repository (optional) + cd ~ + rm -rf klipper-led_effect + ## Configuration Documentation can be found [here](docs/LED_Effect.md). diff --git a/docs/LED_Effect.md b/docs/LED_Effect.md index 7b0dc5a..62796ef 100644 --- a/docs/LED_Effect.md +++ b/docs/LED_Effect.md @@ -30,9 +30,9 @@ the Neopixel chain back to the MCU board in addition to the GND to the power source. This will ensure the board can communicate with the strips. -The number of discrete emitters per IO pin is limited. It is possible -to wire two strips to the same data pin and have them show the same colors. -It is also possible to specify multiple LED chains on different IO pins +The number of discrete emitters per IO pin is limited. It is possible +to wire two strips to the same data pin and have them show the same colors. +It is also possible to specify multiple LED chains on different IO pins in the LED Effects configuration settings. ## Wiring APA102 compatible (Dotstar) LEDs @@ -46,10 +46,10 @@ data line. # Configuring the strips In your config file, each strip or chain connected to an IO pin must -have a definition. Each strips data pin (and clock pin if applicable) -is defined along with the number of LEDs in the chain. The LED Effect -instances are capable of using multiple strips of different types and -color orders concurrently, but each strip must first be defined by its +have a definition. Each strips data pin (and clock pin if applicable) +is defined along with the number of LEDs in the chain. The LED Effect +instances are capable of using multiple strips of different types and +color orders concurrently, but each strip must first be defined by its type. ``` @@ -108,33 +108,75 @@ layers: This has defined an effect called `panel_idle`. ### Controlling the effects -Effects can be active or inactive. Inactive effects don't output any color -data, while active effects return color data, that is summed up for each LED +Effects can be active or inactive. Inactive effects don't output any color +data, while active effects return color data, that is summed up for each LED they run on. #### Activating and deactivating effects -Our example effect can be activated by running the GCode command -`SET_LED_EFFECT EFFECT=panel_idle`. To stop all effects which are currently -running on the LEDs the new effect is using, set the `REPLACE` parameter to 1: +Our example effect can be activated by running the GCode command +`SET_LED_EFFECT EFFECT=panel_idle`. To stop all effects which are currently +running on the LEDs the new effect is using, set the `REPLACE` parameter to 1: `SET_LED_EFFECT EFFECT=panel_idle REPLACE=1` -Running the command `SET_LED_EFFECT EFFECT=panel_idle STOP=1` deactivates this -particular effect again. +Running the command `SET_LED_EFFECT EFFECT=panel_idle STOP=1` deactivates this +particular effect again. To deactivate all effects we can use the GCode command `STOP_LED_EFFECTS`. To only deactivate effects for certain LEDs we can specify the LEDS parameter: -`STOP_LED_EFFECTS LEDS="neopixel:panel_ring"` You can also specify indeces (see -below): `STOP_LED_EFFECTS LEDS="neopixel:panel_ring (1-7)"`. Only one -LED parameter can be specified at a time. To stop the effects for multiple LEDs +`STOP_LED_EFFECTS LEDS="neopixel:panel_ring"` You can also specify indeces (see +below): `STOP_LED_EFFECTS LEDS="neopixel:panel_ring (1-7)"`. Only one +LED parameter can be specified at a time. To stop the effects for multiple LEDs we have to run the command multiple times. #### Fading in and out Effects can be faded in and out by specifying the `FADETIME` parameter: -`SET_LED_EFFECT EFFECT=panel_idle FADETIME=1.0` fades the effect in during one -second. Running `SET_LED_EFFECT EFFECT=panel_idle STOP=1 FADETIME=1.0` fades it -out in one second. We can also fade out all effects by running -`STOP_LED_EFFECTS FADETIME=1.0`. It is also possible to crossfade effects by -using the `REPLACE` parameter with `SET_LED_EFFECT` (see above): +`SET_LED_EFFECT EFFECT=panel_idle FADETIME=1.0` fades the effect in during one +second. Running `SET_LED_EFFECT EFFECT=panel_idle STOP=1 FADETIME=1.0` fades it +out in one second. We can also fade out all effects by running +`STOP_LED_EFFECTS FADETIME=1.0`. It is also possible to crossfade effects by +using the `REPLACE` parameter with `SET_LED_EFFECT` (see above): `SET_LED_EFFECT EFFECT=panel_idle REPLACE=1 FADETIME=1.0` +#### Restarting Effects +When an effect is stopped and then started again, it resumes from the frame where +it last left off. To restart the effect from the beginning, specify the `RESTART` +parameter: `SET_LED_EFFECT EFFECT=panel_idle RESTART=1`. + +#### Template processing +The effect layers are processed as (templates)[https://www.klipper3d.org/Command_Templates.html#template-expansion]. +That means that they can contain the same control logic that Klipper macros do. +However, processing layers can be computationally intensive, which may affect the +performance of the Raspberry Pi host. Therefore, layers are only evaluated as +templates on effect creation (when the config is read in). + +If there is a need to evaluate the layers everytime the effect is activated, +set the `recalculate` effect-level parameter to `true`. + +Setting the `recalculate` setting to `true` will also allow the effect to accept +parameters just like `gcode_macro`. Parameters can be passed through the +`SET_LED_EFFECT` command. + +The following is an example of a layer that accepts parameters: + +``` +[led_effect param_effect] +autostart: false +recalculate: true +leds: + neopixel:leds +layers: + blink {params.DURATION|default(1)|float} {params.CYCLE|default(0.5)|float} top (1.0, 0.0, 0.0) +``` + +To activate the effect with different values for both the effect rate and cutoff, +use the following commend: + +`SET_LED_EFFECT EFFECT=param_effect DURATION=3 CYCLE=0.2` + +It is important to note that because effects are pre-evaluated when they are +first processed, each parameter that is used in the `layers` should have a +default value set. This is required because the initial evaluation of the effect +is not done in the context of a GCode command and, therefore, there is no way +to pass any parameters. + ### Additional effect level parameters autostart: true @@ -146,24 +188,36 @@ Sets the frame rate in frames per second for the effect run_on_error: (Needs patched MCU firmware. Currently not supported.) +recalculate: +Enable layer template recalculation on effect activation. + heater: Specifies the heater to use for a heater effect. Use `extruder` for the -extruder and `heater_bed` for the bed. For temperature fans or sensors add the -type and use quotes. +extruder and `heater_bed` for the bed. For temperature fans or sensors add the +type and use quotes. Example: `heater: "temperature_fan myfan"` analog_pin: Specifies the pin to use for effects using an analog signal. +Example: `analog_pin: PA1` stepper: Specifies the axis to use for the stepper effect. Possible values are: -`x`, `y` and `z`. Example: `stepper: x` +`x`, `y` and `z`. +Example: `stepper: x` endstops: Specifies the endstops the homing effect triggers on. Multiple endstops can be -specified as a comma seprated list. Possible values are: `x`, `y`, `z` and `probe`. +specified as a comma seperated list. Possible values are: `x`, `y`, `z` and `probe`. Example: `endstops: x, y` +button_pins: +Specifies the pins the button effect trigger on. Multiple pins can be specified +as a comma seperated list. Then the effect will trigger on any of the buttons. +Using already assigned pins (such as endstop pins) is possible by using +`duplicate_pin_override` (see Klipper documentation for details). +Example: `button_pins: PC1, PC2` + ## Defining LEDs The `leds:` section is a list of Neopixel or Dotstar strips that will @@ -219,10 +273,10 @@ Each layer is defined with the following parameters Each layer must be on a single line and each line must be indented. Color palettes can be of unlimited length but may be compressed depending on the size of the frame or number of LEDs on a strip. Colors are defined -as groups of Red, Green, Blue and (optional) White. The white channel only used -on RGBW LEDs and ignored on RGB LEDs. The range for each color is a decimal -number from 0.0 to 1.0. So for yellow, you would use ( 1.0, 1.0, 0.0 ). For -white you would use ( 1.0, 1.0, 1.0 ) on an RGB LED or ( 0.0, 0.0, 0.0, 1.0 ) +as groups of Red, Green, Blue and (optional) White. The white channel is only +used on RGBW LEDs and ignored on RGB LEDs. The range for each color is a decimal +number from 0.0 to 1.0. So for yellow, you would use ( 1.0, 1.0, 0.0 ). For +white you would use ( 1.0, 1.0, 1.0 ) on an RGB LED or ( 0.0, 0.0, 0.0, 1.0 ) on an RGBW LED. Individual colors must be wrapped in parentheses and separated by commas. @@ -253,7 +307,7 @@ difference in hue. Cutoff: 0 Not used but must be provided Palette: Colors are cycled in order -LEDs fade through the colors. If a palette of multiple colors is provided, it +LEDs fade through the colors. If a palette of multiple colors is provided, it will cycle through those colors in the order they are specified in the palette. The effect rate parameter controls how long it takes to go through all colors. @@ -285,7 +339,7 @@ effect rate controls how many times per second the lights will strobe. The cutof parameter controls the decay rate. A good decay rate is 1.5. #### Twinkle - Effect Rate: 1 Increases the probability that an LED will illuminate. + Effect Rate: 1 Increases the probability that an LED will illuminate. (0 = never, 254 = always) Cutoff: .25 Determines decay rate. A higher number yields quicker decay Palette: Random color chosen Random flashes of light with decay along a strip. If a palette is specified, @@ -299,8 +353,8 @@ Colors from the palette are blended into a linear gradient across the length of the strip. The effect rate parameter controls the speed at which the colors are cycled through. A negative value for the effect rate changes the direction the gradient cycles (right to left vs left to right). The Cutoff determines the -length of the gradient in relation to the chain length. The bigger the value, -the shorter the gradient (e.g. the value 2 means 2 gradients on the length of +length of the gradient in relation to the chain length. The bigger the value, +the shorter the gradient (e.g. the value 2 means 2 gradients on the length of the chain) #### Pattern @@ -308,7 +362,7 @@ the chain) Cutoff: 1 How far the pattern gets shifted Palette: The pattern to be shifted The palette is applied as a recurring pattern on the chain and shifted along the -chain. The effect rate determines the time between the shifts in seconds, the +chain. The effect rate determines the time between the shifts in seconds, the cutoff determines the amount of LED positions the pattern gets shifted. #### Comet @@ -344,11 +398,31 @@ indicate the hotend or bed is in a safe state to touch. #### Temperature Effect Rate: 20 Cold Temperature Cutoff: 80 Hot Temperature - Palette: Color values to blend from Cold to Hot + Palette: Color values to blend from "Cold" to "Hot" The temperature of the configured heater determines the color in a gradient over the palette. When only one color is defined in the palette, the brightness of that color is defined by the temperature. +#### HeaterGauge + Effect Rate: 50 Number of trailing LEDs + Cutoff: 0 Number of leading LEDs + Palette: Color values to blend from "Cold" to "Hot" +The temperature of the heater relative from 0 to its target is represented by +the first color in the palette. The remaining colors in the gradient are blended +and mirrored on either side. As the heater heats up to it's target temperature, +the lights move up the strip. A negative value in effect rate will fill the +entire strip leading up to the temperature position, a negative value in cutoff +will fill the entire strip after the temperature position. + +#### TemperatureGauge + Effect Rate: 20 Cold Temperature + Cutoff: 80 Hot Temperature + Palette: Color values to blend +The temperature of the heater or temperature sensor relative from the cold +temperature to the hot temperature its target is represented by the first color +in the palette. The remaining colors form a gradient on the lower side of the +strip. + #### Fire Effect Rate: 45 Probability of "sparking" Cutoff: 40 Rate of "cooling" @@ -400,9 +474,9 @@ position, a negative value in cutoff will fill the entire strip after the steppe Effect Rate: 1 Scaling of position Cutoff: 0 Offset of position Palette: Color values to blend -The color of the LEDs are determined by the position of the stepper motor. The +The color of the LEDs are determined by the position of the stepper motor. The position is determined between 0 and 100 and is multiplied with the effect rate -and the cutoff is added as offset. This then determines the value in the +and the cutoff is added as offset. This then determines the value in the palette, that is calculated as a gradient over the specified color values. #### Progress @@ -417,9 +491,37 @@ layer reports print progress. Cutoff: 0 Not used, but must be provided Palette: Colors are cycled in order -LEDs turn on during homing when the endstop is triggered and fade out again. The -effect rate determines the time for the fade out. If a palette of multiple colors -is provided, it will cycle through those colors in order. +Needs an endstop defined. LEDs turn on during homing when the endstop is +triggered and fade out again. The effect rate determines the time for the fade +out. If a palette of multiple colors is provided, it will cycle through those +colors in order. + +#### SwitchButton + Effect Rate: 1 Fade in time. Time until LEDs are on after button press + Cutoff: 1 Fade out time. Time until LEDs are off after button release + Palette: Colors are cycled in order + +Needs a button_pin defined. LEDs turn on when the button is pressed and turn off +when the button is released again. Each press cycles through the colors of the +palette. + +#### ToggleButton + Effect Rate: 1 Fade in time. Time to fade in next color + Cutoff: 1 Fade out time. Time to fade out previous color + Palette: Colors are cycled in order + +Needs a button_pin defined. Cycles through the colors with each button press. +The transition times can be configured with the effect rate and cutoff parameters. +Hint: Define (0,0,0) as a color if you want to toggle between on and off. + +#### FlashButton + Effect Rate: 0.1 Fade in time. Time to fade in. + Cutoff: 1 Fade out time. Time to fade out. + Palette: Colors are cycled in order + +Needs a button_pin defined. When the button is pressed the LEDs fade on in the +defined time and fade off immediately afterwards. If a palette of multiple colors +is provided, it will cycle through those colors in order with each button press. ## Effect Layer Blending If you have ever used image editing software you may be familiar with @@ -624,7 +726,7 @@ data signal at 3.3V. Signal integrity can also be deteriorated by ringing and reflections on the data line. Especially, when the cable to the first LED is rather long. -This can be reduced by adding a 700 Ohm resistor in line to the data line +This can be reduced by adding a 700 Ohm resistor in line to the data line directly in front of the first LED. Another source of flickering is voltage drop. Addressable LEDs consume @@ -648,7 +750,7 @@ to power LEDs like this from a separate 5V source from the board. Different chip manufacturers and chip styles use slightly different protocols for color data. Some specify the color order be Red, Green, then Blue others specify Green, Red, Blue. The configuration for the -LED strip has an optional parameter that can be set in the 'neopixel' +LED strip has an optional parameter that can be set in the 'neopixel' section to change the color order. `` diff --git a/examples/Voron_Stealthburner/stealthburner_led_effects_barf.cfg b/examples/Voron_Stealthburner/stealthburner_led_effects_barf.cfg index 3ecbf46..9dac1ba 100644 --- a/examples/Voron_Stealthburner/stealthburner_led_effects_barf.cfg +++ b/examples/Voron_Stealthburner/stealthburner_led_effects_barf.cfg @@ -50,9 +50,9 @@ # likely have to use WLED with Moonraker and a small micro-controller (please see the LED thread for help inside # of the stealthburner_beta channel on Discord). # -##################################### -# END INSTRUCTRUCTIONS # -##################################### +################################# +# END INSTRUCTIONS # +################################# [neopixel sb_leds] @@ -342,4 +342,4 @@ gcode: gcode: STOP_LED_EFFECTS SET_LED_EFFECT EFFECT=sb_logo_printing - set_nozzle_leds_on \ No newline at end of file + set_nozzle_leds_on diff --git a/install-led_effect.sh b/install-led_effect.sh index 83b302a..99ba53d 100755 --- a/install-led_effect.sh +++ b/install-led_effect.sh @@ -3,6 +3,7 @@ set -e KLIPPER_PATH="${HOME}/klipper" +KLIPPER_SERVICE_NAME=klipper SYSTEMDDIR="/etc/systemd/system" MOONRAKER_CONFIG_DIR="${HOME}/printer_data/config" @@ -12,11 +13,12 @@ if [ ! -d "${MOONRAKER_CONFIG_DIR}" ]; then MOONRAKER_CONFIG_DIR="${HOME}/klipper_config" fi -usage(){ echo "Usage: $0 [-k ] [-c ]" 1>&2; exit 1; } +usage(){ echo "Usage: $0 [-k ] [-s ] [-c ] [-u]" 1>&2; exit 1; } # Parse command line arguments -while getopts "k:c:uh" arg; do +while getopts "k:s:c:uh" arg; do case $arg in k) KLIPPER_PATH=$OPTARG;; + s) KLIPPER_SERVICE_NAME=$OPTARG;; c) MOONRAKER_CONFIG_DIR=$OPTARG;; u) UNINSTALL=1;; h) usage;; @@ -29,10 +31,10 @@ SRCDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/src/ && pwd )" # Verify Klipper has been installed check_klipper() { - if [ "$(sudo systemctl list-units --full -all -t service --no-legend | grep -F "klipper.service")" ]; then - echo "Klipper service found." + if [ "$(sudo systemctl list-units --full -all -t service --no-legend | grep -F "$KLIPPER_SERVICE_NAME.service")" ]; then + echo "Klipper service found with name "$KLIPPER_SERVICE_NAME"." else - echo "[ERROR] Klipper service not found, please install Klipper first" + echo "[ERROR] Klipper service with name "$KLIPPER_SERVICE_NAME" not found, please install Klipper first or specify name with -s." exit -1 fi } @@ -90,21 +92,21 @@ add_updater() restart_klipper() { echo -n "Restarting Klipper... " - sudo systemctl restart klipper + sudo systemctl restart $KLIPPER_SERVICE_NAME echo "[OK]" } start_klipper() { echo -n "Starting Klipper... " - sudo systemctl start klipper + sudo systemctl start $KLIPPER_SERVICE_NAME echo "[OK]" } stop_klipper() { echo -n "Stopping Klipper... " - sudo systemctl start klipper + sudo systemctl stop $KLIPPER_SERVICE_NAME echo "[OK]" } diff --git a/simulator/poetry.lock b/simulator/poetry.lock index 0b31c6a..0e1b7db 100644 --- a/simulator/poetry.lock +++ b/simulator/poetry.lock @@ -1,22 +1,20 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "altgraph" -version = "0.17.3" +version = "0.17.4" description = "Python graph (network) package" -category = "main" optional = false python-versions = "*" files = [ - {file = "altgraph-0.17.3-py2.py3-none-any.whl", hash = "sha256:c8ac1ca6772207179ed8003ce7687757c04b0b71536f81e2ac5755c6226458fe"}, - {file = "altgraph-0.17.3.tar.gz", hash = "sha256:ad33358114df7c9416cdb8fa1eaa5852166c505118717021c6a8c7c7abbd03dd"}, + {file = "altgraph-0.17.4-py2.py3-none-any.whl", hash = "sha256:642743b4750de17e655e6711601b077bc6598dbfa3ba5fa2b2a35ce12b508dff"}, + {file = "altgraph-0.17.4.tar.gz", hash = "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406"}, ] [[package]] name = "black" version = "22.12.0" description = "The uncompromising code formatter." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -50,14 +48,13 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "click" -version = "8.1.3" +version = "8.1.7" description = "Composable command line interface toolkit" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, ] [package.dependencies] @@ -67,7 +64,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -76,26 +72,33 @@ files = [ ] [[package]] -name = "future" -version = "0.18.2" -description = "Clean single-source support for Python 3 and 2" -category = "main" +name = "importlib-metadata" +version = "7.0.1" +description = "Read metadata from Python packages" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = ">=3.8" files = [ - {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, + {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, + {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, ] +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] + [[package]] name = "macholib" -version = "1.16.2" +version = "1.16.3" description = "Mach-O header analysis and editing" -category = "main" optional = false python-versions = "*" files = [ - {file = "macholib-1.16.2-py2.py3-none-any.whl", hash = "sha256:44c40f2cd7d6726af8fa6fe22549178d3a4dfecc35a9cd15ea916d9c83a688e0"}, - {file = "macholib-1.16.2.tar.gz", hash = "sha256:557bbfa1bb255c20e9abafe7ed6cd8046b48d9525db2f9b77d3122a63a2a8bf8"}, + {file = "macholib-1.16.3-py2.py3-none-any.whl", hash = "sha256:0e315d7583d38b8c77e815b1ecbdbf504a8258d8b3e17b61165c6feb60d18f2c"}, + {file = "macholib-1.16.3.tar.gz", hash = "sha256:07ae9e15e8e4cd9a788013d81f5908b3609aa76f9b1421bae9c4d7606ec86a30"}, ] [package.dependencies] @@ -103,251 +106,267 @@ altgraph = ">=0.17" [[package]] name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." -category = "dev" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." optional = false -python-versions = "*" +python-versions = ">=3.5" files = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] [[package]] name = "numpy" -version = "1.24.1" +version = "1.24.4" description = "Fundamental package for array computing in Python" -category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "numpy-1.24.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:179a7ef0889ab769cc03573b6217f54c8bd8e16cef80aad369e1e8185f994cd7"}, - {file = "numpy-1.24.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b09804ff570b907da323b3d762e74432fb07955701b17b08ff1b5ebaa8cfe6a9"}, - {file = "numpy-1.24.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1b739841821968798947d3afcefd386fa56da0caf97722a5de53e07c4ccedc7"}, - {file = "numpy-1.24.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e3463e6ac25313462e04aea3fb8a0a30fb906d5d300f58b3bc2c23da6a15398"}, - {file = "numpy-1.24.1-cp310-cp310-win32.whl", hash = "sha256:b31da69ed0c18be8b77bfce48d234e55d040793cebb25398e2a7d84199fbc7e2"}, - {file = "numpy-1.24.1-cp310-cp310-win_amd64.whl", hash = "sha256:b07b40f5fb4fa034120a5796288f24c1fe0e0580bbfff99897ba6267af42def2"}, - {file = "numpy-1.24.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7094891dcf79ccc6bc2a1f30428fa5edb1e6fb955411ffff3401fb4ea93780a8"}, - {file = "numpy-1.24.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e418681372520c992805bb723e29d69d6b7aa411065f48216d8329d02ba032"}, - {file = "numpy-1.24.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e274f0f6c7efd0d577744f52032fdd24344f11c5ae668fe8d01aac0422611df1"}, - {file = "numpy-1.24.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0044f7d944ee882400890f9ae955220d29b33d809a038923d88e4e01d652acd9"}, - {file = "numpy-1.24.1-cp311-cp311-win32.whl", hash = "sha256:442feb5e5bada8408e8fcd43f3360b78683ff12a4444670a7d9e9824c1817d36"}, - {file = "numpy-1.24.1-cp311-cp311-win_amd64.whl", hash = "sha256:de92efa737875329b052982e37bd4371d52cabf469f83e7b8be9bb7752d67e51"}, - {file = "numpy-1.24.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b162ac10ca38850510caf8ea33f89edcb7b0bb0dfa5592d59909419986b72407"}, - {file = "numpy-1.24.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26089487086f2648944f17adaa1a97ca6aee57f513ba5f1c0b7ebdabbe2b9954"}, - {file = "numpy-1.24.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:caf65a396c0d1f9809596be2e444e3bd4190d86d5c1ce21f5fc4be60a3bc5b36"}, - {file = "numpy-1.24.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0677a52f5d896e84414761531947c7a330d1adc07c3a4372262f25d84af7bf7"}, - {file = "numpy-1.24.1-cp38-cp38-win32.whl", hash = "sha256:dae46bed2cb79a58d6496ff6d8da1e3b95ba09afeca2e277628171ca99b99db1"}, - {file = "numpy-1.24.1-cp38-cp38-win_amd64.whl", hash = "sha256:6ec0c021cd9fe732e5bab6401adea5a409214ca5592cd92a114f7067febcba0c"}, - {file = "numpy-1.24.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:28bc9750ae1f75264ee0f10561709b1462d450a4808cd97c013046073ae64ab6"}, - {file = "numpy-1.24.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84e789a085aabef2f36c0515f45e459f02f570c4b4c4c108ac1179c34d475ed7"}, - {file = "numpy-1.24.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e669fbdcdd1e945691079c2cae335f3e3a56554e06bbd45d7609a6cf568c700"}, - {file = "numpy-1.24.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef85cf1f693c88c1fd229ccd1055570cb41cdf4875873b7728b6301f12cd05bf"}, - {file = "numpy-1.24.1-cp39-cp39-win32.whl", hash = "sha256:87a118968fba001b248aac90e502c0b13606721b1343cdaddbc6e552e8dfb56f"}, - {file = "numpy-1.24.1-cp39-cp39-win_amd64.whl", hash = "sha256:ddc7ab52b322eb1e40521eb422c4e0a20716c271a306860979d450decbb51b8e"}, - {file = "numpy-1.24.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed5fb71d79e771ec930566fae9c02626b939e37271ec285e9efaf1b5d4370e7d"}, - {file = "numpy-1.24.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad2925567f43643f51255220424c23d204024ed428afc5aad0f86f3ffc080086"}, - {file = "numpy-1.24.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cfa1161c6ac8f92dea03d625c2d0c05e084668f4a06568b77a25a89111621566"}, - {file = "numpy-1.24.1.tar.gz", hash = "sha256:2386da9a471cc00a1f47845e27d916d5ec5346ae9696e01a8a34760858fe9dd2"}, + {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"}, + {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"}, + {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"}, + {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"}, + {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"}, + {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"}, + {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"}, + {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"}, + {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"}, + {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"}, + {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, +] + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] [[package]] name = "pathspec" -version = "0.10.3" +version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pathspec-0.10.3-py3-none-any.whl", hash = "sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6"}, - {file = "pathspec-0.10.3.tar.gz", hash = "sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6"}, + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] [[package]] name = "pefile" -version = "2022.5.30" +version = "2023.2.7" description = "Python PE parsing module" -category = "main" optional = false python-versions = ">=3.6.0" files = [ - {file = "pefile-2022.5.30.tar.gz", hash = "sha256:a5488a3dd1fd021ce33f969780b88fe0f7eebb76eb20996d7318f307612a045b"}, + {file = "pefile-2023.2.7-py3-none-any.whl", hash = "sha256:da185cd2af68c08a6cd4481f7325ed600a88f6a813bad9dea07ab3ef73d8d8d6"}, + {file = "pefile-2023.2.7.tar.gz", hash = "sha256:82e6114004b3d6911c77c3953e3838654b04511b8b66e8583db70c65998017dc"}, ] -[package.dependencies] -future = "*" - [[package]] name = "pillow" -version = "9.3.0" +version = "10.2.0" description = "Python Imaging Library (Fork)" -category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Pillow-9.3.0-1-cp37-cp37m-win32.whl", hash = "sha256:e6ea6b856a74d560d9326c0f5895ef8050126acfdc7ca08ad703eb0081e82b74"}, - {file = "Pillow-9.3.0-1-cp37-cp37m-win_amd64.whl", hash = "sha256:32a44128c4bdca7f31de5be641187367fe2a450ad83b833ef78910397db491aa"}, - {file = "Pillow-9.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:0b7257127d646ff8676ec8a15520013a698d1fdc48bc2a79ba4e53df792526f2"}, - {file = "Pillow-9.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b90f7616ea170e92820775ed47e136208e04c967271c9ef615b6fbd08d9af0e3"}, - {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68943d632f1f9e3dce98908e873b3a090f6cba1cbb1b892a9e8d97c938871fbe"}, - {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be55f8457cd1eac957af0c3f5ece7bc3f033f89b114ef30f710882717670b2a8"}, - {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d77adcd56a42d00cc1be30843d3426aa4e660cab4a61021dc84467123f7a00c"}, - {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:829f97c8e258593b9daa80638aee3789b7df9da5cf1336035016d76f03b8860c"}, - {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:801ec82e4188e935c7f5e22e006d01611d6b41661bba9fe45b60e7ac1a8f84de"}, - {file = "Pillow-9.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:871b72c3643e516db4ecf20efe735deb27fe30ca17800e661d769faab45a18d7"}, - {file = "Pillow-9.3.0-cp310-cp310-win32.whl", hash = "sha256:655a83b0058ba47c7c52e4e2df5ecf484c1b0b0349805896dd350cbc416bdd91"}, - {file = "Pillow-9.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:9f47eabcd2ded7698106b05c2c338672d16a6f2a485e74481f524e2a23c2794b"}, - {file = "Pillow-9.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:57751894f6618fd4308ed8e0c36c333e2f5469744c34729a27532b3db106ee20"}, - {file = "Pillow-9.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7db8b751ad307d7cf238f02101e8e36a128a6cb199326e867d1398067381bff4"}, - {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3033fbe1feb1b59394615a1cafaee85e49d01b51d54de0cbf6aa8e64182518a1"}, - {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22b012ea2d065fd163ca096f4e37e47cd8b59cf4b0fd47bfca6abb93df70b34c"}, - {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a65733d103311331875c1dca05cb4606997fd33d6acfed695b1232ba1df193"}, - {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:502526a2cbfa431d9fc2a079bdd9061a2397b842bb6bc4239bb176da00993812"}, - {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:90fb88843d3902fe7c9586d439d1e8c05258f41da473952aa8b328d8b907498c"}, - {file = "Pillow-9.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:89dca0ce00a2b49024df6325925555d406b14aa3efc2f752dbb5940c52c56b11"}, - {file = "Pillow-9.3.0-cp311-cp311-win32.whl", hash = "sha256:3168434d303babf495d4ba58fc22d6604f6e2afb97adc6a423e917dab828939c"}, - {file = "Pillow-9.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:18498994b29e1cf86d505edcb7edbe814d133d2232d256db8c7a8ceb34d18cef"}, - {file = "Pillow-9.3.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:772a91fc0e03eaf922c63badeca75e91baa80fe2f5f87bdaed4280662aad25c9"}, - {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa4107d1b306cdf8953edde0534562607fe8811b6c4d9a486298ad31de733b2"}, - {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4012d06c846dc2b80651b120e2cdd787b013deb39c09f407727ba90015c684f"}, - {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77ec3e7be99629898c9a6d24a09de089fa5356ee408cdffffe62d67bb75fdd72"}, - {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:6c738585d7a9961d8c2821a1eb3dcb978d14e238be3d70f0a706f7fa9316946b"}, - {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:828989c45c245518065a110434246c44a56a8b2b2f6347d1409c787e6e4651ee"}, - {file = "Pillow-9.3.0-cp37-cp37m-win32.whl", hash = "sha256:82409ffe29d70fd733ff3c1025a602abb3e67405d41b9403b00b01debc4c9a29"}, - {file = "Pillow-9.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:41e0051336807468be450d52b8edd12ac60bebaa97fe10c8b660f116e50b30e4"}, - {file = "Pillow-9.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:b03ae6f1a1878233ac620c98f3459f79fd77c7e3c2b20d460284e1fb370557d4"}, - {file = "Pillow-9.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4390e9ce199fc1951fcfa65795f239a8a4944117b5935a9317fb320e7767b40f"}, - {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40e1ce476a7804b0fb74bcfa80b0a2206ea6a882938eaba917f7a0f004b42502"}, - {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0a06a052c5f37b4ed81c613a455a81f9a3a69429b4fd7bb913c3fa98abefc20"}, - {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03150abd92771742d4a8cd6f2fa6246d847dcd2e332a18d0c15cc75bf6703040"}, - {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:15c42fb9dea42465dfd902fb0ecf584b8848ceb28b41ee2b58f866411be33f07"}, - {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:51e0e543a33ed92db9f5ef69a0356e0b1a7a6b6a71b80df99f1d181ae5875636"}, - {file = "Pillow-9.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3dd6caf940756101205dffc5367babf288a30043d35f80936f9bfb37f8355b32"}, - {file = "Pillow-9.3.0-cp38-cp38-win32.whl", hash = "sha256:f1ff2ee69f10f13a9596480335f406dd1f70c3650349e2be67ca3139280cade0"}, - {file = "Pillow-9.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:276a5ca930c913f714e372b2591a22c4bd3b81a418c0f6635ba832daec1cbcfc"}, - {file = "Pillow-9.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:73bd195e43f3fadecfc50c682f5055ec32ee2c933243cafbfdec69ab1aa87cad"}, - {file = "Pillow-9.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c7c8ae3864846fc95f4611c78129301e203aaa2af813b703c55d10cc1628535"}, - {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e0918e03aa0c72ea56edbb00d4d664294815aa11291a11504a377ea018330d3"}, - {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0915e734b33a474d76c28e07292f196cdf2a590a0d25bcc06e64e545f2d146c"}, - {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af0372acb5d3598f36ec0914deed2a63f6bcdb7b606da04dc19a88d31bf0c05b"}, - {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:ad58d27a5b0262c0c19b47d54c5802db9b34d38bbf886665b626aff83c74bacd"}, - {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:97aabc5c50312afa5e0a2b07c17d4ac5e865b250986f8afe2b02d772567a380c"}, - {file = "Pillow-9.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9aaa107275d8527e9d6e7670b64aabaaa36e5b6bd71a1015ddd21da0d4e06448"}, - {file = "Pillow-9.3.0-cp39-cp39-win32.whl", hash = "sha256:bac18ab8d2d1e6b4ce25e3424f709aceef668347db8637c2296bcf41acb7cf48"}, - {file = "Pillow-9.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:b472b5ea442148d1c3e2209f20f1e0bb0eb556538690fa70b5e1f79fa0ba8dc2"}, - {file = "Pillow-9.3.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ab388aaa3f6ce52ac1cb8e122c4bd46657c15905904b3120a6248b5b8b0bc228"}, - {file = "Pillow-9.3.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbb8e7f2abee51cef77673be97760abff1674ed32847ce04b4af90f610144c7b"}, - {file = "Pillow-9.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca31dd6014cb8b0b2db1e46081b0ca7d936f856da3b39744aef499db5d84d02"}, - {file = "Pillow-9.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c7025dce65566eb6e89f56c9509d4f628fddcedb131d9465cacd3d8bac337e7e"}, - {file = "Pillow-9.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ebf2029c1f464c59b8bdbe5143c79fa2045a581ac53679733d3a91d400ff9efb"}, - {file = "Pillow-9.3.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b59430236b8e58840a0dfb4099a0e8717ffb779c952426a69ae435ca1f57210c"}, - {file = "Pillow-9.3.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12ce4932caf2ddf3e41d17fc9c02d67126935a44b86df6a206cf0d7161548627"}, - {file = "Pillow-9.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae5331c23ce118c53b172fa64a4c037eb83c9165aba3a7ba9ddd3ec9fa64a699"}, - {file = "Pillow-9.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:0b07fffc13f474264c336298d1b4ce01d9c5a011415b79d4ee5527bb69ae6f65"}, - {file = "Pillow-9.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:073adb2ae23431d3b9bcbcff3fe698b62ed47211d0716b067385538a1b0f28b8"}, - {file = "Pillow-9.3.0.tar.gz", hash = "sha256:c935a22a557a560108d780f9a0fc426dd7459940dc54faa49d83249c8d3e760f"}, + {file = "pillow-10.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e"}, + {file = "pillow-10.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0"}, + {file = "pillow-10.2.0-cp310-cp310-win32.whl", hash = "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023"}, + {file = "pillow-10.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72"}, + {file = "pillow-10.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757"}, + {file = "pillow-10.2.0-cp311-cp311-win32.whl", hash = "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068"}, + {file = "pillow-10.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56"}, + {file = "pillow-10.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1"}, + {file = "pillow-10.2.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef"}, + {file = "pillow-10.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04"}, + {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f"}, + {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb"}, + {file = "pillow-10.2.0-cp312-cp312-win32.whl", hash = "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f"}, + {file = "pillow-10.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9"}, + {file = "pillow-10.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48"}, + {file = "pillow-10.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9"}, + {file = "pillow-10.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d"}, + {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6"}, + {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe"}, + {file = "pillow-10.2.0-cp38-cp38-win32.whl", hash = "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e"}, + {file = "pillow-10.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591"}, + {file = "pillow-10.2.0-cp39-cp39-win32.whl", hash = "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516"}, + {file = "pillow-10.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8"}, + {file = "pillow-10.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6"}, + {file = "pillow-10.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868"}, + {file = "pillow-10.2.0.tar.gz", hash = "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +typing = ["typing-extensions"] +xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "2.6.0" +version = "4.2.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "platformdirs-2.6.0-py3-none-any.whl", hash = "sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca"}, - {file = "platformdirs-2.6.0.tar.gz", hash = "sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e"}, + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, ] [package.extras] -docs = ["furo (>=2022.9.29)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.4)"] -test = ["appdirs (==1.4.4)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] [[package]] name = "pyinstaller" -version = "5.7.0" +version = "6.4.0" description = "PyInstaller bundles a Python application and all its dependencies into a single package." -category = "main" optional = false -python-versions = "<3.12,>=3.7" +python-versions = "<3.13,>=3.8" files = [ - {file = "pyinstaller-5.7.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:b967ae71ab7b05e18608dbb4518da5afa54f0835927cb7a5ce52ab8fffed03b6"}, - {file = "pyinstaller-5.7.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:3180b9bf22263380adc5e2ee051b7c21463292877215bbe70c9155dc76f4b966"}, - {file = "pyinstaller-5.7.0-py3-none-manylinux2014_i686.whl", hash = "sha256:0f80e2403e76630ad3392c71f09c1a4284e8d8a8a99fb55ff3a0aba0e06300ed"}, - {file = "pyinstaller-5.7.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:2c1dd9d11cfc48bab61eeb06de69a3d1ad742bbb2ef14716965ca0333dd43a5b"}, - {file = "pyinstaller-5.7.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:dfc12e92fe10ae645dd0dd1fcfa4cd7677b2e96119e3cd4980d742e09bb78925"}, - {file = "pyinstaller-5.7.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f35f06d48faea0ad738429c009941059beebaa306e9d9ead95f1df4b441de2aa"}, - {file = "pyinstaller-5.7.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:28a8a0da656493aa32d9665e2f6f84775da0f23174859ed8facaa4226fe77a17"}, - {file = "pyinstaller-5.7.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:1ac3f09b838710c43e34b0a7ad003bd168a754b0b786c561b47baf1af9104354"}, - {file = "pyinstaller-5.7.0-py3-none-win32.whl", hash = "sha256:9cdb8ee8622ee8d2c6cd67f001b610019d4371a8bf3f7850562640ce786894d7"}, - {file = "pyinstaller-5.7.0-py3-none-win_amd64.whl", hash = "sha256:9b47c10fbefac6f6493266f8b1689109b2b14efa9142dbd2cd7549226a4568b7"}, - {file = "pyinstaller-5.7.0-py3-none-win_arm64.whl", hash = "sha256:3e51e18a16dec0414079762843cf892a5d70749ad56ca7b3c7b5f8367dc50b1e"}, - {file = "pyinstaller-5.7.0.tar.gz", hash = "sha256:0e5953937d35f0b37543cc6915dacaf3239bcbdf3fd3ecbb7866645468a16775"}, + {file = "pyinstaller-6.4.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:a2e63fa71784f290bbf79b31b60a27c45b17a18b8c7f910757f9474e0c12c95d"}, + {file = "pyinstaller-6.4.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:3127724d1841f785a9916d7b4cfd9595f359925e9ce7d137a16db8c29ca8453b"}, + {file = "pyinstaller-6.4.0-py3-none-manylinux2014_i686.whl", hash = "sha256:a37f83850cb150ad1e00fe92acecc4d39b8e10162a1850a5836a05fcb2daa870"}, + {file = "pyinstaller-6.4.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:28b98fa3c74602bdc4c5a7698e907f31e714cc40a13f6358082bcbc74ddab35c"}, + {file = "pyinstaller-6.4.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:3ae62cf8858ec4dc54df6fa03d29bc78297e3c87caf532887eae8c3893be0789"}, + {file = "pyinstaller-6.4.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e3e1e6922a4260dcacf6f5655b0ca857451e05ac502d01642935d0f2873ad3c7"}, + {file = "pyinstaller-6.4.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:78fb66ca753ef8becdf059eaa1e764d384cacb8c2ec76800126f8c9ef6d19a50"}, + {file = "pyinstaller-6.4.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:e07cff584600647af7dc279dd04c60cd1b4b1b41947b0753f8fcf1969300a583"}, + {file = "pyinstaller-6.4.0-py3-none-win32.whl", hash = "sha256:c7bc0fbea8a9010484cfa7d3856416003af73271f03ca3da4bc0eaf14680ad17"}, + {file = "pyinstaller-6.4.0-py3-none-win_amd64.whl", hash = "sha256:ec8a08c983e3febb0247893cd9bd59f55b6767a1f649cb41a0a129b8f04ff2cb"}, + {file = "pyinstaller-6.4.0-py3-none-win_arm64.whl", hash = "sha256:11e6da6a6e441379352ee460a8880f2633dac91dac0f5a9eeff5d449d459b046"}, + {file = "pyinstaller-6.4.0.tar.gz", hash = "sha256:1bf608ed947b58614711275a7ff169289b32560dc97ec748ebd5fa8bdec80649"}, ] [package.dependencies] altgraph = "*" +importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""} macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""} +packaging = ">=22.0" pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""} -pyinstaller-hooks-contrib = ">=2021.4" -pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} +pyinstaller-hooks-contrib = ">=2024.0" +pywin32-ctypes = {version = ">=0.2.1", markers = "sys_platform == \"win32\""} setuptools = ">=42.0.0" [package.extras] -encryption = ["tinyaes (>=1.0.0)"] +completion = ["argcomplete"] hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"] [[package]] name = "pyinstaller-hooks-contrib" -version = "2022.14" +version = "2024.1" description = "Community maintained hooks for PyInstaller" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pyinstaller-hooks-contrib-2022.14.tar.gz", hash = "sha256:5ae8da3a92cf20e37b3e00604d0c3468896e7d746e5c1449473597a724331b0b"}, - {file = "pyinstaller_hooks_contrib-2022.14-py2.py3-none-any.whl", hash = "sha256:1a125838a22d7b35a18993c6e56d3c5cc3ad7da00954f95bc5606523939203f2"}, + {file = "pyinstaller-hooks-contrib-2024.1.tar.gz", hash = "sha256:51a51ea9e1ae6bd5ffa7ec45eba7579624bf4f2472ff56dba0edc186f6ed46a6"}, + {file = "pyinstaller_hooks_contrib-2024.1-py2.py3-none-any.whl", hash = "sha256:131494f9cfce190aaa66ed82e82c78b2723d1720ce64d012fbaf938f4ab01d35"}, ] +[package.dependencies] +importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""} +packaging = ">=22.0" +setuptools = ">=42.0.0" + [[package]] name = "pywin32-ctypes" -version = "0.2.0" -description = "" -category = "main" +version = "0.2.2" +description = "A (partial) reimplementation of pywin32 using ctypes/cffi" optional = false -python-versions = "*" +python-versions = ">=3.6" files = [ - {file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"}, - {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"}, + {file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"}, + {file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"}, ] [[package]] name = "setuptools" -version = "65.6.3" +version = "69.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"}, - {file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"}, + {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, + {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -359,7 +378,6 @@ files = [ name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -369,40 +387,61 @@ files = [ [[package]] name = "typing-extensions" -version = "4.4.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "dev" +version = "4.9.0" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, - {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, ] [[package]] name = "wxpython" -version = "4.2.0" +version = "4.2.1" description = "Cross platform GUI toolkit for Python, \"Phoenix\" version" -category = "main" optional = false python-versions = "*" files = [ - {file = "wxPython-4.2.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:f15b04aca27fe5b42af5eeb3952ab9a2cf7d6b375bf237b76f0c9d9ab3bf08c8"}, - {file = "wxPython-4.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:3bc788f046ee80f41c814ab2f75f87b0d0cd42fd3fb950815199c7be57b5ae12"}, - {file = "wxPython-4.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:7894b4d3fbbf726d8315d08d030b881bd29ed7476bc5f6ae90262064de2a664e"}, - {file = "wxPython-4.2.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:0edf70129a9c5554d0f788c7cd37e60e7d326a14d4370df43870cc637c2534f3"}, - {file = "wxPython-4.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8a278028b0a92a7ff9bcf022faf92ebfe35f53b61ca486338c46f207c4faaa4a"}, - {file = "wxPython-4.2.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:f79b8103ec62bff14bb653c9aa17a55fb1398a465b3b9371bcd80272eb1e3152"}, - {file = "wxPython-4.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:8b53eb64549996a04f773bdec92b4612ecf7d622e9bbdeb85249062a469a5eb2"}, - {file = "wxPython-4.2.0.tar.gz", hash = "sha256:663cebc4509d7e5d113518865fe274f77f95434c5d57bc386ed58d65ceed86c7"}, + {file = "wxPython-4.2.1-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:3fd606d10db694c29f712f13dc3d3179d0204a71f6c1fbb5fcee859d03e9ff97"}, + {file = "wxPython-4.2.1-cp310-cp310-win32.whl", hash = "sha256:5b233c39d7bfb53b9c4928ee7c86d626f1f7a716a6dfc3acc152bb437e658751"}, + {file = "wxPython-4.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:bb7988814e706eb00792589d606d317da5661dcffbb09263cd20da956c46bcbb"}, + {file = "wxPython-4.2.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:e87960d1963e291d4009c8547c85716b7d5325eb828cd183fdb28d441d6c3787"}, + {file = "wxPython-4.2.1-cp311-cp311-win32.whl", hash = "sha256:a41f3e03c3bfbe80864d7456f5c1236991fa937eedb60b986bd67e1bb47b7c3d"}, + {file = "wxPython-4.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:3062b4d2f5d6dcf1d59983797fc067270a5ce829a918d52a516212e798f0c9ae"}, + {file = "wxPython-4.2.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:957a6e7cc68a8e4d7ca49c72a691b6efd5684040f4f03b112d0122e7ab470497"}, + {file = "wxPython-4.2.1-cp312-cp312-win32.whl", hash = "sha256:8d846a785cd33c31e7eb42038eb159c88977d38208496b8322d14aef107f3eec"}, + {file = "wxPython-4.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:1ca327c877f276b33e2c4b6cb8417964305ee505e2509fb2000851d48b82328f"}, + {file = "wxPython-4.2.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:a7eefbc7fe7ac86479d814302711f8f118ba214229aa2a6d789fb888ee79abaa"}, + {file = "wxPython-4.2.1-cp38-cp38-win32.whl", hash = "sha256:ff0423e84a5aaa203e7c1c3d36f8417c54cb4cd8849a43b3c917ac3bfafa4ad7"}, + {file = "wxPython-4.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:903f45131107802b38c0b5d0e964a2ce0295b67e8c3d7659821ac5b26a35658b"}, + {file = "wxPython-4.2.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:a15b76dad81f9bd6ceadf00fbede9aff9e09859a9aa698c53e8bd56b95d2effc"}, + {file = "wxPython-4.2.1-cp39-cp39-win32.whl", hash = "sha256:c4db6d7f054d76cb1532dbd5da81b87b7a90dc9fdf18a3540063b2f8f5f3e663"}, + {file = "wxPython-4.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:0595fdd133a552a232a99759b87891136a4500c806bbea68b888e7b6f2c9bbea"}, + {file = "wxPython-4.2.1.tar.gz", hash = "sha256:e48de211a6606bf072ec3fa778771d6b746c00b7f4b970eb58728ddf56d13d5c"}, ] [package.dependencies] -numpy = {version = "*", markers = "python_version >= \"3.0\""} +numpy = {version = "*", markers = "python_version >= \"3.0\" and python_version < \"3.12\""} pillow = "*" six = "*" +[[package]] +name = "zipp" +version = "3.17.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, + {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + [metadata] lock-version = "2.0" python-versions = "<3.11,>=3.8" -content-hash = "be72410470daf1ce8fc12125d94a70502aac0da7b1a9fdfebfbbaab0dcb82a7f" +content-hash = "8c0681d56fc2ec1e5bb1b9df9eb33f7066fcad1b976a792744e23d9b853eac62" diff --git a/simulator/pyproject.toml b/simulator/pyproject.toml index fdd991b..b1ccf11 100644 --- a/simulator/pyproject.toml +++ b/simulator/pyproject.toml @@ -7,8 +7,8 @@ readme = "README.md" [tool.poetry.dependencies] python = "<3.11,>=3.8" -wxPython = "^4.2.0" -pyinstaller = "^5.4.1" +wxPython = "^4.2.1" +pyinstaller = "^6.4.0" numpy = ">1.22" [tool.poetry.group.dev.dependencies] diff --git a/simulator/simgui.fbp b/simulator/simgui.fbp index 357db52..12658d9 100644 --- a/simulator/simgui.fbp +++ b/simulator/simgui.fbp @@ -36,6 +36,7 @@ wxBOTH 1 + 0 1 impl_virtual @@ -87,6 +88,7 @@ Dock 0 Left + 0 1 1 @@ -164,6 +166,7 @@ Dock 0 Left + 0 1 1 @@ -224,6 +227,7 @@ Dock 0 Left + 0 1 1 @@ -285,6 +289,7 @@ Dock 0 Left + 0 1 1 @@ -350,6 +355,7 @@ Dock 0 Left + 0 1 1 @@ -412,6 +418,7 @@ Dock 0 Left + 0 1 1 @@ -476,6 +483,7 @@ Dock 0 Left + 0 1 1 @@ -537,6 +545,7 @@ Dock 0 Left + 0 1 1 @@ -599,6 +608,7 @@ Dock 0 Left + 0 1 1 @@ -661,6 +671,7 @@ Dock 0 Left + 0 1 1 @@ -726,6 +737,7 @@ Dock 0 Left + 0 1 1 @@ -787,6 +799,7 @@ Dock 0 Left + 0 1 1 @@ -852,6 +865,7 @@ Dock 0 Left + 0 1 1 @@ -913,6 +927,7 @@ Dock 0 Left + 0 1 1 @@ -981,6 +996,7 @@ Dock 0 Left + 0 1 1 @@ -1050,6 +1066,7 @@ Dock 0 Left + 0 1 1 @@ -1111,6 +1128,7 @@ Dock 0 Left + 0 1 1 @@ -1198,6 +1216,7 @@ Dock 0 Left + 0 1 1 @@ -1259,6 +1278,7 @@ Dock 0 Left + 0 1 1 @@ -1346,6 +1366,7 @@ Dock 0 Left + 0 1 1 @@ -1407,6 +1428,7 @@ Dock 0 Left + 0 1 1 @@ -1494,6 +1516,7 @@ Dock 0 Left + 0 1 1 @@ -1555,6 +1578,7 @@ Dock 0 Left + 0 1 1 @@ -1610,16 +1634,16 @@ 5 - wxEXPAND + wxEXPAND|wxTOP 1 bEndstopSizer - wxHORIZONTAL + wxVERTICAL none 5 - wxALL|wxALIGN_CENTER_VERTICAL + wxALL 0 1 @@ -1647,6 +1671,7 @@ Dock 0 Left + 0 1 1 @@ -1691,6 +1716,79 @@ OnBtnEndstopClick + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 + wxID_ANY + Button + + 0 + + 0 + + + 0 + 60,-1 + 1 + m_btnButton + 1 + + + protected + 1 + + + + Resizable + 1 + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + OnBtnButtonClick + + @@ -1732,6 +1830,7 @@ Dock 0 Left + 0 1 1 @@ -1799,6 +1898,7 @@ Dock 0 Left + 0 1 1 @@ -1861,6 +1961,7 @@ Dock 0 Left + 0 0 1 @@ -1925,6 +2026,7 @@ Dock 0 Left + 0 1 1 @@ -1987,6 +2089,7 @@ Dock 0 Left + 0 0 1 @@ -2052,6 +2155,7 @@ Dock 0 Left + 0 1 1 @@ -2114,6 +2218,7 @@ Dock 0 Left + 0 0 1 @@ -2180,6 +2285,7 @@ Dock 0 Left + 0 1 1 @@ -2242,6 +2348,7 @@ Dock 0 Left + 0 0 1 @@ -2308,6 +2415,7 @@ Dock 0 Left + 0 1 1 @@ -2370,6 +2478,7 @@ Dock 0 Left + 0 0 1 @@ -2436,6 +2545,7 @@ Dock 0 Left + 0 1 1 @@ -2516,6 +2626,7 @@ Dock 0 Left + 0 0 1 @@ -2594,6 +2705,7 @@ Dock 0 Left + 0 0 1 @@ -2668,6 +2780,7 @@ Dock 0 Left + 0 0 1 @@ -2742,6 +2855,7 @@ Dock 0 Left + 0 0 1 @@ -2816,6 +2930,7 @@ Dock 0 Left + 0 0 1 @@ -2891,6 +3006,7 @@ Dock 0 Left + 0 1 1 @@ -2953,6 +3069,7 @@ Dock 0 Left + 0 0 1 @@ -3028,6 +3145,7 @@ Dock 0 Left + 0 1 1 @@ -3106,6 +3224,7 @@ Dock 0 Left + 0 1 1 @@ -3180,6 +3299,7 @@ Dock 0 Left + 0 1 1 @@ -3267,6 +3387,7 @@ Dock 0 Left + 0 1 1 @@ -3341,6 +3462,7 @@ Dock 0 Left + 0 1 1 @@ -3423,6 +3545,7 @@ Dock 0 Left + 0 1 1 @@ -3492,6 +3615,7 @@ Dock 0 Left + 0 1 1 diff --git a/simulator/simulator/klippermock.py b/simulator/simulator/klippermock.py index e7fbac6..9ebe1ac 100644 --- a/simulator/simulator/klippermock.py +++ b/simulator/simulator/klippermock.py @@ -37,6 +37,8 @@ def load_object(self, config, o): return self.objects[o] elif o == "query_adc": return self + elif o == "buttons": + return self return None def register_event_handler(self, event, callback): pass @@ -46,6 +48,8 @@ def register_command(self, cmd, callback, desc): pass def register_timer(self, callback, time): pass + def register_buttons(self, pins, callback): + pass def get_reactor(self): return self def register_timer(self, callback, time): @@ -74,6 +78,14 @@ def set_progress (self, progress): self.led_effect.handler.printProgress=progress def set_analog(self, value): self.led_effect.analogValue=value + def load_template(self, config, name): + self.template = config.get(name) + return self + def render(self, context=None): + return self.template + def create_template_context(self): + return {'printer': self} + class mockConfig: def __init__(self): @@ -81,12 +93,14 @@ def __init__(self): "frame_rate" : "24.0", "autostart" : "False", "run_on_error" : "False", + "recalculate": "False", "heater" : "bed", "analog_pin" : "PA0", "stepper" : "x", "layers" : """gradient 1 1 top (1, 0.0, 0.0),(0, 1, 0.0),(0.0, 0.0, 1)""", "leds" : "leds:leds", - "endstops" : "x" + "endstops" : "x", + "button_pins" : "PA0" } def set_printer(self, printer): self.printer=printer @@ -102,6 +116,8 @@ def getint(self,key,default,minval,maxval): return int(self.config[key]) def setint(self,key, value): self.config[key] = int (value) + def getlist(self,key,default): + return list(self.config[key]) def get_name(self): return "led_effect simulator" def get(self, key, default=None ): diff --git a/simulator/simulator/simgui.py b/simulator/simulator/simgui.py index cb437f6..c4d1e79 100644 --- a/simulator/simulator/simgui.py +++ b/simulator/simulator/simgui.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- ########################################################################### -## Python code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3) +## Python code generated with wxFormBuilder (version 3.10.1-e2e4764) ## http://www.wxformbuilder.org/ ## ## PLEASE DO *NOT* EDIT THIS FILE! @@ -168,15 +168,20 @@ def __init__( self, parent ): bHeaterStepperSizer.Add( ( 20, 0), 1, wx.EXPAND, 5 ) - bEndstopSizer = wx.BoxSizer( wx.HORIZONTAL ) + bEndstopSizer = wx.BoxSizer( wx.VERTICAL ) self.m_btnEndstop = wx.Button( self.m_panel41, wx.ID_ANY, u"Endstop", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_btnEndstop.SetMinSize( wx.Size( 60,-1 ) ) - bEndstopSizer.Add( self.m_btnEndstop, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + bEndstopSizer.Add( self.m_btnEndstop, 0, wx.ALL, 5 ) + self.m_btnButton = wx.ToggleButton( self.m_panel41, wx.ID_ANY, u"Button", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_btnButton.SetMinSize( wx.Size( 60,-1 ) ) - bHeaterStepperSizer.Add( bEndstopSizer, 1, wx.EXPAND, 5 ) + bEndstopSizer.Add( self.m_btnButton, 0, wx.ALL, 5 ) + + + bHeaterStepperSizer.Add( bEndstopSizer, 1, wx.EXPAND|wx.TOP, 5 ) self.m_panel41.SetSizer( bHeaterStepperSizer ) @@ -390,6 +395,7 @@ def __init__( self, parent ): self.m_slProgress.Bind( wx.EVT_SLIDER, self.OnProgressSlider ) self.m_slAnalog.Bind( wx.EVT_SLIDER, self.OnAnalogSlider ) self.m_btnEndstop.Bind( wx.EVT_BUTTON, self.OnBtnEndstopClick ) + self.m_btnButton.Bind( wx.EVT_TOGGLEBUTTON, self.OnBtnButtonClick ) self.m_cbActive.Bind( wx.EVT_CHECKBOX, self.OnEffectSettingChanged ) self.m_cbEffect.Bind( wx.EVT_COMBOBOX, self.OnEffectSettingChanged ) self.m_spinEffectRate.Bind( wx.EVT_SPINCTRLDOUBLE, self.OnEffectSettingChanged ) @@ -456,6 +462,9 @@ def OnAnalogSlider( self, event ): def OnBtnEndstopClick( self, event ): event.Skip() + def OnBtnButtonClick( self, event ): + event.Skip() + def OnEffectSettingChanged( self, event ): event.Skip() diff --git a/simulator/simulator/simulator.py b/simulator/simulator/simulator.py index 7398a88..8d3e791 100644 --- a/simulator/simulator/simulator.py +++ b/simulator/simulator/simulator.py @@ -254,7 +254,12 @@ def OnBtnEndstopClick(self, event): self.printer.led_effect.handler.homing_end_flag["x"] += 1 else: self.printer.led_effect.handler.homing_end_flag["x"] = 0 - + + def OnBtnButtonClick( self, event ): + if self.m_btnButton.Value: + self.printer.led_effect.button_state = 1 + else: + self.printer.led_effect.button_state = 0 def OnExit(self, event): self.Close(True) diff --git a/src/led_effect.py b/src/led_effect.py index e00c864..e282b29 100644 --- a/src/led_effect.py +++ b/src/led_effect.py @@ -8,7 +8,6 @@ from math import cos, exp, pi from random import randint -import logging ANALOG_SAMPLE_TIME = 0.001 ANALOG_SAMPLE_COUNT = 5 @@ -114,7 +113,6 @@ def _handle_shutdown(self): def _handle_homing_move_begin(self, hmove): endstops_being_homed = [name for es,name in hmove.endstops] - logging.info(endstops_being_homed) for endstop in endstops_being_homed: if endstop in self.homing_start_flag: @@ -309,6 +307,7 @@ def __init__(self, config): self.config = config self.printer = config.get_printer() self.gcode = self.printer.lookup_object('gcode') + self.gcode_macro = self.printer.lookup_object('gcode_macro') self.handler = self.printer.load_object(config, 'led_effect') self.frameRate = 1.0 / config.getfloat('frame_rate', default=24, minval=1, maxval=60) @@ -316,7 +315,8 @@ def __init__(self, config): self.iteration = 0 self.layers = [] self.analogValue = 0 - self.fadeValue = 1.0 + self.button_state = 0 + self.fadeValue = 0.0 self.fadeTime = 0.0 self.fadeEndTime = 0 @@ -346,9 +346,12 @@ def __init__(self, config): self.runOnShutown = config.getboolean('run_on_error', False) self.heater = config.get('heater', None) self.analogPin = config.get('analog_pin', None) + self.buttonPins = config.getlist('button_pins', None) self.stepper = config.get('stepper', None) + self.recalculate = config.get('recalculate', False) self.endstops = [x.strip() for x in config.get('endstops','').split(',')] - self.configLayers = config.get('layers') + self.layerTempl = self.gcode_macro.load_template(config, 'layers') + self.configLayers = [] self.configLeds = config.get('leds') self.nextEventTime = 0 @@ -365,6 +368,10 @@ def __init__(self, config): query_adc = self.printer.load_object(self.config, 'query_adc') query_adc.register_adc(self.name, self.mcu_adc) + if self.buttonPins: + buttons = self.printer.load_object(config, "buttons") + buttons.register_buttons(self.buttonPins, self.button_callback) + cmd_SET_LED_help = 'Starts or Stops the specified led_effect' def _handle_ready(self): @@ -372,6 +379,8 @@ def _handle_ready(self): self.ledChains = [] self.leds = [] self.enabled = self.autoStart + if not self.enabled: + self.nextEventTime = self.handler.reactor.NEVER self.printer.register_event_handler('klippy:shutdown', self._handle_shutdown) #map each LED from the chains to the "pixels" in the effect frame @@ -400,7 +409,14 @@ def _handle_ready(self): .lower() : c for c in self._layerBase.__subclasses__() if str(c).startswith("= 1: for led in self.leds: for effect in self.handler.effects: @@ -511,6 +536,8 @@ def cmd_SET_LED_EFFECT(self, gcmd): if not self.enabled: self.set_fade_time(parmFadeTime) + if gcmd.get_int('RESTART', 0) >= 1: + self.reset_frame() self.set_enabled(True) def _handle_shutdown(self): @@ -518,6 +545,9 @@ def _handle_shutdown(self): def adcCallback(self, read_time, read_value): self.analogValue = int(read_value * 1000.0) / 10.0 + + def button_callback(self, eventtime, state): + self.button_state = state ###################################################################### # LED Effect layers @@ -542,6 +572,8 @@ def __init__(self, **kwargs): self.lastAnalog = 0 def nextFrame(self, eventtime): + if not self.frameCount: + return [0] * COLORS * self.ledCount self.frameNumber += 1 self.frameNumber = self.frameNumber * \ ( self.frameNumber < self.frameCount ) @@ -883,6 +915,10 @@ def __init__(self, **kwargs): self.frameCount = len(self.thisFrame) + if self.handler.heater is None: + raise self.handler.printer.config_error( + "LED Effect '%s' has no heater defined." % (self.handler.name)) + def nextFrame(self, eventtime): heaterTarget = self.frameHandler.heaterTarget[self.handler.heater] heaterCurrent = self.frameHandler.heaterCurrent[self.handler.heater] @@ -920,6 +956,11 @@ def __init__(self, **kwargs): for i in range(len(gradient)): self.thisFrame.append(gradient[i] * self.ledCount) self.frameCount = len(self.thisFrame) + + if self.handler.heater is None: + raise self.handler.printer.config_error( + "LED Effect '%s' has no heater defined." % (self.handler.name)) + def nextFrame(self, eventtime): if self.effectCutoff == self.effectRate: s = 200 if self.frameHandler.heaterCurrent[self.handler.heater] >= self.effectRate else 0 @@ -931,6 +972,111 @@ def nextFrame(self, eventtime): s = min(len(self.thisFrame)-1,s) s = max(0,s) return self.thisFrame[s] + class layerHeaterGauge(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerHeaterGauge, self).__init__(**kwargs) + + if self.effectRate < 0: + self.effectRate = self.ledCount + + if self.effectCutoff < 0: + self.effectCutoff = self.ledCount + + if self.effectRate == 0: + trailing = colorArray(COLORS, [0.0]*COLORS * self.ledCount) + else: + trailing = colorArray(COLORS, self._gradient(self.paletteColors[1:], + int(self.effectRate), True)) + trailing.padLeft([0.0]*COLORS, self.ledCount) + + if self.effectCutoff == 0: + leading = colorArray(COLORS, [0.0]*COLORS * self.ledCount) + else: + leading = colorArray(COLORS, self._gradient(self.paletteColors[1:], + int(self.effectCutoff), False)) + leading.padRight([0.0]*COLORS, self.ledCount) + + gradient = colorArray(COLORS, trailing + self.paletteColors[0] + leading) + gradient.shift(len(trailing), 0) + frames = [gradient[:self.ledCount]] + + for i in range(0, self.ledCount): + gradient.shift(1,1) + frames.append(gradient[:self.ledCount]) + + self.thisFrame.append(colorArray(COLORS, [0.0]*COLORS * self.ledCount)) + for i in range(1, 101): + x = int((i / 101.0) * self.ledCount) + self.thisFrame.append(frames[x]) + + self.frameCount = len(self.thisFrame) + + def nextFrame(self, eventtime): + heaterTarget = self.frameHandler.heaterTarget[self.handler.heater] + heaterCurrent = self.frameHandler.heaterCurrent[self.handler.heater] + heaterLast = self.frameHandler.heaterLast[self.handler.heater] + + if heaterTarget > 0.0: + p = int(heaterCurrent/heaterTarget * 100.0) + elif heaterLast > 0.0: + p = int(heaterCurrent/heaterLast * 100.0) + else: + p = 0 + + p = min(len(self.thisFrame)-1,p) + p = max(0,p) + + return self.thisFrame[p] + + class layerTemperatureGauge(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerTemperatureGauge, self).__init__(**kwargs) + + trailing = colorArray(COLORS, self._gradient(self.paletteColors[1:], + int(self.ledCount), True)) + trailing.padLeft([0.0]*COLORS, self.ledCount) + + leading = colorArray(COLORS, [0.0]*COLORS * self.ledCount) + + gradient = colorArray(COLORS, trailing + self.paletteColors[0] + leading) + gradient.shift(len(trailing), 0) + frames = [gradient[:self.ledCount]] + + for i in range(0, self.ledCount): + gradient.shift(1,1) + frames.append(gradient[:self.ledCount]) + + self.thisFrame.append(colorArray(COLORS, [0.0]*COLORS * self.ledCount)) + self.steps = 255 + for i in range(1, self.steps + 1): + x = int((i / float(self.steps + 1)) * self.ledCount) + frames2=colorArray(COLORS,[]) + + for idx,led in enumerate(frames[x]): + + brightness = min(1.0,max(0.0,len(frames[x]) * (float(i) / float(self.steps + 1)) - int(idx/COLORS))) + + frames2.append(led*brightness) + + self.thisFrame.append(frames2) + + self.frameCount = len(self.thisFrame) + + def nextFrame(self, eventtime): + if self.effectCutoff == self.effectRate: + s = len(self.thisFrame) if self.frameHandler.heaterCurrent[self.handler.heater] >= self.effectRate else 0 + else: + s = int(((self.frameHandler.heaterCurrent[self.handler.heater] - + self.effectRate) / + (self.effectCutoff - self.effectRate)) * self.steps) + + s = min(len(self.thisFrame)-1,s) + s = max(0,s) + + + + return self.thisFrame[s] + #Responds to analog pin voltage class layerAnalogPin(_layerBase): @@ -1084,7 +1230,10 @@ def __init__(self, **kwargs): self.frameLen = len(self.gradient) self.heatLen = len(self.heatMap) self.heatSource = int(self.ledCount / 10.0) - self.effectRate = 0 + + if self.handler.heater is None: + raise self.handler.printer.config_error( + "LED Effect '%s' has no heater defined." % (self.handler.name)) if self.heatSource < 1: self.heatSource = 1 @@ -1097,14 +1246,15 @@ def nextFrame(self, eventtime): heaterLast = self.frameHandler.heaterLast[self.handler.heater] if heaterTarget > 0.0 and heaterCurrent > 0.0: - if heaterCurrent <= heaterTarget-2: - spark = int((heaterCurrent / heaterTarget) * 80) - brightness = int((heaterCurrent / heaterTarget) * 100) - elif self.effectCutoff > 0: - spark = 0 - else: - spark = 80 - brightness = 100 + if (heaterCurrent >= self.effectRate): + if heaterCurrent <= heaterTarget-2: + spark = int((heaterCurrent / heaterTarget) * 80) + brightness = int((heaterCurrent / heaterTarget) * 100) + elif self.effectCutoff > 0: + spark = 0 + else: + spark = 80 + brightness = 100 elif self.effectRate > 0 and heaterCurrent > 0.0: if heaterCurrent >= self.effectRate: spark = int(((heaterCurrent - self.effectRate) @@ -1112,7 +1262,7 @@ def nextFrame(self, eventtime): brightness = int(((heaterCurrent - self.effectRate) / heaterLast) * 100) - if spark > 0: + if spark > 0 and heaterTarget != 0: cooling = int((heaterCurrent / heaterTarget) * 20) for h in range(self.heatLen): @@ -1205,7 +1355,6 @@ def __init__(self, **kwargs): self.coloridx=-1 self.my_flag={} for endstop in self.handler.endstops: - logging.info(endstop) self.frameHandler.homing_end_flag[endstop] = 0 self.my_flag[endstop] = self.frameHandler.homing_end_flag[endstop] @@ -1222,7 +1371,123 @@ def nextFrame(self, eventtime): self.counter += 1 return frame + class layerSwitchButton(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerSwitchButton, self).__init__(**kwargs) + self.last_state = 0 + self.coloridx = 0 + self.fadeValue = 0.0 + self.paletteColors = colorArray(COLORS, self.paletteColors) + + for c in range(0, len(self.paletteColors)): + color = self.paletteColors[c] + self.thisFrame.append(colorArray(COLORS,color*self.ledCount)) + + def nextFrame(self, eventtime): + if self.handler.button_state > self.last_state: + self.coloridx = (self.coloridx + 1) % len(self.paletteColors) + + self.last_state = self.handler.button_state + + if self.last_state: + if self.effectRate > 0 and self.fadeValue < 1.0: + self.fadeValue += (self.handler.frameRate / self.effectRate) + else: + self.fadeValue = 1.0 + else: + if self.effectCutoff > 0 and self.fadeValue > 0.0: + self.fadeValue -= (self.handler.frameRate / self.effectCutoff) + else: + self.fadeValue = 0.0 + + if self.fadeValue < 0: self.fadeValue = 0 + if self.fadeValue > 1.0: self.fadeValue = 1.0 + return [self.fadeValue * i for i in self.thisFrame[self.coloridx]] + class layerToggleButton(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerToggleButton, self).__init__(**kwargs) + self.last_state = 0 + self.last_coloridx = 0 + self.coloridx = 0 + self.fadeInValue = 0.0 + self.fadeOutValue = 0.0 + self.active = False + self.paletteColors = colorArray(COLORS, self.paletteColors) + + for c in range(0, len(self.paletteColors)): + color = self.paletteColors[c] + self.thisFrame.append(colorArray(COLORS,color*self.ledCount)) + + def nextFrame(self, eventtime): + if self.handler.button_state > self.last_state: + self.last_coloridx = self.coloridx + self.coloridx = (self.coloridx + 1) % len(self.paletteColors) + self.last_state = self.handler.button_state + self.fadeInValue = 0 + self.fadeOutValue = 1.0 + + self.last_state = self.handler.button_state + + if self.effectRate > 0 and self.fadeInValue < 1.0: + self.fadeInValue += (self.handler.frameRate / self.effectRate) + else: + self.fadeInValue = 1.0 + if self.effectCutoff > 0 and self.fadeOutValue > 0.0: + self.fadeOutValue -= (self.handler.frameRate / self.effectCutoff) + else: + self.fadeOutValue = 0.0 + + if self.fadeInValue < 0: self.fadeInValue = 0 + if self.fadeInValue > 1.0: self.fadeInValue = 1.0 + + if self.fadeOutValue < 0: self.fadeOutValue = 0 + if self.fadeOutValue > 1.0: self.fadeOutValue = 1.0 + + frameIn = [self.fadeInValue * i for i in self.thisFrame[self.coloridx]] + frameOut = [self.fadeOutValue * i for i in self.thisFrame[self.last_coloridx]] + + return [ i + o for i, o in zip(frameIn,frameOut)] + + class layerFlashButton(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerFlashButton, self).__init__(**kwargs) + self.last_state = 0 + self.active = False + self.coloridx = 0 + self.fadeValue = 0.0 + self.paletteColors = colorArray(COLORS, self.paletteColors) + + for c in range(0, len(self.paletteColors)): + color = self.paletteColors[c] + self.thisFrame.append(colorArray(COLORS,color*self.ledCount)) + + def nextFrame(self, eventtime): + + if self.handler.button_state > self.last_state: + self.coloridx = (self.coloridx + 1) % len(self.paletteColors) + self.active = True + + self.last_state=self.handler.button_state + + if self.active: + if self.effectRate > 0 and self.fadeValue < 1.0: + self.fadeValue += (self.handler.frameRate / self.effectRate) + else: + self.fadeValue = 1.0 + if self.fadeValue >= 1.0: + self.fadeValue = 1.0 + self.active = False + else: + if self.effectCutoff > 0 and self.fadeValue > 0.0: + self.fadeValue -= (self.handler.frameRate / self.effectCutoff) + else: + self.fadeValue = 0.0 + + if self.fadeValue <= 0: + self.fadeValue = 0 + + return [self.fadeValue * i for i in self.thisFrame[self.coloridx]] def load_config_prefix(config): return ledEffect(config)