X39.io
A fancy world of magic, unicorns and a raging lazy dev

GDPR
by X39


As i currently lack the time to edit the website, here is what i do with your data:

==First things first==

This Webpage is currently using google analytics. This will change as soon as i got the time to remove it again. but that means that you are currently monitored whenever you navigate any of the pages here.

Apart from the above exception (which you can block using simple anti-tracking scripts till i removed it) no connection to the "outside internet" are done. Your data also is never shared with anybody in the outside world.

==Website==

  • The nginx server is running default logging for debuging purpose.
  • Google Analytics is running in this webpage for simple statistics service. Meaning your basic data is shared with google.
  • The PHP script this webpage is running sets a Cookie that allows to keep session informations. A session usually will be deleted after 30 minutes. Session data is not of importance for you (nothing will be set in there) but important for me to actually ... well ... do anything on this webpage.

==Applications==

  • Some applications are using update mechanisms which automatically runs at the startup. It communicates with this server. Default logging of nginx applies here too.
  • Applications updating are logged into an internal SQL table. The logged stats are: IP, Timestamp, API path. Those are logged for simple usage stats.

Inkscape - Good Software, Horrible Userexperience
by X39


I installed Inkscape like ages ago to do small edits on some SVG i had. It worked pretty damn good besides ... some problems...

The whole software is not designed so that some newcommer could pick it up easy. Ugly nested menus, way to specific snap options (which is theoretically good, but only for those who use inkscape on a regular basis! For EVERY other person, this is making things confusing AF, especially because not even all options can be put on at a single place) and generally a feel of lacking features due to them being so well hidden in nested menus or wrong terms that somebody not familiar will simply not find it.

Want an example of how hard this can be?

Microsoft provides the icon pack of visual studio for "free" but it has some lacking icons (eg. Tag has no NewTag variant)

Now, to edit this, you can use inkscape and join those two together so that they form a new 16x16 image

sounds easy right?

well ... it is not that simple afterall, but lets walk through this step as somebody new.

  1. You will pull both items into the current page
  2. You try to position them correctly whilst noticing that nothing snaps
  3. You search the snapping options (not knowing where they are, you ignore the righthand side as in most software, such options are at top whilst tools are left and righthand is current selected properties etc.) but cannot find them
  4. You google, to see a tutorial to do that and think "great"
  5. You try to position them correctly and everything still is not snapping
  6. You google again just to find out that those snapping options in the document properties are not all snapping options and enable snapping in the right bar for nodes too
  7. You position them correctly and export it
  8. You notice that the whole exported path is not usable because for some reason it is not in the right size and positoon
  9. You google how to change the page size
  10. You fiddle around a few mins until you got it to 16x16 px
  11. You export again, still not as it is displayed in inkscape
  12. You check the object just to see that its bounds are outside of the page area (and those got exported too)
  13. You try to find a way to crop the object to the visible page
  14. Few minutes later you realize that there is no inbuilt way to crop to the page (but the other way around which are the first few google results that will popup)
  15. Try to use the rectangle tool to create a rectangle at page size
  16. Try again because nothing appeared when you first tried
  17. Repeat step (16) up to the point where you try to just select everything
  18. Realize that you now have a ton of objects in your page
  19. Try to find some sort of object explorer, find none and google
  20. Google solution is not working, search icons on the right to find the treeview explorer
  21. Removing stuff from the explorer is not possible
  22. Write a rant
  23. Open everything in GIMP to do the same
  24. Be done in 20 minutes instead of 2 weeks of learning inkscape fully

In the end, Inkscape just feels bad!

There is a science field in the IT that is called Human-Computer-Interaction and everytime i think about giving inkscape a try, i notice that the whole software is not build in any way to suit to the average human.

It just feels like some developer put some option somewhere without any actual concept of grouping or awareness of other software available on the market.

I am fairly sure that experienced users can make good use of Inkscape, but as somebody who is not mainly doing such things but rather utilizing (or some may call it abusing) the tool to crop, manipulate etc. existing SVG/XAML paths the whole software feels bloated and not thought through.

[BotW] Seriously Nintendo fanboys ... the fuck is it with you?
by X39


Somebody not liking your game as much as you do through your fanboy glasses does not means they hate it...

they just do not use your fanboy-glasses and see the problems which also exist.

Example?

BotW is a good and solid game. It makes fun, got a beautiful world etc. etc.

However!!! It has design flaws which are unavoidable and probably annoyed most of the people playing the game.

Want examples?

The weapon durability system is horseshit... if weapons would "just" break and you could repair them if you bring them to a smith, probably ppl would be more ok with it. At last, it is a neat addition but executed horrible in a way that annoys and is not an addition to the gameplay.

Cooking is fun, but not in BotW. Yes it is neat for the first few times you do it but then you notice a big bummer: You lack a ton of quality of life (from now just refered to as QOL) features. Starting at the simplest: you cannot easily repeat your last cooking or make a bunch with the same. Just crafting eg. a potion feels cumbersome due to you being in need of having the right stuff in your inventory (which is fine) but you cannot see if you even got the right category of items. Due to the interface design, it simply does not feels right when you continue playing and need to cook to get health items, potions etc. it feels like you waste your time as this could be more simple. A simple book for example that opens up and allows to recraft anything you like. Picking ingredients would still be simple, but should be limited to what actually can be used in the current recipe

Motion Control shrines are just awful! It does not feels right to be in need of precise movement when you always can 100% freely move and rotate your object. They feel completly unnatural and anybody thinking they are "nice addition" is right, just that the execution is so wrong. Examples? There are shrines where you have to move a hammer with motion controls. So far so good right? But the hammer just has to swing from the left to the right, hitting a large ball. This however is deadly hard simply because the moment you start moving your joycon, the game moves the hammer. When you then rotate the hammer, the ball will fall off the ledge simply because your hammer is rotated slightly. This feels awful and youre happy when youre done with it. No challenge just pure anger about a broken mechanic.

The defensive mechanics like Shield Parry or jump-avoid are also completly horrible. The timing spot is way to short to get it off reliably, the enemies do not announce their attacks good enough to visually feel it, ... There is simply so much wrong with this mechanic... not to mention that the moment there is more then one enemy, you are simply fucked because all of theese things will not work anymore. So even if you by magic sit through hours to learn to parry correctly, it is no usable skill simply because the enemy behind you will just straigth hit you without a chance to parry or actually see that he is there.

could continue days with this! And it is awful that you fanboys do not want to notice this.

Do theese things hinder me from playing the game? Fuck no. But they exist! Everybody touching the game will experience them, everybody will get annoyed by them (you too) and everybody normal will not enjoy theese things as much as they could.

Theese are the reasons, why BotW should not be even considered as a Game of the Year ...

but they also do not make the game a bad one ... it is just not a perfect game.

In case somebody is in need of Full-Width TreeViewItem background highlighting
by X39


The Style:


                    <Style x:Key="FullRowTVI" TargetType="{x:Type TreeViewItem}">
                        <Setter Property="Background" Value="Transparent"/>
                        <Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
                        <Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
                        <Setter Property="Padding" Value="1,0,0,0"/>
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type TreeViewItem}">
                                    <ControlTemplate.Resources>
                                        <ss:StaggeredThicknessConverter Left="True" Length="19" x:Key="TVIStaggeredThicknessConverter" EndType="{x:Type TreeView}"/>
                                    </ControlTemplate.Resources>
                                    <Grid>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition MinWidth="19" Width="Auto"/>
                                            <ColumnDefinition Width="Auto"/>
                                            <ColumnDefinition Width="*"/>
                                        </Grid.ColumnDefinitions>
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto"/>
                                            <RowDefinition/>
                                        </Grid.RowDefinitions>
                                        <Border Name="Bd" Background="{TemplateBinding Background}" BorderBrush="Transparent" BorderThickness="0" Padding="0" Grid.ColumnSpan="3">
                                            <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
                                        </Border>
                                        <ToggleButton x:Name="Expander" IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press" Margin="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TreeViewItem}}, Converter={StaticResource TVIStaggeredThicknessConverter}}">
                                            <ToggleButton.Style>
                                                <Style TargetType="ToggleButton">
                                                    <Setter Property="Focusable" Value="False"/>
                                                    <Setter Property="Template">
                                                        <Setter.Value>
                                                            <ControlTemplate TargetType="ToggleButton">
                                                                <Grid Width="15" Height="13" Background="Transparent">
                                                                    <Path x:Name="ExpandPath" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="1,1,1,1" Fill="#444" Data="M 4 0 L 8 4 L 4 8 Z"/>
                                                                </Grid>
                                                                <ControlTemplate.Triggers>
                                                                    <Trigger Property="IsChecked" Value="True">
                                                                        <Setter Property="Data" TargetName="ExpandPath" Value="M 0 4 L 8 4 L 4 8 Z"/>
                                                                    </Trigger>
                                                                </ControlTemplate.Triggers>
                                                            </ControlTemplate>
                                                        </Setter.Value>
                                                    </Setter>
                                                </Style>
                                            </ToggleButton.Style>
                                        </ToggleButton>
                                        <Border Grid.Column="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
                                            <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
                                        </Border>
                                        <ItemsPresenter x:Name="ItemsHost" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3"/>
                                    </Grid>
                                    <ControlTemplate.Triggers>
                                        <Trigger Property="IsExpanded" Value="false">
                                            <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed"/>
                                        </Trigger>
                                        <Trigger Property="HasItems" Value="false">
                                            <Setter TargetName="Expander" Property="Visibility" Value="Hidden"/>
                                        </Trigger>
                                        <MultiTrigger>
                                            <MultiTrigger.Conditions>
                                                <Condition Property="HasHeader" Value="false"/>
                                                <Condition Property="Width" Value="Auto"/>
                                            </MultiTrigger.Conditions>
                                            <Setter TargetName="PART_Header" Property="MinWidth" Value="75"/>
                                        </MultiTrigger>
                                        <MultiTrigger>
                                            <MultiTrigger.Conditions>
                                                <Condition Property="HasHeader" Value="false"/>
                                                <Condition Property="Height" Value="Auto"/>
                                            </MultiTrigger.Conditions>
                                            <Setter TargetName="PART_Header" Property="MinHeight" Value="19"/>
                                        </MultiTrigger>
                                        <Trigger Property="IsSelected" Value="true">
                                            <Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                                        </Trigger>
                                        <MultiTrigger>
                                            <MultiTrigger.Conditions>
                                                <Condition Property="IsSelected" Value="true"/>
                                                <Condition Property="IsSelectionActive" Value="false"/>
                                            </MultiTrigger.Conditions>
                                            <Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                                        </MultiTrigger>
                                        <Trigger Property="IsEnabled" Value="false">
                                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                                        </Trigger>
                                    </ControlTemplate.Triggers>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                    <Style TargetType="{x:Type TreeView}">
                        <Setter Property="ItemContainerStyle" Value="{StaticResource FullRowTVI}"/>
                    </Style>```

The Converter:

using System; using System.Globalization; using System.Windows; using System.Windows.Data; using System.Windows.Media;

/// <summary>
/// Adds up the left margin of the upper visual tree up to the point where the <see cref="Type"/> is no longer matching starting at 0.
/// Expects the <see cref="DependencyObject"/> as value, will simply return value if passed value is not of <see cref="Type"/> <see cref="DependencyObject"/>
/// <see cref="UnsetOnNullConverter.ConvertBack(Object, Type, Object, CultureInfo)"/> will always return <see cref="System.Windows.DependencyProperty.UnsetValue"/>.
/// </summary>
public class StaggeredThicknessConverter : IValueConverter
{
    /// <summary>
    /// The length that should be added each time.
    /// </summary>
    public double Length { get; set; }

    /// <summary>
    /// Type that will be searched for. Continues to count until null or this.
    /// If not set, will count until different parent is encountered.
    /// </summary>
    public Type EndType { get; set; }

    /// <summary>
    /// Sets wether the top part of <see cref="Thickness"/> should be affected.
    /// </summary>
    public bool Top { get; set; }
    /// <summary>
    /// Sets wether the bottom part of <see cref="Thickness"/> should be affected.
    /// </summary>
    public bool Bot { get; set; }
    /// <summary>
    /// Sets wether the left part of <see cref="Thickness"/> should be affected.
    /// </summary>
    public bool Left { get; set; }
    /// <summary>
    /// Sets wether the right part of <see cref="Thickness"/> should be affected.
    /// </summary>
    public bool Right { get; set; }

    /// <summary>
    /// Converts a value
    /// </summary>
    /// <param name="value">The value produced by the binding source.</param>
    /// <param name="targetType">The type of the binding target property.</param>
    /// <param name="parameter">The converter parameter to use.</param>
    /// <param name="culture">The culture to use in the converter.</param>
    /// <returns>A converted value. If the method returns null, the valid null value is used.</returns>
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is DependencyObject obj))
        {
            return value;
        }
        var actingtype = obj.GetType();
        Type objtype;
        double leftmargin = 0;

        while((objtype = (obj = VisualTreeHelper.GetParent(obj)).GetType()).IsEquivalentTo(actingtype) || (this.EndType != null && !objtype.IsEquivalentTo(this.EndType)))
        {
            if (objtype.IsEquivalentTo(actingtype))
            {
                leftmargin += this.Length;
            }
        }
        return new Thickness(
            this.Left ? leftmargin : 0,
            this.Top ? leftmargin : 0,
            this.Right ? leftmargin : 0,
            this.Bot ? leftmargin : 0);
    }

    /// <summary>
    /// Converts a value.
    /// </summary>
    /// <param name="value">The value that is produced by the binding target.</param>
    /// <param name="targetType">The type to convert to.</param>
    /// <param name="parameter">The converter parameter to use.</param>
    /// <param name="culture">The culture to use in the converter.</param>
    /// <returns>A converted value. If the method returns null, the valid null value is used.</returns>
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return DependencyProperty.UnsetValue;
    }
}

python bullshittery - today: raw strings
by X39


dir = r"C:\somepath\log\"

results in SyntaxError: EOL while scanning string literal

lovely

Just killed my debian setup by accident ...
by X39


just took 8 hours to restore everything to a state where it was before (ok ... also fixed problems like reverse-dns lookup being wrong etc. :3)

anyways ... everything up running again