csos95's recent activity
-
Comment on Day 9: Disk Fragmenter in ~comp.advent_of_code
-
Comment on Day 8: Resonant Collinearity in ~comp.advent_of_code
csos95 Another easy day and one that didn't have Rhai's performance hurting me with the solution I came up with. I was really expecting tonight's to add onto day 3's. I'm starting to wonder if any...Another easy day and one that didn't have Rhai's performance hurting me with the solution I came up with.
I was really expecting tonight's to add onto day 3's.
I'm starting to wonder if any Intcode-like thing is coming, I was really looking forward to it.Rhai Solution
import "utils" as utils; let input = utils::get_input(8, false); let grid = new_grid(input.split("\n").map(|line| line.to_chars())); let antennas = #{}; for pos in grid.cell_positions() { let cell = grid.cell(pos).to_string(); if cell == "." { continue; } let positions = antennas.get(cell) ?? []; positions.push(pos); antennas.set(cell, positions); } // PART 1 let antinodes = #{}; for frequency in antennas.keys() { let positions = antennas.get(frequency); for pair in positions.combinations(2) { let diff = new_point(pair[0].x - pair[1].x, pair[0].y - pair[1].y); for point in [pair[0] - diff, pair[0] + diff, pair[1] - diff, pair[1] + diff] { if point == pair[0] || point == pair[1] || !grid.is_valid(point) { continue; } antinodes.set(point.to_string(), true); } } } print(`part 1: ${antinodes.len()}`); // PART 2 let antinodes = #{}; for frequency in antennas.keys() { let positions = antennas.get(frequency); for pair in positions.combinations(2) { let diff = new_point(pair[0].x - pair[1].x, pair[0].y - pair[1].y); for situation in 0..4 { let point = switch situation { 0 | 1 => pair[0], 2 | 3 => pair[1], }; loop { if !grid.is_valid(point) { break; } antinodes.set(point.to_string(), true); switch situation { 0 | 2 => point -= diff, 1 | 3 => point += diff, } } } } } print(`part 2: ${antinodes.len()}`);
-
Comment on Day 7: Bridge Repair in ~comp.advent_of_code
csos95 (edited )LinkTonight's was really easy compared to last night's (at least compared to my attempt at a non-brute for solution to that using graphs). Most of the time it took me to do part one was just searching...Tonight's was really easy compared to last night's (at least compared to my attempt at a non-brute for solution to that using graphs).
Most of the time it took me to do part one was just searching for the right iterator combination in itertools and most of the time to do part two was runtime (this is the second night Rhai's low performance showed up, 2:08 runtime).Rhai Solution
import "utils" as utils; let input = utils::get_input(7, false).split("\n").map(|line| { let parts = line.split(":"); let solution = parts[0].parse_int(); parts[1].trim(); let values = parts[1].split(" ").map(|v| v.parse_int()); #{solution: solution, values: values} }); let total = 0; for equation in input { let values = equation.values; let op_sets = ["+", "*"].permutations_with_replacement(values.len()-1); for ops in op_sets { let value = values[0]; for (op, i) in ops { switch op { "+" => value += values[i + 1], "*" => value *= values[i + 1], } } if value == equation.solution { total += value; break; } } } print(`part 1: ${total}`); let total = 0; for equation in input { let values = equation.values; let op_sets = ["+", "*", "||"].permutations_with_replacement(values.len()-1); for ops in op_sets { let value = values[0]; for (op, i) in ops { switch op { "+" => value += values[i + 1], "*" => value *= values[i + 1], "||" => value = `${value}${values[i + 1]}`.parse_int(), } } if value == equation.solution { total += value; break; } } } print(`part 2: ${total}`);
-
Comment on Day 6: Guard Gallivant in ~comp.advent_of_code
csos95 (edited )LinkPart two was rough. I had a nice solution, but it didn't work for the full input. I worked on it for a while, but eventually gave up and did a brute force solution. While it was running, I...Part two was rough.
I had a nice solution, but it didn't work for the full input.
I worked on it for a while, but eventually gave up and did a brute force solution.
While it was running, I realized why my nice solution wouldn't work in all cases.
And the extension to make it work is a lesser brute-force, but I also have to juggle a bunch of extra temporary state.This is the first one where the performance of Rhai really reared its head (not only is it a tree-walk interpreter, it passes everything by value).
It took 7:48 to run part two.I'll likely come back later and clean it up with a better solution.
I have a few ideas for what to do better, but I'm a bit tired and salty at the moment.Rhai Solution
import "utils" as utils; let input = utils::get_input(6, false); // AUXILIARY fn next_dir(dir) { switch dir { "up" => "right", "right" => "down", "down" => "left", "left" => "up", } } fn dir_offset(dir) { switch dir { "up" => new_point(0, -1), "down" => new_point(0, 1), "left" => new_point(-1, 0), "right" => new_point(1, 0), } } // PART 1 let grid = new_grid(input.split("\n").map(|line| line.to_chars())); let guard_pos = (); let guard_dir = (); for item in grid.cells().zip(grid.cell_positions()) { if item[0] == '^' { guard_dir = "up"; } if item[0] == 'v' { guard_dir = "down"; } if item[0] == '<' { guard_dir = "left"; } else if item[0] == '>' { guard_dir = "right"; } if guard_dir != () { guard_pos = item[1]; grid.set_cell(guard_pos, 'X'); break; } } while grid.is_valid(guard_pos) { let offset = dir_offset(guard_dir); if grid.cell(guard_pos + offset) != '#' { guard_pos = guard_pos + offset; grid.set_cell(guard_pos, 'X'); } else { guard_dir = next_dir(guard_dir); } } let total = 0; for cell in grid.cells() { if cell == 'X' { total += 1; } } print(`part 1: ${total}`); // PART 2 let prev_grid = grid; let grid = new_grid(input.split("\n").map(|line| line.to_chars())); let guard_pos = (); let guard_dir = (); for item in grid.cells().zip(grid.cell_positions()) { if item[0] == '^' { guard_dir = "up"; } if item[0] == 'v' { guard_dir = "down"; } if item[0] == '<' { guard_dir = "left"; } else if item[0] == '>' { guard_dir = "right"; } if guard_dir != () { guard_pos = item[1]; grid.set_cell(guard_pos, '.'); break; } } let total = 0; let original_guard_pos = guard_pos; let original_guard_dir = guard_dir; for pos in grid.cell_positions() { if (pos.x == original_guard_pos.x && pos.y == original_guard_pos.y) || prev_grid.cell(pos) != 'X' { continue; } guard_pos = original_guard_pos; guard_dir = original_guard_dir; let graph = new_graph(); let point_to_node = #{}; point_to_node[`${guard_pos}-${guard_dir}`] = graph.add_node(0.0); grid.set_cell(pos, '#'); let found = false; let prev_node = point_to_node[`${guard_pos}-${guard_dir}`]; let curr_node = (); while grid.is_valid(guard_pos) { let offset = dir_offset(guard_dir); if grid.cell(guard_pos + offset) != '#' { guard_pos = guard_pos + offset; } else { guard_dir = next_dir(guard_dir); } curr_node = point_to_node[`${guard_pos}-${guard_dir}`]; if curr_node == () { curr_node = graph.add_node(0.0); point_to_node[`${guard_pos}-${guard_dir}`] = curr_node; } if !graph.contains_edge(prev_node, curr_node) { graph.add_edge(prev_node, curr_node, 0.0); } if graph.is_cyclic_directed() { found = true; break; } prev_node = curr_node; } if found { total += 1; } grid.set_cell(pos, '.'); } print(`part 2: ${total}`);
-
Comment on Day 5: Print Queue in ~comp.advent_of_code
csos95 (edited )LinkThis one really tripped me up. When I read the challenge, the first thing that popped into my head was "oh! A graph problem!" and I set to work adding an interface to the petgraph library. After...This one really tripped me up.
When I read the challenge, the first thing that popped into my head was "oh! A graph problem!" and I set to work adding an interface to the petgraph library.
After finishing it, getting all the data inserted with pages as nodes and rules as edges, I did a topological sort on the graph to get an ordering of all pages so I could just check that each page in an update has a higher index than the previous one.I ran it on the example input and it worked perfectly!
Then I ran it on the actual input and it errored!
There was a cycle somewhere!I tried using a few functions to find the page cycle (the error only returns the node it was at when it found a cylce), but couldn't figure it out.
However, while looking at the input, I realized that I didn't even need to use a graph to begin with.
The rules had relations between relevant pages directly, I didn't need to check transitive rules.I'd already gone through the trouble of building a graph so I went ahead and used it for the simpler problem of checking if two pages have a rule.
Rhai Solution
import "utils" as utils; let input = utils::get_input(5, false).split("\n\n"); let ordering_rules = input[0] .split("\n") .map(|line| line .split("|") .map(|id| id.parse_int())); let page_updates = input[1] .split("\n") .map(|line| line .split(",") .map(|id| id.parse_int())); // get all page numbers, deduplicated let pages = []; for rule in ordering_rules { pages.push(rule[0]); pages.push(rule[1]); } for update in page_updates { for page in update { pages.push(page); } } pages.sort(); pages.dedup(); // add a node for each page and keep a mapping of page to node and vice versa let page_graph = new_graph(); let page_to_node = new_int_map(); let node_to_page = new_int_map(); for page in pages { let node = page_graph.add_node(0.0); page_to_node[page] = node; node_to_page[node.index()] = page; } // add ordering rules as nodes for rule in ordering_rules { if rule[0] != rule[1] { page_graph.add_edge(page_to_node[rule[0]], page_to_node[rule[1]], 0.0); } } // PART 1 let total = 0; for update in page_updates { // print(update); let valid = true; for i in 0..update.len()-1 { if page_graph.contains_edge(page_to_node[update[i+1]], page_to_node[update[i]]) { valid = false; break; } } if valid { total += update[update.len() / 2]; } } print(`part 1: ${total}`); // PART 2 let total = 0; for update in page_updates { let valid = true; for i in 0..update.len()-1 { if page_graph.contains_edge(page_to_node[update[i+1]], page_to_node[update[i]]) { valid = false; break; } } if !valid { let i = 0; while i < update.len()-1 { if page_graph.contains_edge(page_to_node[update[i+1]], page_to_node[update[i]]) { let a = update[i]; update[i] = update[i+1]; update[i+1] = a; i = 0; } else { i += 1; } } total += update[update.len() / 2]; } } print(`part 2: ${total}`);
Edit: I found out from a reddit post why the cycle caused me issues with topological sort, but not in the other solution.
Excerpt from the challenge:
The notation X|Y means that if both page number X and page number Y are to be produced as part of an update, page number X must be printed at some point before page number Y.
The cycle never appears among the pages for a given update.
-
Comment on Misogynist hacker who threatened the wrong woman (hacker) and found out in ~comp
csos95 It loads the rest of the article with Javascript after about ten seconds with no indication that it's not the entire article and there's more to load.It loads the rest of the article with Javascript after about ten seconds with no indication that it's not the entire article and there's more to load.
-
Comment on Day 4: Ceres Search in ~comp.advent_of_code
csos95 (edited )LinkMy initial solution isn't as nice as I'd like it to be, but it works. I might go back over it tomorrow and add some functions to my utils module to make working with grids easier. Rhai Solution...My initial solution isn't as nice as I'd like it to be, but it works.
I might go back over it tomorrow and add some functions to my utils module to make working with grids easier.Rhai Solution
import "utils" as utils; let input = utils::get_input(4, false); let grid = input.split("\n").map(|line| line.to_chars()); let height = grid.len(); let width = grid[0].len(); let total = 0; for y in 0..height { for x in 0..width { for vy in range(-1, 2, 1) { for vx in range(-1, 2, 1) { if vy == 0 && vx == 0 { continue; } if has_xmas!(x, y, vx, vy) { total += 1; } } } } } fn has_xmas(x, y, vx, vy) { x+vx*3 < width && y+vy*3 < height && x+vx*3 >= 0 && y+vy*3 >= 0 &&grid[y][x] == 'X' && grid[y+vy*1][x+vx*1] == 'M' && grid[y+vy*2][x+vx*2] == 'A' && grid[y+vy*3][x+vx*3] == 'S' } print(`part 1: ${total}`); let total = 0; for y in 0..height { for x in 0..width { if grid[y][x] != 'A' || x-1 < 0 || x+1 >= width || y-1 < 0 || y+1 >= height { continue; } let first_diag = grid[y-1][x-1] + grid[y][x] + grid[y+1][x+1]; let second_diag = grid[y-1][x+1] + grid[y][x] + grid[y+1][x-1]; if (first_diag == "MAS" || first_diag == "SAM") && (second_diag == "MAS" || second_diag == "SAM") { total += 1; } } } print(`part 2: ${total}`);
Edit: I added grid and point types and redid my solution using them.
Rhai Solution
import "utils" as utils; let input = utils::get_input(4, false); let grid = new_grid(input.split("\n").map(|line| line.to_chars())); let total = 0; for position in grid.cell_positions() { for offset in neighbor_offsets() { if has_xmas!(position, offset) { total += 1; } } } fn has_xmas(point, dp) { grid.is_valid(point + dp * 3) && grid.cell(point) == 'X' && grid.cell(point + dp) == 'M' && grid.cell(point + dp * 2) == 'A' && grid.cell(point + dp * 3) == 'S' } print(`part 1: ${total}`); let total = 0; for pos in grid.cell_positions() { if grid.cell(pos) != 'A' || !grid.is_valid(pos - 1) || !grid.is_valid(pos + 1) { continue; } let first_diag = grid.cell(pos - 1) + grid.cell(pos) + grid.cell(pos + 1); let second_diag = grid.cell(pos + new_point(1, -1)) + grid.cell(pos) + grid.cell(pos + new_point(-1, 1)); if first_diag in ["MAS", "SAM"] && second_diag in ["MAS", "SAM"] { total += 1; } } print(`part 2: ${total}`);
-
Comment on Day 3: Mull It Over in ~comp.advent_of_code
csos95 That was my first thought when I read the challenge and I'm looking forward to it!That was my first thought when I read the challenge and I'm looking forward to it!
-
Comment on Day 3: Mull It Over in ~comp.advent_of_code
csos95 (edited )LinkI'm pretty tired tonight (finally remembered to drag myself to the gym a few hours after dinner) so my initial solution is a bit less compact than it could be. I'll probably go back over it...I'm pretty tired tonight (finally remembered to drag myself to the gym a few hours after dinner) so my initial solution is a bit less compact than it could be.
I'll probably go back over it tomorrow and also write a few functions for my utils module.Rhai Solution
import "utils" as utils; let input = utils::get_input(3, false); // PART 1 let total = 0; for (section, i) in input.split("mul(").extract(1) { let possible_params = section.split(")"); if possible_params.len() < 2 { continue; } let possible_digits = possible_params[0].split(","); if possible_digits.len() != 2 || possible_digits[0].to_chars().some(|c| c < '0' || c > '9') || possible_digits[1].to_chars().some(|c| c < '0' || c > '9') { continue; } let x = possible_digits[0].parse_int(); let y = possible_digits[1].parse_int(); total += x * y; } print(`part 1: ${total}`); // PART 2 let total = 0; let enabled = true; for (section, i) in input.split("mul(") { if enabled && i != 0 { let possible_params = section.split(")"); if possible_params.len() < 2 { continue; } let possible_digits = possible_params[0].split(","); if possible_digits.len() != 2 || possible_digits[0].to_chars().some(|c| c < '0' || c > '9') || possible_digits[1].to_chars().some(|c| c < '0' || c > '9') { continue; } let x = possible_digits[0].parse_int(); let y = possible_digits[1].parse_int(); total += x * y; } if enabled && section.contains("don't()") { enabled = false; } if !enabled && section.contains("do()") { enabled = true; } } print(`part 2: ${total}`);
My current utils.rhai
fn get_input(day, example) { if example { let input = open_file(`day${day}_example.txt`) .read_string(); input.trim(); input } else { let input = open_file(`day${day}.txt`) .read_string(); input.trim(); input } } fn is_sorted(array) { for i in 0..array.len()-1 { if array[i] > array[i+1] { return false; } } true } fn is_rev_sorted(array) { for i in range(array.len()-1, 0, -1) { if array[i] > array[i-1] { return false; } } true } fn is_ordered(array) { let fails = 0; for i in 0..array.len()-1 { if array[i] > array[i+1] { fails += 1; break; } } for i in range(array.len()-1, 0, -1) { if array[i] > array[i-1] { fails += 1; break; } } fails < 2 }
Edit: I added basic regex to Rhai with
new_regex(regex_string)
andcaptures(Regex, input)
functions using the regex crate and made a shorter solution.Rhai Solution
import "utils" as utils; let input = utils::get_input(3, false); // PART 1 let total = 0; let regex = new_regex(#"mul\(([0-9]+),([0-9]+)\)"#); for captures in regex.captures(input) { let x = captures[1].parse_int(); let y = captures[2].parse_int(); total += x * y; } print(`part 1: ${total}`); // PART 2 let total = 0; let enabled = true; let regex = new_regex(#"(mul|do|don't)\((?:([0-9]+),([0-9]+))?\)"#); for captures in regex.captures(input) { switch captures[1] { "don't" => enabled = false, "do" => enabled = true, "mul" if enabled => { let x = captures[2].parse_int(); let y = captures[3].parse_int(); total += x * y; } } } print(`part 2: ${total}`);
-
Comment on Day 2: Red-Nosed Reports in ~comp.advent_of_code
csos95 (edited )LinkToday's took me a bit longer for the second part because I misunderstood the change and for some reason thought if there was a single bad level I could simply remove it without checking if the new...Today's took me a bit longer for the second part because I misunderstood the change and for some reason thought if there was a single bad level I could simply remove it without checking if the new report is safe.
Once I realized my mistake it was pretty straightforward.
My only real annoyance with Rhai so far is that there's no good mode for emacs for it.
I found an old one someone made, but the way it handles the indentations is really janky.
It seems like it's sort of trying to line the indentation up with the first letter of the second token on the line above and if that fails, it just does a massive amount of indentation.
So I've got anywhere from two to four spaces of indentation depending on the line.Rhai Code
fn get_input(day, example) { if example { let input = open_file(`day${day}_example.txt`) .read_string(); input.trim(); input } else { let input = open_file(`day${day}.txt`) .read_string(); input.trim(); input } } // INPUT let input = get_input(2, false); let reports = []; for line in input.split("\n") { let report = []; for level in line.split() { report.push(level.parse_int()); } reports.push(report); } // AUXILIARY fn is_decreasing(report) { if report.len() < 2 { true } else { report[0] > report[1] && is_decreasing(report.extract(1)) } } fn is_increasing(report) { if report.len() < 2 { true } else { report[0] < report[1] && is_increasing(report.extract(1)) } } fn is_gradual(report) { if report.len() < 2 { true } else { let diff = (report[0] - report[1]).abs(); diff > 0 && diff < 4 && is_gradual(report.extract(1)) } } // PART 1 let safe = 0; for report in reports { if (is_decreasing(report) || is_increasing(report)) && is_gradual(report) { safe += 1; } } print(`part 1: ${safe}`); // PART 2 let safe = 0; for report in reports { if (is_decreasing(report) || is_increasing(report)) && is_gradual(report) { safe += 1; } else { for i in 0..report.len() { let report_copy = report; report_copy.remove(i); if (is_decreasing(report_copy) || is_increasing(report_copy)) && is_gradual(report_copy) { safe += 1; break; } } } } print(`part 2: ${safe}`);
Edit: I made it more compact and moved the
get_input
function to a separate file since it'll be used every day.Rhai Code
import "utils" as utils; // INPUT let reports = utils::get_input(2, false) .split("\n") .map(|report| report .split() .map(|l| l.parse_int())); // AUXILIARY fn is_safe_inner(report, last_diff) { if report.len() < 2 { return true; } let diff = report[0] - report[1]; let diff_abs = diff.abs(); if last_diff != () && last_diff * diff < 0 { return false; } diff_abs > 0 && diff_abs < 4 && is_safe_inner(report.extract(1), diff) } fn is_safe(report) { is_safe_inner(report, ()) } // PART 1 let safe = reports.filter(is_safe).len(); print(`part 1: ${safe}`); // PART 2 let safe = reports.filter(|report| { if is_safe(report) { return true; } else { for i in 0..report.len() { let report = report; report.remove(i); if is_safe(report) { return true; } } } false }).len(); print(`part 2: ${safe}`);
-
Comment on Day 1: Historian Hysteria in ~comp.advent_of_code
csos95 This year I'm doing Advent of Code in rhai, an embedded scripting language for rust, because I've been meaning to try it out for a while. It's not amazing speed-wise because it's a treewalk...This year I'm doing Advent of Code in rhai, an embedded scripting language for rust, because I've been meaning to try it out for a while.
It's not amazing speed-wise because it's a treewalk interpreter, but it has a lot of nice features such as many safety options for when you need to run untrusted code, custom operators/syntax, and a decent api for making rust types and functions usable within it.
I initially did it using the built-in object map type, but it seems to only support string keys and I was annoyed that I had to convert the integer keys I had with every get and set.
I could've just re-processed the input to have the values as strings again and not need to do any conversion, but I'm almost certainly going to need to use integer keys more than once so I added anHashMap<INT, Dynamic>
type namedIntMap
to Rhai.It was very easy to get started with, I had no trouble finding the methods I needed in the docs to complete the initial challenge or for creating the
IntMap
type and methods.
I'm quite impressed with how easy it was to extend.Rhai Code
fn get_input(day) { let input = open_file(`day${day}.txt`) .read_string(); input.trim(); input } let input = get_input(1); // PART 1 let list1 = []; let list2 = []; for line in input.split("\n") { let items = line.split(); list1.push(items[0].parse_int()); list2.push(items[1].parse_int()); } list1.sort(); list2.sort(); let total = 0; for i in 0..list1.len() { total += (list1[i] - list2[i]).abs(); } print(`part1: ${total}`); // PART 2 let list2_occurrences = new_int_map(); for location in list2 { let prev = list2_occurrences[location] ?? 0; list2_occurrences[location] = prev + 1; } let total = 0; for location in list1 { let occurrences = list2_occurrences[location] ?? 0; total += location * occurrences; } print(`part2: ${total}`);
-
Comment on How do you build strong online communities? in ~talk
csos95 Every funeral I've been to (which isn't a ton, but it's more than a few) has had plenty of jokes told. Everyone grieves differently, but if I were at a funeral with zero jokes told I'd probably...I mean if you tell a joke at a funeral you cannot read the room.
Every funeral I've been to (which isn't a ton, but it's more than a few) has had plenty of jokes told.
Everyone grieves differently, but if I were at a funeral with zero jokes told I'd probably wonder if anyone around even liked the person or ever had any good times with them. -
Comment on Any recommendations for books, novellas and short story collections? in ~books
csos95 I recently read The Dispatcher by John Scalzi and enjoyed it.I recently read The Dispatcher by John Scalzi and enjoyed it.
In the wake of an unexplained phenomenon worldwide — when people are deliberately killed, they almost always disappear from their site of death and reappear, reset to several hours earlier, in a safe place — the profession of "Dispatcher" evolves. Dispatchers euthanize mortally-injured people before their natural deaths, enabling them to reset. Tony Valdez is a Dispatcher recruited by the police to assist in investigating the disappearance of another Dispatcher.
-
Comment on Tildes Book Club - Spring 2025 nomination thread - Books from minority or diverse or disadvantaged perspectives in ~books
csos95 (edited )LinkBorn a Crime: Stories from a South African Childhood by Trevor Noah.Born a Crime: Stories from a South African Childhood by Trevor Noah.
The book details Trevor Noah's experiences growing up in South Africa during the apartheid era. Noah's parents were a white Swiss-German father and a black Xhosa mother. At the time of Noah's birth in 1984, their interracial relationship was illegal under the Immorality Act, 1957. According to Noah, "for [him] to be born as a mixed-race baby" was to be "born a crime." Interracial relations were decriminalised when the Immorality Act was amended in 1985. As a mixed-race person, Noah was classified as a "Coloured" in accordance to the apartheid system of racial classification. Noah was raised primarily by his mother and maternal grandmother in Soweto.
-
Comment on A pregnant teenager died after trying to get care in three visits to Texas emergency rooms in ~society
csos95 It was Justice Thomas’ concurring opinion on the case. https://www.law.cornell.edu/supremecourt/text/19-1392#writing-19-1392_CONCUR_5 Relevant pragraph:I can't find a reference to it right now, but there was a whole list of decisions he was suggesting could be overturned, including gay and trans rights.
It was Justice Thomas’ concurring opinion on the case.
https://www.law.cornell.edu/supremecourt/text/19-1392#writing-19-1392_CONCUR_5Relevant pragraph:
For that reason, in future cases, we should reconsider all of this Court’s substantive due process precedents, including Griswold, Lawrence, and Obergefell. Because any substantive due process decision is “demonstrably erroneous,” Ramos v. Louisiana, 590 U. S. ___, ___ (2020) (Thomas, J., concurring in judgment) (slip op., at 7), we have a duty to “correct the error” established in those precedents, Gamble v. United States, 587 U. S. ___, ___ (2019) (Thomas, J., concurring) (slip op., at 9). After overruling these demonstrably erroneous decisions, the question would remain whether other constitutional provisions guarantee the myriad rights that our substantive due process cases have generated. For example, we could consider whether any of the rights announced in this Court’s substantive due process cases are “privileges or immunities of citizens of the United States” protected by the Fourteenth Amendment. Amdt. 14, §1; see McDonald, 561 U. S., at 806 (opinion of Thomas, J.). To answer that question, we would need to decide important antecedent questions, including whether the Privileges or Immunities Clause protects any rights that are not enumerated in the Constitution and, if so, how to identify those rights. See id., at 854. That said, even if the Clause does protect unenumerated rights, the Court conclusively demonstrates that abortion is not one of them under any plausible interpretive approach. See ante, at 15, n. 22.
-
Comment on Star Trek: Strange New Worlds | Season 3 NYCC exclusive clip in ~tv
csos95 They're from season 20 of South Park. They're talking fruit that look a bit like grapes that cause people to feel nostalgic about stuff with comments in the form of "Member X?". They start out...They're from season 20 of South Park.
They're talking fruit that look a bit like grapes that cause people to feel nostalgic about stuff with comments in the form of "Member X?".
They start out making comments about Star Wars, but as the season goes on they throw out more and more bigoted comments like "Member when there weren't so many Mexicans?"I can't remember specifically how the season ended, but I think it was something to do with the election, the memberberries being the big bad pulling the strings and creating a change in society that made Mr. Garrison (who acts as Trump stand-in in South Park) popular, and then they just sort of disappeared because the writers didn't plan for Trump actually winning.
I assume they just mean the "nostalgia bait" part and not the latter bit in their comment.
-
Comment on Intuit is shutting down the personal finance service Mint and shifting users to Credit Karma in ~finance
csos95 There was a new comment: https://tildes.net/~finance/1btc/intuit_is_shutting_down_the_personal_finance_service_mint_and_shifting_users_to_credit_karma#comment-cxn5 For future reference, the topic...There was a new comment: https://tildes.net/~finance/1btc/intuit_is_shutting_down_the_personal_finance_service_mint_and_shifting_users_to_credit_karma#comment-cxn5
For future reference, the topic log on the right sidebar (if you’re on mobile you can open it by clicking the “sidebar” link on the top right of the page) shows when the last comment was made and links to it.
So for me right now it shows
Last comment posted
7m ago -
Comment on Database schema for an upcoming comment hosting system in ~comp
csos95 Here is the documentation on strict tables. I haven't bothered to use them because I do all my stuff in rust (usually with diesel) and have strong type checking to prevent me from using the wrong...Here is the documentation on
strict
tables.
I haven't bothered to use them because I do all my stuff in rust (usually with diesel) and have strong type checking to prevent me from using the wrong type by accident.but not sure even referential integrity is maintained by Sqlite unless we use the strict mode?
Strict tables are unrelated to foreign key constraints.
The default for SQLite (another one of those "backwards compatibility" oddities) is to not enforce foreign key constraints.
You have to enable it with apragma
statement:pragma foreign_keys = on;
A full list of pragma statements is available here.I usually use
journal_mode = wal
,synchronous = normal
,foreign_keys = on
, andbusy_timeout = SOME_TIMEOUT_IN_MS
in my projects.
This will use a write ahead log for writes (much faster and makes it so readers and writers (still limited to one writer at a time though) do not block each other), make it do less syncing to the filesystem, enable foreign key checking, and automatically waits if a table is locked with a defaultbusy_handler
.Something to note for that last option is that it mostly will take care of
database is locked
errors that occur when you try to read/write when the needed table is locked.
The one case it doesn't cover is when adeferred
transaction (the default) is "upgraded" to a write transaction.
In this case, if a needed table is locked, it will immediately error instead of using thebusy_handler
.
So if you use transactions, you should make themimmediate
when you are going to be writing.
Ex:begin immediate transaction
Transactions documentation here -
Comment on Database schema for an upcoming comment hosting system in ~comp
csos95 Adding to what unkz said, php has built-in functions for secure password hashing and verification. password_hash and password_verify.Adding to what unkz said, php has built-in functions for secure password hashing and verification.
password_hash and password_verify. -
Comment on Database schema for an upcoming comment hosting system in ~comp
csos95 (edited )LinkSomething to be aware of is that in SQLite the types are more of a hint for how to store the data for a column rather than a constraint. You can store any type of data in any type of column...Something to be aware of is that in SQLite the types are more of a hint for how to store the data for a column rather than a constraint.
You can store any type of data in any type of column (unless you specifically usestrict
tables).
It will attempt to convert the data to the storage class indicated by the column type used, but if it fails it will store the data as is.
This page of the SQLite documentation explains this in detail.
I come back to it often to remind myself of what column types are associated with what affinities.Additionally, the numeric parameters on types are ignored.
So a column of typevarchar(255)
will store a 300 character string without complaint.
To add a constraint on the length you need to add acheck
constraint to the end.
So instead ofname varchar(255) not null
, you can doname text not null check(length(name) <= 255)
(I generally prefer using the five affinity type names so I don't have to remember the exact rules for affinity mapping).EDIT: I just noticed you have two primary keys set for the
comments
table.
That won't work.
Theid
column should probably be defined asid integer primary key autoincrement
and theuser_id
should be defined asuser_id integer not null references users(id)
.
Theautoincrement
preventsrowid
s from being reused in certain situations and isn't strictly necessary, but I always use it to be safe because it doesn't really affect performance for anything I've used SQLite for.
Additionally if you ever want to have a primary key that isn'tinteger
(which is a special case that maps to therowid
), you need to addnot null
to it.
Otherwise you could end up with every row having aNULL
id.
This is because of two issues:primary key
does not implynot null
in SQLite because there was a bug early on and changing it to follow the SQL standard would break programs that relied on that behavior (that's the general reason behind many weird behaviors/default values in SQLite).- In SQL null is not equal to anything, even null, so all of the null primary key values would be considered different.
Another thing is that you can put the
unique
constraints directly on the column they refer to when it's just a single column.
Ex:username text not null unique
Took me longer to get around to doing it than I expected.
Had to fiddle with part two a bit to get it to complete in a reasonable time because of Rhai's performance.
Rhai Solution