aboutsummaryrefslogtreecommitdiff
path: root/aoc2023/build/packages/gleam_community_colour/src
diff options
context:
space:
mode:
authorJ.J <thechairman@thechairman.info>2024-05-30 21:50:02 -0400
committerJ.J <thechairman@thechairman.info>2024-05-30 21:50:02 -0400
commit612fd986ab1e00b6d34dc1937136250e08e89325 (patch)
treea3c93952040c6afdf348b5831619a45db7ba0a2e /aoc2023/build/packages/gleam_community_colour/src
parent231c2b688d1e6cf0846d46e883da30e042a9c6cf (diff)
downloadgleam_aoc-612fd986ab1e00b6d34dc1937136250e08e89325.tar.gz
gleam_aoc-612fd986ab1e00b6d34dc1937136250e08e89325.zip
cleanup
Diffstat (limited to 'aoc2023/build/packages/gleam_community_colour/src')
-rw-r--r--aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour.gleam1126
-rw-r--r--aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam173
-rw-r--r--aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour.erl511
-rw-r--r--aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl73
-rw-r--r--aoc2023/build/packages/gleam_community_colour/src/gleam_community_colour.app.src9
5 files changed, 1892 insertions, 0 deletions
diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour.gleam b/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour.gleam
new file mode 100644
index 0000000..1f5872f
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour.gleam
@@ -0,0 +1,1126 @@
+////
+//// - **Types**
+//// - [`Colour`](#Colour)
+//// - [`Color`](#Color)
+//// - **Constructors**
+//// - [`from_rgb255`](#from_rgb255)
+//// - [`from_rgb`](#from_rgb)
+//// - [`from_rgba`](#from_rgba)
+//// - [`from_hsl`](#from_hsl)
+//// - [`from_hsla`](#from_hsla)
+//// - [`from_rgb_hex`](#from_rgb_hex)
+//// - [`from_rgba_hex`](#from_rgba_hex)
+//// - [`from_rgb_hex_string`](#from_rgb_hex_string)
+//// - [`from_rgba_hex_string`](#from_rgba_hex_string)
+//// - **Conversions**
+//// - [`to_rgba`](#to_rgba)
+//// - [`to_hsla`](#hsla)
+//// - [`to_css_rgba_string`](#to_css_rgba_string)
+//// - [`to_rgba_hex_string`](#to_rgba_hex_string)
+//// - [`to_rgb_hex_string`](#to_rgb_hex_string)
+//// - [`to_rgba_hex`](#to_rgba_hex)
+//// - [`to_rgb_hex`](#to_rgb_hex)
+//// - **Colours**
+//// - [`light_red`](#light_red)
+//// - [`red`](#red)
+//// - [`dark_red`](#dark_red)
+//// - [`light_orange`](#light_orange)
+//// - [`orange`](#orange)
+//// - [`dark_orange`](#dark_orange)
+//// - [`light_yellow`](#light_yellow)
+//// - [`yellow`](#yellow)
+//// - [`dark_yellow`](#dark_yellow)
+//// - [`light_green`](#light_green)
+//// - [`green`](#green)
+//// - [`dark_green`](#dark_green)
+//// - [`light_blue`](#light_blue)
+//// - [`blue`](#blue)
+//// - [`dark_blue`](#dark_blue)
+//// - [`light_purple`](#light_purple)
+//// - [`purple`](#purple)
+//// - [`dark_purple`](#dark_purple)
+//// - [`light_brown`](#light_brown)
+//// - [`brown`](#brown)
+//// - [`dark_brown`](#dark_brown)
+//// - [`black`](#black)
+//// - [`white`](#white)
+//// - [`light_grey`](#light_grey)
+//// - [`grey`](#grey)
+//// - [`dark_grey`](#dark_grey)
+//// - [`light_gray`](#light_gray)
+//// - [`gray`](#gray)
+//// - [`dark_gray`](#dark_gray)
+//// - [`light_charcoal`](#light_charcoal)
+//// - [`charcoal`](#charcoal)
+//// - [`dark_charcoal`](#dark_charcoal)
+//// - [`pink`](#pink)
+////
+//// ---
+////
+//// This package was heavily inspired by the `elm-color` module.
+//// The original source code can be found
+//// <a href="https://github.com/avh4/elm-color/">here</a>.
+////
+//// <details>
+//// <summary>The license of that package is produced below:</summary>
+////
+////
+//// > MIT License
+////
+//// > Copyright 2018 Aaron VonderHaar
+////
+//// > Redistribution and use in source and binary forms, with or without modification,
+//// are permitted provided that the following conditions are met:
+////
+//// 1. Redistributions of source code must retain the above copyright notice,
+//// this list of conditions and the following disclaimer.
+////
+//// 2. Redistributions in binary form must reproduce the above copyright notice,
+//// this list of conditions and the following disclaimer in the documentation
+//// and/or other materials provided with the distribution.
+////
+//// 3. Neither the name of the copyright holder nor the names of its contributors
+//// may be used to endorse or promote products derived from this software without
+//// specific prior written permission.
+////
+//// > THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+//// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+//// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+//// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+//// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+//// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+//// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+////
+//// > The above copyright notice and this permission notice shall be included in all
+//// copies or substantial portions of the Software.
+//// </details>
+////
+
+// Just in case we decide in the future to no longer include the above reference
+// and license, this package was initially a port of the `elm-color` module:
+//
+// https://github.com/avh4/elm-color/
+//
+
+// IMPORTS --------------------------------------------------------------------
+
+import gleam/int
+import gleam/float
+import gleam/result
+import gleam/string
+import gleam/list
+
+// TYPES ----------------------------------------------------------------------
+
+/// A representation of a colour that can be converted to RGBA or HSLA format.
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+/// </br>
+///
+pub opaque type Colour {
+ Rgba(r: Float, g: Float, b: Float, a: Float)
+ Hsla(h: Float, s: Float, l: Float, a: Float)
+}
+
+/// Type alias for `Colour`
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+/// </br>
+///
+pub type Color =
+ Colour
+
+// UTILITY --------------------------------------------------------------------
+
+fn valid_colour_value(c: Float) -> Result(Float, Nil) {
+ case c >. 1.0 || c <. 0.0 {
+ True -> Error(Nil)
+ False -> Ok(c)
+ }
+}
+
+fn hue_to_rgb(hue: Float, m1: Float, m2: Float) -> Float {
+ let h = case hue {
+ _ if hue <. 0.0 -> hue +. 1.0
+ _ if hue >. 1.0 -> hue -. 1.0
+ _ -> hue
+ }
+
+ let h_t_6 = h *. 6.0
+ let h_t_2 = h *. 2.0
+ let h_t_3 = h *. 3.0
+
+ case h {
+ _ if h_t_6 <. 1.0 -> m1 +. { m2 -. m1 } *. h *. 6.0
+ _ if h_t_2 <. 1.0 -> m2
+ _ if h_t_3 <. 2.0 -> m1 +. { m2 -. m1 } *. { 2.0 /. 3.0 -. h } *. 6.0
+ _ -> m1
+ }
+}
+
+fn hex_string_to_int(hex_string: String) -> Result(Int, Nil) {
+ let hex = case hex_string {
+ "#" <> hex_number -> hex_number
+ "0x" <> hex_number -> hex_number
+ _ -> hex_string
+ }
+
+ hex
+ |> string.lowercase()
+ |> string.to_graphemes()
+ |> list.reverse()
+ |> list.index_fold(
+ Ok(0),
+ fn(total, char, index) {
+ case total {
+ Error(Nil) -> Error(Nil)
+ Ok(v) -> {
+ use num <- result.then(case char {
+ "a" -> Ok(10)
+ "b" -> Ok(11)
+ "c" -> Ok(12)
+ "d" -> Ok(13)
+ "e" -> Ok(14)
+ "f" -> Ok(15)
+ _ -> int.parse(char)
+ })
+ use base <- result.then(int.power(16, int.to_float(index)))
+ Ok(v + float.round(int.to_float(num) *. base))
+ }
+ }
+ },
+ )
+}
+
+fn hsla_to_rgba(
+ h: Float,
+ s: Float,
+ l: Float,
+ a: Float,
+) -> #(Float, Float, Float, Float) {
+ let m2 = case l <=. 0.5 {
+ True -> l *. { s +. 1.0 }
+ False -> l +. s -. l *. s
+ }
+
+ let m1 = l *. 2.0 -. m2
+
+ let r = hue_to_rgb(h +. 1.0 /. 3.0, m1, m2)
+ let g = hue_to_rgb(h, m1, m2)
+ let b = hue_to_rgb(h -. 1.0 /. 3.0, m1, m2)
+
+ #(r, g, b, a)
+}
+
+fn rgba_to_hsla(
+ r: Float,
+ g: Float,
+ b: Float,
+ a: Float,
+) -> #(Float, Float, Float, Float) {
+ let min_colour = float.min(r, float.min(g, b))
+
+ let max_colour = float.max(r, float.max(g, b))
+
+ let h1 = case True {
+ _ if max_colour == r -> float.divide(g -. b, max_colour -. min_colour)
+ _ if max_colour == g ->
+ float.divide(b -. r, max_colour -. min_colour)
+ |> result.then(fn(d) { Ok(2.0 +. d) })
+ _ ->
+ float.divide(r -. g, max_colour -. min_colour)
+ |> result.then(fn(d) { Ok(4.0 +. d) })
+ }
+
+ let h2 = case h1 {
+ Ok(v) -> Ok(v *. { 1.0 /. 6.0 })
+ _ -> h1
+ }
+
+ let h3 = case h2 {
+ Ok(v) if v <. 0.0 -> v +. 1.0
+ Ok(v) -> v
+ _ -> 0.0
+ }
+
+ let l = { min_colour +. max_colour } /. 2.0
+
+ let s = case True {
+ _ if min_colour == max_colour -> 0.0
+ _ if l <. 0.5 ->
+ { max_colour -. min_colour } /. { max_colour +. min_colour }
+ _ -> { max_colour -. min_colour } /. { 2.0 -. max_colour -. min_colour }
+ }
+
+ #(h3, s, l, a)
+}
+
+// CONSTRUCTORS ---------------------------------------------------------------
+
+/// Returns a `Result(Colour)` created from the given 8 bit RGB values.
+///
+/// Returns `Error(Nil)` if the supplied RGB values are greater than 255 or less than 0.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb255(255, 0, 0)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgb255(r red: Int, g green: Int, b blue: Int) -> Result(Colour, Nil) {
+ use r <- result.then(
+ red
+ |> int.to_float()
+ |> float.divide(255.0)
+ |> result.then(valid_colour_value),
+ )
+
+ use g <- result.then(
+ green
+ |> int.to_float()
+ |> float.divide(255.0)
+ |> result.then(valid_colour_value),
+ )
+
+ use b <- result.then(
+ blue
+ |> int.to_float()
+ |> float.divide(255.0)
+ |> result.then(valid_colour_value),
+ )
+
+ Ok(Rgba(r: r, g: g, b: b, a: 1.0))
+}
+
+/// Returns `Result(Colour)` created from the given RGB values.
+///
+/// If the supplied RGB values are greater than 1.0 or less than 0.0 returns `Error(Nil)`
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb(1.0, 0.0, 0.0)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgb(
+ r red: Float,
+ g green: Float,
+ b blue: Float,
+) -> Result(Colour, Nil) {
+ use r <- result.then(valid_colour_value(red))
+ use g <- result.then(valid_colour_value(green))
+ use b <- result.then(valid_colour_value(blue))
+
+ Ok(Rgba(r: r, g: g, b: b, a: 1.0))
+}
+
+/// Returns `Result(Colour)` created from the given RGBA values.
+///
+/// Returns `Error(Nil)` if the supplied RGBA values are greater than 1.0 or less than 0.0.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red_half_opacity) = from_rbga(1.0, 0.0, 0.0, 0.5)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgba(
+ r red: Float,
+ g green: Float,
+ b blue: Float,
+ a alpha: Float,
+) -> Result(Colour, Nil) {
+ use r <- result.then(valid_colour_value(red))
+ use g <- result.then(valid_colour_value(green))
+ use b <- result.then(valid_colour_value(blue))
+ use a <- result.then(valid_colour_value(alpha))
+
+ Ok(Rgba(r: r, g: g, b: b, a: a))
+}
+
+/// Returns `Result(Colour)` created from the given HSLA values.
+///
+/// Returns `Error(Nil)`f the supplied HSLA values are greater than 1.0 or less than 0.0.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red_half_opacity) = from_hsla(0.0, 1.0, 0.5, 0.5)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_hsla(
+ h hue: Float,
+ s saturation: Float,
+ l lightness: Float,
+ a alpha: Float,
+) -> Result(Colour, Nil) {
+ use h <- result.then(valid_colour_value(hue))
+ use s <- result.then(valid_colour_value(saturation))
+ use l <- result.then(valid_colour_value(lightness))
+ use a <- result.then(valid_colour_value(alpha))
+
+ Ok(Hsla(h: h, s: s, l: l, a: a))
+}
+
+/// Returns `Result(Colour)` created from the given HSL values.
+///
+/// Returns `Error(Nil)` if the supplied HSL values are greater than 1.0 or less than 0.0.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_hsla(0.0, 1.0, 0.5)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_hsl(
+ h hue: Float,
+ s saturation: Float,
+ l lightness: Float,
+) -> Result(Colour, Nil) {
+ from_hsla(hue, saturation, lightness, 1.0)
+}
+
+/// Returns a `Result(Colour)` created from the given hex `Int`.
+///
+/// Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffff or less than 0x0.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb_hex(0xff0000)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgb_hex(hex: Int) -> Result(Colour, Nil) {
+ case hex > 0xffffff || hex < 0 {
+ True -> Error(Nil)
+ False -> {
+ let r =
+ int.bitwise_shift_right(hex, 16)
+ |> int.bitwise_and(0xff)
+ let g =
+ int.bitwise_shift_right(hex, 8)
+ |> int.bitwise_and(0xff)
+ let b = int.bitwise_and(hex, 0xff)
+ from_rgb255(r, g, b)
+ }
+ }
+}
+
+/// Returns a `Result(Colour)` created from the given RGB hex `String`.
+///
+/// Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `"#ffffff" or less than `"#0"`
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb_hex_string("#ff0000")
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgb_hex_string(hex_string: String) -> Result(Colour, Nil) {
+ use hex_int <- result.then(hex_string_to_int(hex_string))
+
+ from_rgb_hex(hex_int)
+}
+
+/// Returns a `Result(Colour)` created from the given RGBA hex `String`.
+///
+/// Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `"#ffffffff" or less than `"#0"`
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red_half_opacity) = from_rgba_hex_string("#ff00007f")
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgba_hex_string(hex_string: String) -> Result(Colour, Nil) {
+ use hex_int <- result.then(hex_string_to_int(hex_string))
+
+ from_rgba_hex(hex_int)
+}
+
+/// Returns a `Result(Colour)` created from the given hex `Int`.
+///
+/// Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffffff or less than 0x0.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red_half_opacity) = from_rgba_hex(0xff00007f)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgba_hex(hex: Int) -> Result(Colour, Nil) {
+ case hex > 0xffffffff || hex < 0 {
+ True -> Error(Nil)
+ False -> {
+ // This won't fail because we are always dividing by 255.0
+ let assert Ok(r) =
+ int.bitwise_shift_right(hex, 24)
+ |> int.bitwise_and(0xff)
+ |> int.to_float()
+ |> float.divide(255.0)
+ // This won't fail because we are always dividing by 255.0
+ let assert Ok(g) =
+ int.bitwise_shift_right(hex, 16)
+ |> int.bitwise_and(0xff)
+ |> int.to_float()
+ |> float.divide(255.0)
+ // This won't fail because we are always dividing by 255.0
+ let assert Ok(b) =
+ int.bitwise_shift_right(hex, 8)
+ |> int.bitwise_and(0xff)
+ |> int.to_float()
+ |> float.divide(255.0)
+ // This won't fail because we are always dividing by 255.0
+ let assert Ok(a) =
+ int.bitwise_and(hex, 0xff)
+ |> int.to_float()
+ |> float.divide(255.0)
+ from_rgba(r, g, b, a)
+ }
+ }
+}
+
+// CONVERSIONS ----------------------------------------------------------------
+
+/// Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s
+/// R, G, B, and A values respectively.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb255(255, 0, 0)
+/// let #(r, g, b, a) = to_rgba(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_rgba(colour: Colour) -> #(Float, Float, Float, Float) {
+ case colour {
+ Rgba(r, g, b, a) -> #(r, g, b, a)
+ Hsla(h, s, l, a) -> hsla_to_rgba(h, s, l, a)
+ }
+}
+
+/// Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s
+/// H, S, L, and A values respectively.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb255(255, 0, 0)
+/// let #(h, s, l, a) = to_hsla(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_hsla(colour: Colour) -> #(Float, Float, Float, Float) {
+ case colour {
+ Hsla(h, s, l, a) -> #(h, s, l, a)
+ Rgba(r, g, b, a) -> rgba_to_hsla(r, g, b, a)
+ }
+}
+
+/// Returns an rgba formatted CSS `String` created from the given `Colour`.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb255(255, 0, 0)
+/// let css_red = to_css_rgba_string(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_css_rgba_string(colour: Colour) -> String {
+ let #(r, g, b, a) = to_rgba(colour)
+
+ let percent = fn(x: Float) -> Float {
+ // This won't fail because we are always dividing by 100.0
+ let assert Ok(p) =
+ x
+ |> float.multiply(10_000.0)
+ |> float.round()
+ |> int.to_float()
+ |> float.divide(100.0)
+
+ p
+ }
+
+ let round_to = fn(x: Float) -> Float {
+ // This won't fail because we are always dividing by 1000.0
+ let assert Ok(r) =
+ x
+ |> float.multiply(1000.0)
+ |> float.round()
+ |> int.to_float()
+ |> float.divide(1000.0)
+
+ r
+ }
+
+ string.join(
+ [
+ "rgba(",
+ float.to_string(percent(r)) <> "%,",
+ float.to_string(percent(g)) <> "%,",
+ float.to_string(percent(b)) <> "%,",
+ float.to_string(round_to(a)),
+ ")",
+ ],
+ "",
+ )
+}
+
+/// Returns an rgba hex formatted `String` created from the given `Colour`.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0)
+/// let red_hex = to_rgba_hex_string(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_rgba_hex_string(colour: Colour) -> String {
+ to_rgba_hex(colour)
+ |> int.to_base16()
+}
+
+/// Returns an rgb hex formatted `String` created from the given `Colour`.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgba(255, 0, 0)
+/// let red_hex = to_rgb_hex_string(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_rgb_hex_string(colour: Colour) -> String {
+ to_rgb_hex(colour)
+ |> int.to_base16()
+}
+
+/// Returns an hex `Int` created from the given `Colour`.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0)
+/// let red_hex_int = to_rgba_hex(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_rgba_hex(colour: Colour) -> Int {
+ let #(r, g, b, a) = to_rgba(colour)
+
+ let red =
+ r *. 255.0
+ |> float.round()
+ |> int.bitwise_shift_left(24)
+
+ let green =
+ g *. 255.0
+ |> float.round()
+ |> int.bitwise_shift_left(16)
+
+ let blue =
+ b *. 255.0
+ |> float.round()
+ |> int.bitwise_shift_left(8)
+
+ let alpha =
+ a *. 255.0
+ |> float.round()
+
+ red + green + blue + alpha
+}
+
+/// Returns a rgb hex `Int` created from the given `Colour`.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgba(255, 0, 0)
+/// let red_hex_int = to_rgb_hex(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_rgb_hex(colour: Colour) -> Int {
+ let #(r, g, b, _) = to_rgba(colour)
+
+ let red =
+ r *. 255.0
+ |> float.round()
+ |> int.bitwise_shift_left(16)
+
+ let green =
+ g *. 255.0
+ |> float.round()
+ |> int.bitwise_shift_left(8)
+
+ let blue =
+ b *. 255.0
+ |> float.round()
+
+ red + green + blue
+}
+
+// COLOURS --------------------------------------------------------------------
+
+/// A `Colour` reprsenting the colour RGBA(239, 41, 41, 1.0)
+pub const light_red = Rgba(
+ r: 0.9372549019607843,
+ g: 0.1607843137254902,
+ b: 0.1607843137254902,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(204, 0, 0, 1.0)
+pub const red = Rgba(r: 0.8, g: 0.0, b: 0.0, a: 1.0)
+
+/// A `Colour` reprsenting the colour RGBA(164, 0, 0, 1.0)
+pub const dark_red = Rgba(r: 0.6431372549019608, g: 0.0, b: 0.0, a: 1.0)
+
+/// A `Colour` reprsenting the colour RGBA(252, 175, 62, 1.0)
+pub const light_orange = Rgba(
+ r: 0.9882352941176471,
+ g: 0.6862745098039216,
+ b: 0.24313725490196078,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(245, 121, 0, 1.0)
+pub const orange = Rgba(
+ r: 0.9607843137254902,
+ g: 0.4745098039215686,
+ b: 0.0,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(206, 92, 0, 1.0)
+pub const dark_orange = Rgba(
+ r: 0.807843137254902,
+ g: 0.3607843137254902,
+ b: 0.0,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(255, 233, 79, 1.0)
+pub const light_yellow = Rgba(
+ r: 1.0,
+ g: 0.9137254901960784,
+ b: 0.30980392156862746,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(237, 212, 0, 1.0)
+pub const yellow = Rgba(
+ r: 0.9294117647058824,
+ g: 0.8313725490196079,
+ b: 0.0,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(196, 160, 0, 1.0)
+pub const dark_yellow = Rgba(
+ r: 0.7686274509803922,
+ g: 0.6274509803921569,
+ b: 0.0,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(138, 226, 52, 1.0)
+pub const light_green = Rgba(
+ r: 0.5411764705882353,
+ g: 0.8862745098039215,
+ b: 0.20392156862745098,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(115, 210, 22, 1.0)
+pub const green = Rgba(
+ r: 0.45098039215686275,
+ g: 0.8235294117647058,
+ b: 0.08627450980392157,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(78, 154, 6, 1.0)
+pub const dark_green = Rgba(
+ r: 0.3058823529411765,
+ g: 0.6039215686274509,
+ b: 0.023529411764705882,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(114, 159, 207, 1.0)
+pub const light_blue = Rgba(
+ r: 0.4470588235294118,
+ g: 0.6235294117647059,
+ b: 0.8117647058823529,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(52, 101, 164, 1.0)
+pub const blue = Rgba(
+ r: 0.20392156862745098,
+ g: 0.396078431372549,
+ b: 0.6431372549019608,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(32, 74, 135, 1.0)
+pub const dark_blue = Rgba(
+ r: 0.12549019607843137,
+ g: 0.2901960784313726,
+ b: 0.5294117647058824,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(173, 127, 168, 1.0)
+pub const light_purple = Rgba(
+ r: 0.6784313725490196,
+ g: 0.4980392156862745,
+ b: 0.6588235294117647,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(117, 80, 123, 1.0)
+pub const purple = Rgba(
+ r: 0.4588235294117647,
+ g: 0.3137254901960784,
+ b: 0.4823529411764706,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(92, 53, 102, 1.0)
+pub const dark_purple = Rgba(
+ r: 0.3607843137254902,
+ g: 0.20784313725490197,
+ b: 0.4,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(233, 185, 110, 1.0)
+pub const light_brown = Rgba(
+ r: 0.9137254901960784,
+ g: 0.7254901960784313,
+ b: 0.43137254901960786,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(193, 125, 17, 1.0)
+pub const brown = Rgba(
+ r: 0.7568627450980392,
+ g: 0.49019607843137253,
+ b: 0.06666666666666667,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(143, 89, 2, 1.0)
+pub const dark_brown = Rgba(
+ r: 0.5607843137254902,
+ g: 0.34901960784313724,
+ b: 0.00784313725490196,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(0, 0, 0, 1.0)
+pub const black = Rgba(r: 0.0, g: 0.0, b: 0.0, a: 1.0)
+
+/// A `Colour` reprsenting the colour RGBA(255, 255, 255, 1.0)
+pub const white = Rgba(r: 1.0, g: 1.0, b: 1.0, a: 1.0)
+
+/// A `Colour` reprsenting the colour RGBA(238, 238, 236, 1.0)
+pub const light_grey = Rgba(
+ r: 0.9333333333333333,
+ g: 0.9333333333333333,
+ b: 0.9254901960784314,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(211, 215, 207, 1.0)
+pub const grey = Rgba(
+ r: 0.8274509803921568,
+ g: 0.8431372549019608,
+ b: 0.8117647058823529,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(186, 189, 182, 1.0)
+pub const dark_grey = Rgba(
+ r: 0.7294117647058823,
+ g: 0.7411764705882353,
+ b: 0.7137254901960784,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(238, 238, 236, 1.0)
+pub const light_gray = Rgba(
+ r: 0.9333333333333333,
+ g: 0.9333333333333333,
+ b: 0.9254901960784314,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(211, 215, 207, 1.0)
+pub const gray = Rgba(
+ r: 0.8274509803921568,
+ g: 0.8431372549019608,
+ b: 0.8117647058823529,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(186, 189, 182, 1.0)
+pub const dark_gray = Rgba(
+ r: 0.7294117647058823,
+ g: 0.7411764705882353,
+ b: 0.7137254901960784,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(136, 138, 133, 1.0)
+pub const light_charcoal = Rgba(
+ r: 0.5333333333333333,
+ g: 0.5411764705882353,
+ b: 0.5215686274509804,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(85, 87, 83, 1.0)
+pub const charcoal = Rgba(
+ r: 0.3333333333333333,
+ g: 0.3411764705882353,
+ b: 0.3254901960784314,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(46, 52, 54, 1.0)
+pub const dark_charcoal = Rgba(
+ r: 0.1803921568627451,
+ g: 0.20392156862745098,
+ b: 0.21176470588235294,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(255, 175, 243, 1.0)
+pub const pink = Rgba(
+ r: 1.0,
+ g: 0.6862745098039216,
+ b: 0.9529411764705882,
+ a: 1.0,
+)
diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam b/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam
new file mode 100644
index 0000000..54f75e4
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam
@@ -0,0 +1,173 @@
+////
+//// - **Accessibility**
+//// - [`luminance`](#luminance)
+//// - [`contrast_ratio`](#contrast_ratio)
+//// - [`maximum_contrast`](#maximum_contrast)
+////
+//// ---
+////
+//// This package was heavily inspired by the `elm-color-extra` module.
+//// The original source code can be found
+//// <a href="https://github.com/noahzgordon/elm-color-extra">here</a>.
+////
+//// <details>
+//// <summary>The license of that package is produced below:</summary>
+////
+////
+//// > MIT License
+////
+//// > Copyright (c) 2016 Andreas Köberle
+////
+//// > Permission is hereby granted, free of charge, to any person obtaining a copy
+//// of this software and associated documentation files (the "Software"), to deal
+//// in the Software without restriction, including without limitation the rights
+//// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//// copies of the Software, and to permit persons to whom the Software is
+//// furnished to do so, subject to the following conditions:
+////
+//// > The above copyright notice and this permission notice shall be included in all
+//// copies or substantial portions of the Software.
+////
+//// > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+//// SOFTWARE.
+////
+//// </details>
+////
+
+// Just in case we decide in the future to no longer include the above reference
+// and license, this package was initially a port of the `elm-color-extra` module:
+//
+// https://github.com/noahzgordon/elm-color-extra
+//
+
+// IMPORTS --------------------------------------------------------------------
+
+import gleam/float
+import gleam/list
+import gleam_community/colour.{type Colour}
+
+// UTILITIES ------------------------------------------------------------------
+
+fn intensity(colour_value: Float) -> Float {
+ // Calculation taken from https://www.w3.org/TR/WCAG20/#relativeluminancedef
+ case True {
+ _ if colour_value <=. 0.03928 -> colour_value /. 12.92
+ _ -> {
+ // Is this guaranteed to be `OK`?
+ let assert Ok(i) = float.power({ colour_value +. 0.055 } /. 1.055, 2.4)
+ i
+ }
+ }
+}
+
+// ACCESSIBILITY --------------------------------------------------------------
+
+/// Returns the relative brightness of the given `Colour` as a `Float` between
+/// 0.0, and 1.0 with 0.0 being the darkest possible colour and 1.0 being the lightest.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// luminance(colour.white) // 1.0
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn luminance(colour: Colour) -> Float {
+ // Calculation taken from https://www.w3.org/TR/WCAG20/#relativeluminancedef
+ let #(r, g, b, _) = colour.to_rgba(colour)
+
+ let r_intensity = intensity(r)
+ let g_intensity = intensity(g)
+ let b_intensity = intensity(b)
+
+ 0.2126 *. r_intensity +. 0.7152 *. g_intensity +. 0.0722 *. b_intensity
+}
+
+/// Returns the contrast between two `Colour` values as a `Float` between 1.0,
+/// and 21.0 with 1.0 being no contrast and, 21.0 being the highest possible contrast.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// contrast_ratio(between: colour.white, and: colour.black) // 21.0
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn contrast_ratio(between colour_a: Colour, and colour_b: Colour) -> Float {
+ // Calculation taken from https://www.w3.org/TR/WCAG20/#contrast-ratiodef
+ let luminance_a = luminance(colour_a) +. 0.05
+ let luminance_b = luminance(colour_b) +. 0.05
+
+ case luminance_a >. luminance_b {
+ True -> luminance_a /. luminance_b
+ False -> luminance_b /. luminance_a
+ }
+}
+
+/// Returns the `Colour` with the highest contrast between the base `Colour`,
+/// and and the other provided `Colour` values.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// maximum_contrast(
+/// colour.yellow,
+/// [colour.white, colour.dark_blue, colour.green],
+/// )
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn maximum_contrast(
+ base: Colour,
+ colours: List(Colour),
+) -> Result(Colour, Nil) {
+ colours
+ |> list.sort(fn(colour_a, colour_b) {
+ let contrast_a = contrast_ratio(base, colour_a)
+ let contrast_b = contrast_ratio(base, colour_b)
+
+ float.compare(contrast_b, contrast_a)
+ })
+ |> list.first()
+}
diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour.erl b/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour.erl
new file mode 100644
index 0000000..21e4c81
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour.erl
@@ -0,0 +1,511 @@
+-module(gleam_community@colour).
+-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
+
+-export([from_rgb255/3, from_rgb/3, from_rgba/4, from_hsla/4, from_hsl/3, from_rgb_hex/1, from_rgb_hex_string/1, from_rgba_hex/1, from_rgba_hex_string/1, to_rgba/1, to_hsla/1, to_css_rgba_string/1, to_rgba_hex/1, to_rgba_hex_string/1, to_rgb_hex/1, to_rgb_hex_string/1]).
+-export_type([colour/0]).
+
+-opaque colour() :: {rgba, float(), float(), float(), float()} |
+ {hsla, float(), float(), float(), float()}.
+
+-spec valid_colour_value(float()) -> {ok, float()} | {error, nil}.
+valid_colour_value(C) ->
+ case (C > 1.0) orelse (C < +0.0) of
+ true ->
+ {error, nil};
+
+ false ->
+ {ok, C}
+ end.
+
+-spec hue_to_rgb(float(), float(), float()) -> float().
+hue_to_rgb(Hue, M1, M2) ->
+ H = case Hue of
+ _ when Hue < +0.0 ->
+ Hue + 1.0;
+
+ _ when Hue > 1.0 ->
+ Hue - 1.0;
+
+ _ ->
+ Hue
+ end,
+ H_t_6 = H * 6.0,
+ H_t_2 = H * 2.0,
+ H_t_3 = H * 3.0,
+ case H of
+ _ when H_t_6 < 1.0 ->
+ M1 + (((M2 - M1) * H) * 6.0);
+
+ _ when H_t_2 < 1.0 ->
+ M2;
+
+ _ when H_t_3 < 2.0 ->
+ M1 + (((M2 - M1) * ((2.0 / 3.0) - H)) * 6.0);
+
+ _ ->
+ M1
+ end.
+
+-spec hex_string_to_int(binary()) -> {ok, integer()} | {error, nil}.
+hex_string_to_int(Hex_string) ->
+ Hex = case Hex_string of
+ <<"#"/utf8, Hex_number/binary>> ->
+ Hex_number;
+
+ <<"0x"/utf8, Hex_number@1/binary>> ->
+ Hex_number@1;
+
+ _ ->
+ Hex_string
+ end,
+ _pipe = Hex,
+ _pipe@1 = gleam@string:lowercase(_pipe),
+ _pipe@2 = gleam@string:to_graphemes(_pipe@1),
+ _pipe@3 = gleam@list:reverse(_pipe@2),
+ gleam@list:index_fold(
+ _pipe@3,
+ {ok, 0},
+ fun(Total, Char, Index) -> case Total of
+ {error, nil} ->
+ {error, nil};
+
+ {ok, V} ->
+ gleam@result:then(case Char of
+ <<"a"/utf8>> ->
+ {ok, 10};
+
+ <<"b"/utf8>> ->
+ {ok, 11};
+
+ <<"c"/utf8>> ->
+ {ok, 12};
+
+ <<"d"/utf8>> ->
+ {ok, 13};
+
+ <<"e"/utf8>> ->
+ {ok, 14};
+
+ <<"f"/utf8>> ->
+ {ok, 15};
+
+ _ ->
+ gleam@int:parse(Char)
+ end, fun(Num) ->
+ gleam@result:then(
+ gleam@int:power(16, gleam@int:to_float(Index)),
+ fun(Base) ->
+ {ok,
+ V + gleam@float:round(
+ gleam@int:to_float(Num) * Base
+ )}
+ end
+ )
+ end)
+ end end
+ ).
+
+-spec hsla_to_rgba(float(), float(), float(), float()) -> {float(),
+ float(),
+ float(),
+ float()}.
+hsla_to_rgba(H, S, L, A) ->
+ M2 = case L =< 0.5 of
+ true ->
+ L * (S + 1.0);
+
+ false ->
+ (L + S) - (L * S)
+ end,
+ M1 = (L * 2.0) - M2,
+ R = hue_to_rgb(H + (1.0 / 3.0), M1, M2),
+ G = hue_to_rgb(H, M1, M2),
+ B = hue_to_rgb(H - (1.0 / 3.0), M1, M2),
+ {R, G, B, A}.
+
+-spec rgba_to_hsla(float(), float(), float(), float()) -> {float(),
+ float(),
+ float(),
+ float()}.
+rgba_to_hsla(R, G, B, A) ->
+ Min_colour = gleam@float:min(R, gleam@float:min(G, B)),
+ Max_colour = gleam@float:max(R, gleam@float:max(G, B)),
+ H1 = case true of
+ _ when Max_colour =:= R ->
+ gleam@float:divide(G - B, Max_colour - Min_colour);
+
+ _ when Max_colour =:= G ->
+ _pipe = gleam@float:divide(B - R, Max_colour - Min_colour),
+ gleam@result:then(_pipe, fun(D) -> {ok, 2.0 + D} end);
+
+ _ ->
+ _pipe@1 = gleam@float:divide(R - G, Max_colour - Min_colour),
+ gleam@result:then(_pipe@1, fun(D@1) -> {ok, 4.0 + D@1} end)
+ end,
+ H2 = case H1 of
+ {ok, V} ->
+ {ok, V * (1.0 / 6.0)};
+
+ _ ->
+ H1
+ end,
+ H3 = case H2 of
+ {ok, V@1} when V@1 < +0.0 ->
+ V@1 + 1.0;
+
+ {ok, V@2} ->
+ V@2;
+
+ _ ->
+ +0.0
+ end,
+ L = (Min_colour + Max_colour) / 2.0,
+ S = case true of
+ _ when Min_colour =:= Max_colour ->
+ +0.0;
+
+ _ when L < 0.5 ->
+ case (Max_colour + Min_colour) of
+ 0.0 -> 0.0;
+ Gleam@denominator -> (Max_colour - Min_colour) / Gleam@denominator
+ end;
+
+ _ ->
+ case ((2.0 - Max_colour) - Min_colour) of
+ 0.0 -> 0.0;
+ Gleam@denominator@1 -> (Max_colour - Min_colour) / Gleam@denominator@1
+ end
+ end,
+ {H3, S, L, A}.
+
+-spec from_rgb255(integer(), integer(), integer()) -> {ok, colour()} |
+ {error, nil}.
+from_rgb255(Red, Green, Blue) ->
+ gleam@result:then(
+ begin
+ _pipe = Red,
+ _pipe@1 = gleam@int:to_float(_pipe),
+ _pipe@2 = gleam@float:divide(_pipe@1, 255.0),
+ gleam@result:then(_pipe@2, fun valid_colour_value/1)
+ end,
+ fun(R) ->
+ gleam@result:then(
+ begin
+ _pipe@3 = Green,
+ _pipe@4 = gleam@int:to_float(_pipe@3),
+ _pipe@5 = gleam@float:divide(_pipe@4, 255.0),
+ gleam@result:then(_pipe@5, fun valid_colour_value/1)
+ end,
+ fun(G) ->
+ gleam@result:then(
+ begin
+ _pipe@6 = Blue,
+ _pipe@7 = gleam@int:to_float(_pipe@6),
+ _pipe@8 = gleam@float:divide(_pipe@7, 255.0),
+ gleam@result:then(_pipe@8, fun valid_colour_value/1)
+ end,
+ fun(B) -> {ok, {rgba, R, G, B, 1.0}} end
+ )
+ end
+ )
+ end
+ ).
+
+-spec from_rgb(float(), float(), float()) -> {ok, colour()} | {error, nil}.
+from_rgb(Red, Green, Blue) ->
+ gleam@result:then(
+ valid_colour_value(Red),
+ fun(R) ->
+ gleam@result:then(
+ valid_colour_value(Green),
+ fun(G) ->
+ gleam@result:then(
+ valid_colour_value(Blue),
+ fun(B) -> {ok, {rgba, R, G, B, 1.0}} end
+ )
+ end
+ )
+ end
+ ).
+
+-spec from_rgba(float(), float(), float(), float()) -> {ok, colour()} |
+ {error, nil}.
+from_rgba(Red, Green, Blue, Alpha) ->
+ gleam@result:then(
+ valid_colour_value(Red),
+ fun(R) ->
+ gleam@result:then(
+ valid_colour_value(Green),
+ fun(G) ->
+ gleam@result:then(
+ valid_colour_value(Blue),
+ fun(B) ->
+ gleam@result:then(
+ valid_colour_value(Alpha),
+ fun(A) -> {ok, {rgba, R, G, B, A}} end
+ )
+ end
+ )
+ end
+ )
+ end
+ ).
+
+-spec from_hsla(float(), float(), float(), float()) -> {ok, colour()} |
+ {error, nil}.
+from_hsla(Hue, Saturation, Lightness, Alpha) ->
+ gleam@result:then(
+ valid_colour_value(Hue),
+ fun(H) ->
+ gleam@result:then(
+ valid_colour_value(Saturation),
+ fun(S) ->
+ gleam@result:then(
+ valid_colour_value(Lightness),
+ fun(L) ->
+ gleam@result:then(
+ valid_colour_value(Alpha),
+ fun(A) -> {ok, {hsla, H, S, L, A}} end
+ )
+ end
+ )
+ end
+ )
+ end
+ ).
+
+-spec from_hsl(float(), float(), float()) -> {ok, colour()} | {error, nil}.
+from_hsl(Hue, Saturation, Lightness) ->
+ from_hsla(Hue, Saturation, Lightness, 1.0).
+
+-spec from_rgb_hex(integer()) -> {ok, colour()} | {error, nil}.
+from_rgb_hex(Hex) ->
+ case (Hex > 16#ffffff) orelse (Hex < 0) of
+ true ->
+ {error, nil};
+
+ false ->
+ R = begin
+ _pipe = erlang:'bsr'(Hex, 16),
+ erlang:'band'(_pipe, 16#ff)
+ end,
+ G = begin
+ _pipe@1 = erlang:'bsr'(Hex, 8),
+ erlang:'band'(_pipe@1, 16#ff)
+ end,
+ B = erlang:'band'(Hex, 16#ff),
+ from_rgb255(R, G, B)
+ end.
+
+-spec from_rgb_hex_string(binary()) -> {ok, colour()} | {error, nil}.
+from_rgb_hex_string(Hex_string) ->
+ gleam@result:then(
+ hex_string_to_int(Hex_string),
+ fun(Hex_int) -> from_rgb_hex(Hex_int) end
+ ).
+
+-spec from_rgba_hex(integer()) -> {ok, colour()} | {error, nil}.
+from_rgba_hex(Hex) ->
+ case (Hex > 16#ffffffff) orelse (Hex < 0) of
+ true ->
+ {error, nil};
+
+ false ->
+ _assert_subject = begin
+ _pipe = erlang:'bsr'(Hex, 24),
+ _pipe@1 = erlang:'band'(_pipe, 16#ff),
+ _pipe@2 = gleam@int:to_float(_pipe@1),
+ gleam@float:divide(_pipe@2, 255.0)
+ end,
+ {ok, R} = case _assert_subject of
+ {ok, _} -> _assert_subject;
+ _assert_fail ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail,
+ module => <<"gleam_community/colour"/utf8>>,
+ function => <<"from_rgba_hex"/utf8>>,
+ line => 588})
+ end,
+ _assert_subject@1 = begin
+ _pipe@3 = erlang:'bsr'(Hex, 16),
+ _pipe@4 = erlang:'band'(_pipe@3, 16#ff),
+ _pipe@5 = gleam@int:to_float(_pipe@4),
+ gleam@float:divide(_pipe@5, 255.0)
+ end,
+ {ok, G} = case _assert_subject@1 of
+ {ok, _} -> _assert_subject@1;
+ _assert_fail@1 ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail@1,
+ module => <<"gleam_community/colour"/utf8>>,
+ function => <<"from_rgba_hex"/utf8>>,
+ line => 594})
+ end,
+ _assert_subject@2 = begin
+ _pipe@6 = erlang:'bsr'(Hex, 8),
+ _pipe@7 = erlang:'band'(_pipe@6, 16#ff),
+ _pipe@8 = gleam@int:to_float(_pipe@7),
+ gleam@float:divide(_pipe@8, 255.0)
+ end,
+ {ok, B} = case _assert_subject@2 of
+ {ok, _} -> _assert_subject@2;
+ _assert_fail@2 ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail@2,
+ module => <<"gleam_community/colour"/utf8>>,
+ function => <<"from_rgba_hex"/utf8>>,
+ line => 600})
+ end,
+ _assert_subject@3 = begin
+ _pipe@9 = erlang:'band'(Hex, 16#ff),
+ _pipe@10 = gleam@int:to_float(_pipe@9),
+ gleam@float:divide(_pipe@10, 255.0)
+ end,
+ {ok, A} = case _assert_subject@3 of
+ {ok, _} -> _assert_subject@3;
+ _assert_fail@3 ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail@3,
+ module => <<"gleam_community/colour"/utf8>>,
+ function => <<"from_rgba_hex"/utf8>>,
+ line => 606})
+ end,
+ from_rgba(R, G, B, A)
+ end.
+
+-spec from_rgba_hex_string(binary()) -> {ok, colour()} | {error, nil}.
+from_rgba_hex_string(Hex_string) ->
+ gleam@result:then(
+ hex_string_to_int(Hex_string),
+ fun(Hex_int) -> from_rgba_hex(Hex_int) end
+ ).
+
+-spec to_rgba(colour()) -> {float(), float(), float(), float()}.
+to_rgba(Colour) ->
+ case Colour of
+ {rgba, R, G, B, A} ->
+ {R, G, B, A};
+
+ {hsla, H, S, L, A@1} ->
+ hsla_to_rgba(H, S, L, A@1)
+ end.
+
+-spec to_hsla(colour()) -> {float(), float(), float(), float()}.
+to_hsla(Colour) ->
+ case Colour of
+ {hsla, H, S, L, A} ->
+ {H, S, L, A};
+
+ {rgba, R, G, B, A@1} ->
+ rgba_to_hsla(R, G, B, A@1)
+ end.
+
+-spec to_css_rgba_string(colour()) -> binary().
+to_css_rgba_string(Colour) ->
+ {R, G, B, A} = to_rgba(Colour),
+ Percent = fun(X) ->
+ _assert_subject = begin
+ _pipe = X,
+ _pipe@1 = gleam@float:multiply(_pipe, 10000.0),
+ _pipe@2 = gleam@float:round(_pipe@1),
+ _pipe@3 = gleam@int:to_float(_pipe@2),
+ gleam@float:divide(_pipe@3, 100.0)
+ end,
+ {ok, P} = case _assert_subject of
+ {ok, _} -> _assert_subject;
+ _assert_fail ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail,
+ module => <<"gleam_community/colour"/utf8>>,
+ function => <<"to_css_rgba_string"/utf8>>,
+ line => 704})
+ end,
+ P
+ end,
+ Round_to = fun(X@1) ->
+ _assert_subject@1 = begin
+ _pipe@4 = X@1,
+ _pipe@5 = gleam@float:multiply(_pipe@4, 1000.0),
+ _pipe@6 = gleam@float:round(_pipe@5),
+ _pipe@7 = gleam@int:to_float(_pipe@6),
+ gleam@float:divide(_pipe@7, 1000.0)
+ end,
+ {ok, R@1} = case _assert_subject@1 of
+ {ok, _} -> _assert_subject@1;
+ _assert_fail@1 ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail@1,
+ module => <<"gleam_community/colour"/utf8>>,
+ function => <<"to_css_rgba_string"/utf8>>,
+ line => 716})
+ end,
+ R@1
+ end,
+ gleam@string:join(
+ [<<"rgba("/utf8>>,
+ <<(gleam@float:to_string(Percent(R)))/binary, "%,"/utf8>>,
+ <<(gleam@float:to_string(Percent(G)))/binary, "%,"/utf8>>,
+ <<(gleam@float:to_string(Percent(B)))/binary, "%,"/utf8>>,
+ gleam@float:to_string(Round_to(A)),
+ <<")"/utf8>>],
+ <<""/utf8>>
+ ).
+
+-spec to_rgba_hex(colour()) -> integer().
+to_rgba_hex(Colour) ->
+ {R, G, B, A} = to_rgba(Colour),
+ Red = begin
+ _pipe = R * 255.0,
+ _pipe@1 = gleam@float:round(_pipe),
+ erlang:'bsl'(_pipe@1, 24)
+ end,
+ Green = begin
+ _pipe@2 = G * 255.0,
+ _pipe@3 = gleam@float:round(_pipe@2),
+ erlang:'bsl'(_pipe@3, 16)
+ end,
+ Blue = begin
+ _pipe@4 = B * 255.0,
+ _pipe@5 = gleam@float:round(_pipe@4),
+ erlang:'bsl'(_pipe@5, 8)
+ end,
+ Alpha = begin
+ _pipe@6 = A * 255.0,
+ gleam@float:round(_pipe@6)
+ end,
+ ((Red + Green) + Blue) + Alpha.
+
+-spec to_rgba_hex_string(colour()) -> binary().
+to_rgba_hex_string(Colour) ->
+ _pipe = to_rgba_hex(Colour),
+ gleam@int:to_base16(_pipe).
+
+-spec to_rgb_hex(colour()) -> integer().
+to_rgb_hex(Colour) ->
+ {R, G, B, _} = to_rgba(Colour),
+ Red = begin
+ _pipe = R * 255.0,
+ _pipe@1 = gleam@float:round(_pipe),
+ erlang:'bsl'(_pipe@1, 16)
+ end,
+ Green = begin
+ _pipe@2 = G * 255.0,
+ _pipe@3 = gleam@float:round(_pipe@2),
+ erlang:'bsl'(_pipe@3, 8)
+ end,
+ Blue = begin
+ _pipe@4 = B * 255.0,
+ gleam@float:round(_pipe@4)
+ end,
+ (Red + Green) + Blue.
+
+-spec to_rgb_hex_string(colour()) -> binary().
+to_rgb_hex_string(Colour) ->
+ _pipe = to_rgb_hex(Colour),
+ gleam@int:to_base16(_pipe).
diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl b/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl
new file mode 100644
index 0000000..64d37bf
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl
@@ -0,0 +1,73 @@
+-module(gleam_community@colour@accessibility).
+-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
+
+-export([luminance/1, contrast_ratio/2, maximum_contrast/2]).
+
+-spec intensity(float()) -> float().
+intensity(Colour_value) ->
+ case true of
+ _ when Colour_value =< 0.03928 ->
+ Colour_value / 12.92;
+
+ _ ->
+ _assert_subject = gleam@float:power(
+ (Colour_value + 0.055) / 1.055,
+ 2.4
+ ),
+ {ok, I} = case _assert_subject of
+ {ok, _} -> _assert_subject;
+ _assert_fail ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail,
+ module => <<"gleam_community/colour/accessibility"/utf8>>,
+ function => <<"intensity"/utf8>>,
+ line => 62})
+ end,
+ I
+ end.
+
+-spec luminance(gleam_community@colour:colour()) -> float().
+luminance(Colour) ->
+ {R, G, B, _} = gleam_community@colour:to_rgba(Colour),
+ R_intensity = intensity(R),
+ G_intensity = intensity(G),
+ B_intensity = intensity(B),
+ ((0.2126 * R_intensity) + (0.7152 * G_intensity)) + (0.0722 * B_intensity).
+
+-spec contrast_ratio(
+ gleam_community@colour:colour(),
+ gleam_community@colour:colour()
+) -> float().
+contrast_ratio(Colour_a, Colour_b) ->
+ Luminance_a = luminance(Colour_a) + 0.05,
+ Luminance_b = luminance(Colour_b) + 0.05,
+ case Luminance_a > Luminance_b of
+ true ->
+ case Luminance_b of
+ 0.0 -> 0.0;
+ Gleam@denominator -> Luminance_a / Gleam@denominator
+ end;
+
+ false ->
+ case Luminance_a of
+ 0.0 -> 0.0;
+ Gleam@denominator@1 -> Luminance_b / Gleam@denominator@1
+ end
+ end.
+
+-spec maximum_contrast(
+ gleam_community@colour:colour(),
+ list(gleam_community@colour:colour())
+) -> {ok, gleam_community@colour:colour()} | {error, nil}.
+maximum_contrast(Base, Colours) ->
+ _pipe = Colours,
+ _pipe@1 = gleam@list:sort(
+ _pipe,
+ fun(Colour_a, Colour_b) ->
+ Contrast_a = contrast_ratio(Base, Colour_a),
+ Contrast_b = contrast_ratio(Base, Colour_b),
+ gleam@float:compare(Contrast_b, Contrast_a)
+ end
+ ),
+ gleam@list:first(_pipe@1).
diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community_colour.app.src b/aoc2023/build/packages/gleam_community_colour/src/gleam_community_colour.app.src
new file mode 100644
index 0000000..a327650
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community_colour.app.src
@@ -0,0 +1,9 @@
+{application, gleam_community_colour, [
+ {vsn, "1.2.0"},
+ {applications, [gleam_stdlib,
+ gleeunit]},
+ {description, "Colour types, conversions, and other utilities"},
+ {modules, [gleam_community@colour,
+ gleam_community@colour@accessibility]},
+ {registered, []}
+]}.