• 4 Posts
  • 18 Comments
Joined 1 year ago
cake
Cake day: June 10th, 2023

help-circle
  • I’d think so. 3k is so many pixels to compute and send 60 times a second.

    But this video says the effect on battery life in their test was like 6%, going from 4k to 800x600. I can imagine that some screens are better at saving power when running at lower resolutions… but what screen manufacturer would optimize energy consumption for anything but maximum resolution? 🤔 I guess the computation of the pixels isn’t much compared to the expense of having those physical dots. But maybe if your web browser was ray-traced? … ?!

    Also, if you take a 2880x1800 screen and divide by 2 (to avoid fractional scaling), you get 1440x900 (this is not 1440p), which is a little closer to 720p than 1080p.


  • I haven’t made a bridge to a VM before today, or made a bridge with Network Manager. That being said, I was able to persuade Network Manger to get a bridge working, and there are a few things I can note:

    • When you setup the bridge, the host network interface should become a slave to the bridge. This means that the physical network interface should not have an IP Address, and your bridge should now be where you configure the host’s IP address.

      • After you start the VM, you should be able to run ip link | grep 'master br0' on the host, and it should display 2 interfaces which are slaves to br0. One for the physical ethernet interface, one for the VM (vnet). And it should only list your ethernet interface when the VM is off.
    • The RedHat tutorial does not show the bridge and the host having different IP addresses, the RedHat tutorial shows the bridge and the guest having different IP addresses. Actually, no, the RedHat tutorial shows the libvirt NAT bridge, not even the bridge that the tutorial describes creating… If you set the IP address of virbr0, I don’t know what happens.

    • If your VM’s network adapter is connected to the host’s bridge, then you should be able to log into your VM and set a static IP address.

    I had a lot of problems getting Network Manager to actually use my ethernet interface as a slave for the bridge. Here’s what worked for me, though:

    nmcli con show
    nmcli con down 'Wired Connection 1'
    nmcli con modify 'Wired Connection 1' connection.autoconnect no
    nmcli con add type bridge con-name br0 ifname br0
    nmcli connection add type bridge-slave ifname enp7s0 master br0
    nmcli con modify br0 connection.autoconnect yes
    nmcli con modify bridge-slave-enp7s0 connection.autoconnect yes
    nmcli con modify br0 ipv4.method manual ipv4.addresses 172.16.0.231/24 bridge.stp no
    sudo systemctl restart NetworkManager.service
    nmcli con show
    ip addr
    
    • Instead of enp7s0, you’d use enp1s0 I guess.
    • Above, I manually set my bridge IP address to a static address because my ethernet interface is wired directly to another computer, so no DHCP for me. If you have DHCP on your ethernet network, you probably don’t need to set “ipv4.method” or “ipv4.addresses”.
    • I set “bridge.stp” to “no” because my network doesn’t have any redundant paths, and the stp process seems to take like 25 seconds before I can use the bridge network.

    After that, I can go into “Virtual Machine Manger”, set my VM’s NIC’s Network Source to “Bridge device…”, Device name to"br0", boot my VM, login to my VM, configure my VM’s ip address. And then I can connect to the VM’s IP address from the physical ethernet network.




  • vole@lemmy.worldtoLinux@lemmy.mlLooking to make the switch
    link
    fedilink
    English
    arrow-up
    3
    ·
    10 months ago

    POP!_OS apparently uses systemd-boot (not to be confused with systemd). It apparently adds a Windows entry automatically if Windows is installed on the same disk. When Windows is installed on a different disk, it looks like booting the windows boot manager EFI program is still possible with systemd-boot. The instructions given in that link are a bit vague, though.

    This page has a different, simpler approach and more specific steps. Apparently you can just copy the Microsoft EFI folder to a specific directory in your Linux drive’s ESP partition. I’d be a little bit concerned about Windows not being able to update its EFI bootloader, but I also don’t know if Windows ever updates that. The page also has instructions on how to interact with the systemd-boot menu during boot.

    You could also install grub yourself, but I can’t guarantee that’ll be easy. Mashing F2 might be the sanest solution, unless you plan on booting into Windows every day.


  • I got interested, so I spent some time looking into what’s going on here. I’m not intimately familiar with X11 or Wayland, but I figured out some stuff.

    Why sudo ip netns exec protected sudo -u user -i doesn’t work for X11 apps

    Short answer: file permissions and abstract unix sockets (which I didn’t know were a thing before now).

    File permissions: when I start an X11 login session, the DISPLAY is :0 and /tmp/.X11-unix/ has only 1 file X0. This file has 777 access. When I start my wayland session with Xwayland, the DISPLAY is :1 and /tmp/.X11-unix/ has 2 files X0 (777) and X1 (755). I can’t figure out how to connect to display :0, so I guess I’m stuck with :1. When you change to a different (non-root) user, the user no longer has access to /tmp/.X11-unix/X1.

    Abstract unix sockets: When I start my wayland/xwayland session, it creates abstract unix sockets with ids @/tmp/.X11-unix/X0 and @/tmp/.X11-unix/X1. See ss -lnp | grep Xwayland. The network namespace also sandboxes these abstract unix sockets. Compare socat ABSTRACT-CONNECT:/tmp/.X11-unix/X1 STDIN and sudo ip netns exec private socat ABSTRACT-CONNECT:/tmp/.X11-unix/X1 STDIN.

    When you do sudo ip netns exec protected su - user, you loose access to both the filesystem unix socket /tmp/.X11-unix/X1 and the abstract unix socket @/tmp/.X11-unix/X1. You need access to one or the other for X11 applications to work.

    I tried using socat to forward X1 such that it works in the network namespace… and it kinda works. sudo ip netns exec protected socat ABSTRACT-LISTEN:/tmp/.X11-unix/X1,fork UNIX-CONNECT:/tmp/.X11-unix/X1. It appears having ABSTRACT-LISTEN before UNIX-CONNECT is important, I guess it would be worth it to properly learn socat. With this sudo ip netns exec protected su - testuser -c 'env DISPLAY=:1 xmessage hi' works, but sudo ip netns exec protected su - testuser -c 'env DISPLAY=:1 QT_QPA_PLATFORM=xcb kcalc' does not work. 😞

    Changing the file permissions on /tmp/.X11-unix/X1 to give the user access seems to work better.

    Wayland waypipe

    Waypipe works as advertised. But it’s still a little bit tricky because you need to have two separate processes for the waypipe client and server, wait for the waypipe socket to be created, adjust file permissions for the waypipe socket file, and set (and probably mkdir) XDG_RUNTIME_DIR.

    waypipe -s /tmp/mywaypipe client &
    sleep 0.1
    chgrp shared-display /tmp/mywaypipe
    chmod g+w /tmp/mywaypipe
    sudo ip netns exec protected su - testuser -c 'mkdir -p -m 0700 /tmp/runtime-testuser && env XDG_RUNTIME_DIR=/tmp/runtime-testuser waypipe -s /tmp/mywaypipe server -- env QT_QPA_PLATFORM=wayland kcalc'
    kill -SIGINT %1
    

    Combined

    into this script https://github.com/vole-dev/grabbag/blob/main/run-netns-user-wayland.bash




  • Completely tangential tip, but in the very-limited video editing I’ve done recently: I’ve used Davinci Resolve, rendered as .mov, and then used ffmpeg to render to my actual desired format. e.g. h264 w/ aac audio so I can upload to Youtube:

    ffmpeg -i input.mov -c:v libopenh264 -profile:v high -c:a aac -pix_fmt yuv420p output.mp4

    I do think that finding the right flags to pass to ffmpeg is a cursed art. Do I need to specify the video profile and the pix_fmt? I don’t know; I thought I did when I adventured to collect these flags. Though maybe it’s just a reflection of the video-codec horrors lurking within all video rendering pipelines.

    edit: there may also be nvidia-accelerated encoders, like h264_nvenc, see ffmpeg -codecs 2>/dev/null | grep -i 'h\.264'. I’m not sure if the profile:v and pix_fmt options apply to other encoders or just libopenh264.


  • Shows for Winter 2024 on my radar, that I am interested in watching:

    • Classroom of the Elite: first two seasons were fun, looking forward to season 3
    • Bottom-tier Character Tomozaki: first season was OK, I’m interested in where the story will go
    • Mato Seihei no Slave: I vaguely recall someone saying there was something good about the source material
    • MASHLE: first season was OK, I’m not very interested in S2, I might binge it when the season is complete
    • Blue Exorcist: oh, another season. It’s been a while. I remember liking the first season and being confused at the start of the second season (it’s about 6 years between each season, so maybe I just forgot some important details. From a S2 MAL review: “the season does not follow the end of season 1. Episodes 18-25 were not canon and accordingly, they do not exist in season 2”, I didn’t know this, so maybe that was my problem)
    • The Dangers in My Heart: first season was fantastic, excited for the second season
    • A Sign of Affection: the source material is rated highly on MAL, I’ll give it a shot
    • Banished from the Hero’s Party: First season was OK
    • TSUKIMICHI: I liked the first season, looking forward to the second season
    • The Foolish Angel Dances with the Devil: I saw the PV, I’ll give it a shot
    • Cherry Magic!: The source material is rated well on MAL, I’ll give it a shot
    • The Witch and the Beast: The source material is rated well on MAL, I’ll give a shot
    • The Weakest Tamer Began a Journey to Pick Up Trash: WILDCARD, I dunno, it sounds like absolute trash from the title, but I think I’ll give it a shot anyways



  • Raku

    Today I’m thankful that I have the combinations() method available. It’s not hard to implement combinations(), but it’s not particularly interesting. This code is a bit anachronistic because I solved part 1 by expanding the universe instead of contracting it, but this way makes the calculations for part 1 and part 2 symmetric. I was worried for a bit there that I’d have to do some “here are all the places where expansion happens, check this list when calculating distances” bookkeeping, and I was quite relieved when I realized that I could just use arithmetic.

    edit: Also, first time using the Slip class in Raku, which is mind bending, but very useful for expanding/contracting the universe and generating the lists of galaxy coordinates. And I learned a neat way to transpose 2D arrays using [Z].

    View the code on Github

    Code
    use v6;
    
    sub MAIN($input) {
        my $file = open $input;
    
        my @map = $file.lines».comb».Array;
        my @galaxies-original = @map».grep("#", :k).grep(*.elems > 0, :kv).rotor(2).map({($_[0] X $_[1]).Slip});
        my $distances-original = @galaxies-original.List.combinations(2).map({($_[0] Z- $_[1])».abs.sum}).sum;
    
        # contract the universe
        @map = @map.map: {$_.all eq '.' ?? slip() !! $_};
        @map = [Z] @map;
        @map = @map.map: {$_.all eq '.' ?? slip() !! $_};
        @map = [Z] @map;
    
        my @galaxies = @map».grep("#", :k).grep(*.elems > 0, :kv).rotor(2).map({($_[0] X $_[1]).Slip});
        my $distances-contracted = @galaxies.List.combinations(2).map({($_[0] Z- $_[1])».abs.sum}).sum;
    
        my $distances-twice-expanded = ($distances-original - $distances-contracted) * 2 + $distances-contracted;
        say "part 1: $distances-twice-expanded";
        my $distances-many-expanded = ($distances-original - $distances-contracted) * 1000000 + $distances-contracted;
        say "part 2: $distances-many-expanded";
    }
    

  • Raku

    My solution for today is quite sloppy. For part 2, I chose to color along both sides of the path (each side different colors) and then doing a fill of the empty space based on what color the empty space is touching. Way less optimal than scanning, and I didn’t cover every case for coloring around the start point, but it was interesting to attempt. I ran into a bunch of issues on dealing with nested arrays in Raku, I need to investigate if there’s a better way to handle them.

    View code on github

    Edit: did some cleanup, added some fun, and switched to the scanning algorithm for part 2, shaved off about 50 lines of code.

    Code
    use v6;
    
    sub MAIN($input) {
        my $file = open $input;
    
        my @map = $file.lines».comb».Array;
    
        my @starting-point = @map».grep('S', :k)».[0].grep(*.defined, :kv).List;
    
        my @path = (@starting-point,);
    
        my %tile-neighbors =
            '|' => (( 1, 0),(-1, 0)),
            '-' => (( 0,-1),( 0, 1)),
            'L' => ((-1, 0),( 0, 1)),
            'J' => ((-1, 0),( 0,-1)),
            '7' => (( 1, 0),( 0,-1)),
            'F' => (( 1, 0),( 0, 1)),
        ;
    
        sub connecting-neighbor(@position, @neighbor) {
            my @neighbor-position = @position Z+ @neighbor;
            return False if any(@neighbor-position Z< (0, 0));
            return False if any(@neighbor-position Z> (@map.end, @map.head.end));
            my $neighbor-tile = @map[@neighbor-position[0]; @neighbor-position[1]];
            my @negative-neighbor = @neighbor X* -1;
            return %tile-neighbors{$neighbor-tile}.grep(@negative-neighbor, :k).elems > 0;
        }
    
        # replace starting-point with the appropriate pipe
        my @start-tile-candidates = <| - L J 7 F>;
        for @start-tile-candidates -> $candidate {
            next if %tile-neighbors{$candidate}.map({!connecting-neighbor(@starting-point, $_)}).any;
            @map[@starting-point[0]; @starting-point[1]] = $candidate;
            last;
        }
    
        repeat {
            my @position := @path.tail;
            my $tile = @map[@position[0]; @position[1]];
            my @neighbors = %tile-neighbors{$tile}.List;
            for @neighbors -> @neighbor {
                my @neighbor-position = @neighbor Z+ @position;
                next if @path.elems >= 2 && @neighbor-position eqv @path[*-2];
                if connecting-neighbor(@position, @neighbor) {
                    @path.push(@neighbor-position);
                    last;
                }
            }
        } while @path.tail !eqv @path.head;
        my $part-one-solution = (@path.elems / 2).floor;
        say "part 1: {$part-one-solution}";
    
        my %pipe-set = @path.Set;
        my %same-side-pairs = ;
        my $part-two-solution = 0;
        for ^@map.elems -> $y {
            my $inside = False;
            my $entrance-pipe = Nil;
            for ^@map.head.elems -> $x {
                if %pipe-set{$($y, $x)} {
                    given @map[$y; $x] {
                        when '|' { $inside = !$inside }
                        when 'F' | 'L' { $entrance-pipe = $_ }
                        when 'J' | '7' {
                            $inside = !$inside if %same-side-pairs{$entrance-pipe} ne $_;
                            $entrance-pipe = Nil;
                        }
                    }
                } elsif $inside {
                    $part-two-solution += 1;
                }
            }
        }
        say "part 2: $part-two-solution";
    }
    

  • Raku

    First time using Grammar Actions Object to make parsing a little cleaner. I thought about not keeping track of the left and right values (and I originally didn’t for part 1), but I think keeping track allows for an easier to understand solution.

    View code on github

    edit: although I don’t know why @values.all != 0 evaluates to true why any value is not zero. I thought that @values.any != 0 would do that, but it seems that their behavior is flipped from my expectations.

    edit2: Oh, I think I understand now. != is a shortcut for !==, and !== is actually the equality operator that is then negated. You can negate most relational operators in Raku by prefixing them with !. So the junction is actually binding to the == equality operator and not the !== inequality operator. Therefore @values.all != 0 becomes !(@values.all == 0). I’m not sure why they would choose this order of operations, though.

    edit3: Ah, it’s in the documentation, so it’s not even an oversight. https://github.com/rakudo/rakudo/issues/3748

    Code (probably still doesn't render correctly)
    use v6;
    
    sub MAIN($input) {
        my $file = open $input;
    
        grammar Oasis {
            token TOP { +%"\n" "\n"* }
            token history { +%\h+ }
            token val { '-'? \d+ }
        }
    
        class OasisActions {
            method TOP ($/) { make $».made }
            method history ($/) { make $».made }
            method val ($/) { make $/.Int }
        }
    
        my $oasis = Oasis.parse($file.slurp, actions => OasisActions.new);
        my @histories = $oasis.made;
        my $part-one-solution;
        my $part-two-solution;
        sub revdiff { $^b - $^a }
        for @histories -> @history {
            my @values = @history;
            my @rightmosts = [@values.tail];
            my @leftmosts = [@values.head];
            while @values.all != 0 {
                @values = @values.tail(*-1) Z- @values.head(*-1);
                @rightmosts.push(@values.tail);
                @leftmosts.push(@values.head);
            }
            $part-one-solution += [+] @rightmosts;
            $part-two-solution += [[&revdiff]] @leftmosts.reverse;
        }
        say "part 1: $part-one-solution";
        say "part 2: $part-two-solution";
    }
    


  • Personally, I’m not a fan of requiring analysis of the individualized input to reach the correct (sufficiently efficient) solution for part 2. Or maybe I’m just resentful because I feel like I’ve been duped after writing an generalized-to-the-puzzle-description-but-insufficiently-efficient solution. 😔

    These quantum ghosts need to come back down to reality.


  • Raku

    My hand-type strength calculations could probably be trimmed down a bit. I didn’t hit any big issues today.

    View code on github

    Code (note: doesn't currently display correctly on Lemmy website)
    use v6;
    
    sub MAIN($input) {
        my $file = open $input;
    
        grammar CamelCards {
            token TOP { +%"\n" "\n"*}
            token row {  " "  }
            token hand { \S+ }
            token bid { \d+ }
        }
    
        my $camel-cards = CamelCards.parse($file.slurp);
        my @rows = $camel-cards.map({ (..Str, ..Int) });
        my @ranked-rows1 = @rows.sort({hand-strength($_[0], &hand-type-strength1, '23456789TJQKA'.comb)});
        my $part-one-solution = (@ranked-rows1»[1] Z* 1..*).sum;
        say "part 1: $part-one-solution";
    
        my @ranked-rows2 = @rows.sort({hand-strength($_[0], &hand-type-strength2, 'J23456789TQKA'.comb)});
        my $part-two-solution = (@ranked-rows2»[1] Z* 1..*).sum;
        say "part 2: $part-two-solution";
    }
    
    sub hand-strength($hand, &hand-type-strength, @card-strengths) {
        my $strength = &hand-type-strength($hand);
        for $hand.comb -> $card {
            $strength = $strength +< 8 + @card-strengths.first({ $_ eq $card }, :k);
        }
        return $strength;
    }
    
    sub hand-type-strength1($hand) {
        my @sorted = $hand.comb.sort;
        my @runs = [1];
        my $card = @sorted[0];
        for @sorted[1..*] -> $new-card {
            if $new-card eq $card {
                @runs.tail += 1;
            } else {
                @runs.push(1);
                $card = $new-card;
            }
        }
        return do given @runs.sort {
            when .[0] == 5 { 6 } # Five of a kind
            when .[1] == 4 { 5 } # Four of a kind
            when .[1] == 3 { 4 } # Full House
            when .[2] == 3 { 3 } # Three of a kind
            when .[1] == 2 { 2 } # Two pair
            when .[3] == 2 { 1 } # One pair
            default { 0 } # High card
        };
    }
    
    sub hand-type-strength2($hand) {
        my @sorted = $hand.comb.grep(none /J/).sort;
        if @sorted.elems == 0 {
            return 6;
        } else {
            my @runs = [1];
            my $card = @sorted[0];
            for @sorted[1..*] -> $new-card {
                if $new-card eq $card {
                    @runs.tail += 1;
                } else {
                    @runs.push(1);
                    $card = $new-card;
                }
            }
            @runs.=sort;
            @runs.tail += 5 - @sorted.elems;
            return do given @runs {
                when .[0] == 5 { 6 } # Five of a kind
                when .[1] == 4 { 5 } # Four of a kind
                when .[1] == 3 { 4 } # Full House
                when .[2] == 3 { 3 } # Three of a kind
                when .[1] == 2 { 2 } # Two pair
                when .[3] == 2 { 1 } # One pair
                default { 0 } # High card
            };
        }
    }
    


  • Raku

    I spent a lot more time than necessary optimizing the count-ways-to-beat function, but I’m happy with the result. This is my first time using the | operator to flatten a list into function arguments.

    edit: unfortunately, the lemmy web page is unable to properly display the source code in a code block. It doesn’t display text enclosed in pointy brackets <>, perhaps it looks too much like HTML. View code on github.

    Code
    use v6;
    
    sub MAIN($input) {
        my $file = open $input;
    
        grammar Records {
            token TOP {  "\n"  "\n"* }
            token times { "Time:" \s* +%\s+ }
            token distances { "Distance:" \s* +%\s+ }
            token num { \d+ }
        }
    
        my $records = Records.parse($file.slurp);
    
        my $part-one-solution = 1;
        for $records».Int Z $records».Int -> $record {
            $part-one-solution *= count-ways-to-beat(|$record);
        }
        say "part 1: $part-one-solution";
    
        my $kerned-time = $records.join.Int;
        my $kerned-distance = $records.join.Int;
        my $part-two-solution = count-ways-to-beat($kerned-time, $kerned-distance);
        say "part 2: $part-two-solution";
    }
    
    sub count-ways-to-beat($time, $record-distance) {
        # time = button + go
        # distance = go * button
        # 0 = go^2 - time * go + distance
        # go = (time +/- sqrt(time**2 - 4*distance))/2
    
        # don't think too hard:
        # if odd t then t/2 = x.5,
        #   so sqrt(t**2-4*d)/2 = 2.3 => result = 4
        #   and sqrt(t**2-4*d)/2 = 2.5 => result = 6
        #   therefore result = 2 * (sqrt(t**2-4*d)/2 + 1/2).floor
        # even t then t/2 = x.0
        #   so sqrt(t^2-4*d)/2 = 2.x => result = 4 + 1(shared) = 5
        #   therefore result = 2 * (sqrt(t^2-4*d)/2).floor + 1
        # therefore result = 2 * ((sqrt(t**2-4*d)+t%2)/2).floor + 1 - t%2
        # Note: sqrt produces a Num, so perhaps the result could be off by 1 or 2,
        #       but it solved my AoC inputs correctly 😃.
    
        my $required-distance = $record-distance + 1;
        return 2 * ((sqrt($time**2 - 4*$required-distance) + $time%2)/2).floor + 1 - $time%2;
    }