#install packages void linux
Explore tagged Tumblr posts
Text
Using Distrosea, I had a look at Rocky Linux 9.
Rocky Linux is a Linux distro designed for the VFX industry. It serves as a drop in replacement for Red Hat Enterprise Linux.
Rocky Linux website:
https://rockylinux.org/
Here is a example of an animation studio that uses the distribution.
DreamWorks' migrated their workstations and servers from Red Hat Enterprise Linux 7 to Rocky Linux 9 in 2023 and completed the rollout the following year.
DreamWorks Animation website:
https://www.dreamworks.com/about
About RHEL:
https://en.wikipedia.org/wiki/Red_Hat_Enterprise_Linux
About Rocky Linux:
https://en.wikipedia.org/wiki/Rocky_Linux
Here are some reasons DreamWorks Animation moved from Red Hat Enterprise Linux:
- Red Hat dropped the CentOS Linux operating system in 2020. They ended support for version 7 in 2024.
CentOS was an downstream version of Red Hats main operating system without its branding and support. Rocky Linux fills this void left by CentOS.
DreamWorks used CentOS alongside Red Hat Enterprise Linux. Both their Workstations and server set-ups were migrated to Rocky.
- Red Hat further restricted access to its source code in their Enterprise focused operating system.
- Rocky Linux has become a very popular open source operating system for the VFX industry and features many modern advancements and desktop environment choices such as GNOME, KDE, XFCE, MATE and Cinnamon.
- Like all Red Hat based builds of Linux, Rocky Linux uses the DNF (Dandified Yellow Dog Updater) extension to manage application installations via the Dnfdragora package manager. However it also uses the universal Flatpak extension to install applications from the GNOME software centre.
- DreamWorks animation pipeline uses their recently opened sourced Moon-Ray renderer, which is built on Rocky Linux. The source code is available on GitHub.
The tool supports Linux and Mac OS. Here is a link to the Open Moon Ray installation and compiling on Rocky:
https://docs.openmoonray.org/getting-started/installation/building-moonray/general_build/
It features a set of commands for installing various graphics libraries (for the render tool and Houdini, a character effects development tool), as well as toolsets which can be applied to programs such as Blender.
There are many YouTube videos about the open sourcing of Moon-Ray itself and some showcases of it working.
Rocky Linux is a downstream, complete binary-compatible release using the Red Hat Enterprise Linux (RHEL) operating system source code.
Unlike RHEL, Rocky is completely free to use. It is released under the BSD 3-Clause license, which allows free use, modification, and distribution.
There are no licensing or subscription fees associated. RHEL is a commercial product from Red Hat and requires a subscription license to use.
Rocky's selection of desktop environments can be installed independently in their own disk image file.
Each one can also be tested on a live USB before installation.
Users can also install their desktop environments of choice using the command line.
When running the system on a server (which is the common way of using Linux systems) it will just have the command line interface when a monitor is plugged in.
Distrosea:
https://distrosea.com/
The latest build is Rocky Linux 10, released in June 2025. The version available to test on Distrosea is 9.
I tried GNOME, MATE, XFCE and KDE.
As this MATE desktop edition didn't come with either Dnfdragora or GNOME Software, I tried installing Blender (an open source animation tool) using the 'sudo dnf install blender' command in the terminal.
However, due to the graphics limitation of the VM, the program couldn't launch.
To install software graphically, you can use GNOME Software Centre that comes on GNOME. This can be used on other desktop environments as well.
A good Linux distribution if you are using graphics heavy applications and need a robust enterprise grade operating system without the cost!
Another Linux distro that is similar is Alma Linux, another enterprise focused operating system that uses the same foundations as CentOS.
4 notes
·
View notes
Text
Dev Log Feb 7 2025 - The Stack
Ahoy. This is JFrame of 16Naughts in the first of what I hope will turn out to be a weekly series of developer logs surrounding some of our activities here in the office. Not quite so focused on individual games most of the time, but more on some of the more interesting parts of development as a whole. Or really, just an excuse for me to geek out a little into the void. With introductions out of the way, the first public version of our game Crescent Roll (https://store.steampowered.com/app/3325680/Crescent_Roll juuuust as a quick plug) is due out here at the end of the month, and has a very interesting/unorthodox tech stack that might be of interest to certain devs wanting to cut down on their application install size. The game itself is actually written in Javascript - you know, the scripting language used by your web browser for the interactive stuff everywhere, including here. If you've been on Newgrounds or any other site, they might call games that use it "HTML5" games like they used to call "Flash" games (RIP in peace). Unfortunately, Javascript still has a bit of a sour reputation in most developer circles, and "web game" doesn't really instill much confidence in the gamer either. However, it's turning more and more into the de-facto standard for like, everything. And I do mean everything. 99% of applications on your phone are just websites wrapped in the system view (including, if you're currently using it, the Tumblr app), and it's bleeding more and more into the desktop and other device spaces. Both Android and iOS have calls available to utilize their native web browsers in applications. Windows and Mac support the same thing with WebView2 and WebKit respectively. Heck, even Xbox and Nintendo have a web framework available too (even goes back as far as Flash support for the Wii). So, if you're not using an existing game engine like we aren't and you want to go multi-platform, your choices are either A) Do it in something C/C++ -ish, or now B) Write it in JS. So great - JS runs everywhere. Except, it's not exactly a first-class citizen in any of these scenarios. Every platform has a different SDK for a different low-level language, and none of them have a one-click "bundle this website into an exe" option. So there is some additional work that needs to be done to get it into that nice little executable package.
Enter C#. Everyone calls it Microsoft Java, but their support for it has been absolutely spectacular that it has surpassed Java in pretty much every single possible way. And that includes the number and types of machines that it runs on. The DotNet Core initiative has Mac, Windows, and Linux covered (plus Xbox), Xamarin has Android, and the new stuff for Maui brought iOS into the fold. Write once, run everywhere. Very nice. Except those itty bitty little application lifetime quirks completely change how you do the initialization on each platform, and the system calls are different for getting the different web views set up, and Microsoft is pushing Maui so hard that actually finding the calls and libraries to do the stuff instead of using their own (very strange) UI toolkit is a jungle, but I mean, I only had to write our stream decompression stuff once and everything works with the same compilation options. So yeah - good enough. And fortunately, only getting better. Just recently, they added Web Views directly into Maui itself so we can now skip a lot of the bootstrapping we had to do (I'm not re-writing it until we have to, but you know- it's there for everyone else). So, there you have it. Crescent Roll is a Javascript HTML5 Web Game that uses the platform native Web View through C#. It's a super tiny 50-100MB (depending on the platform) from not having to bundle the JS engine with it, compiles in seconds, and is fast and lean when running and only getting faster and leaner as it benefits from any performance improvements made anywhere in any of those pipeline. And that's it for today's log. Once this thing is actually, you know, released, I can hopefully start doing some more recent forward-looking progress things rather than a kind of vague abstract retrospective ramblings. Maybe some shader stuff next week, who knows.
Lemme know if you have any questions on anything. I know it's kind of dry, but I can grab some links for stuff to get started with, or point to some additional reading if you want it.
3 notes
·
View notes
Note
sans a few gpu/cpu config fixes a fresh install + all my packages of void linux is identical to a fully updated old one. Like maybe if you fucked up building something that doesnt have an uninstall script and don't know how to find all the files manually? I just see 0 purpose, is it different for other distros
For the most part, not really. There are some Linux users on this website who have royally fucked their systems beyond comprehension, and it would be easier and faster to just reinstall the OS than to actually fix anything going on there, and yet just continue to live every day like this. It's their computers, they can do what they want, but this is the level of "Not willing to reinstall the OS" I had in mind.
I am an opposite extreme, I have fun messing around with wiping and reinstalling my crap. It may have been a little unclear but I don't think this is necessarily ideal use, it's just not particularly painful or obtrusive cuz reinstalls (or wiping and putting a slightly different flavor) don't take all that much time and getting everything back in order, at least for me and with how I partition things, does not take very long.
Honestly though this time I'm just thinking of wiping Mint and going back to Debian for a few reasons, which technically isn't "reinstalling" but it reminded me of those horrifying setups that real Linux users out there willingly use every day.
ETA: I mean in general I don't relate to not wanting to futz around with the OS install but I am. an extreme case, basically.
2 notes
·
View notes
Text
Debian 12 xfce ~~~~ let's go~~~~~
I complained about debian not having wifi drivers upon live cd boot, apparently that was by design for the older versions as (i think?) device drivers like that might be proprietary and non-free. and debian ships usually free and open source packages....
so that was by design~~ they changed it I think in debian 12, which I'm late to finding lol.
I missed the transparency thing xfce does sometimes~~~ I like xfce's compositor~~ and for some reason I don't like KDE when I tried it before and hadn't tried it since~~
could've tried it but just jumped on xfce desktop with debian 12, especially cause I've come to like thunar file manager over dolphin (? was that kde's?)
just got it up and running~~ tho I forget (or don't know) how to update the system yet.... mint has an update manager, or it's a cinnamon desktop thing..... idk.... tho I'm guessing "sudo apt-get update"
I like the splash screen and grub menu~~~ and (not that linux mint debian was unstable cause it wasn't~~) I hope debian is really stable~~ ot that's what I read anyway~~
and my function keys still work, lol. unlike upon fresh windows install~~
and I can still access the other hard drive~~ but for some reason upon unmounting it it says that there's still something going on or data is being written to it, but then it seems to unmount fine anyway~~ so I hope nothing is going wrong already~~ lol
continually talking about linux cause I got nowhere else to~~ lol sorry for cluttering up the tags if they aren't correct at all~~
now to install vlc and stuff lol~~ and hopefully find more xfce-4 themes so I can get it looking like windows 95 lol
or what's a better desktop environment than xfce? I tried lxde and it's supposedly not getting updated anymore so better to try lxqt in that case? it's newer.... Cinnamon is nice but got bored of it w mint, kde I didn't like back when I tried it a decade ago and hadn't touched it since.... hadn't messed w GNOME either in a long while either tho, I miss the sidebar and quick access to workspaces but didn't like it for other reasons too... or maybe it wasn't as customizeable..... or I didn't know how.....
currently rocking debian 12 as the title suggests w xfce desktop environment~~~ but could maybe switch to lxqt ~~~ but idk how to wipe all components from xfce and install lxqt...
and I don't like having more than one desktop environment installed cause that leads to duplicate apps
*side glances at how many terminal emulators are here anyway*
which do I choose? there are so many~~~ but lately I like xfce~~~ and might give lxqt a shot~~~ idk.....
there are so many and I already have a hard time choosing anyway lol
also just realized that the installer didn't ask for a root password so i have to "sudo" every single time cause I can't run as root directly.
and for some reason my username didn't capitalize so I tried to log into the system and it said the password was incorrect, I knew the password was correct, I made the first letter of my username small and i was in~~~
wtf~~~ did it lowercase it in the installer and I didn't realize it? is this what happened before when I tried to install debian years ago? I just reinstalled mint like an idiot instead of trying things T_T;;
tho I still consider myself a newbie cause arch, opensuse, slackware and others like that scare me ~~~ but they'd get me to learn~~ I just don't know enough to use them yet.
which begs the question, should I be running debian anyway? or should I just go back to mint?p
second guessing myself after a SUCCESSFUL INSTALL~~~~~ rip. but I like what I got going..... and cinnamon was getting boring lol
tldr: I'm taking tumblr on the linux journey with me~~~ :) hopefully typing about it into the void will help me be less anxious about trying stuff and potentially breaking my system~~ lol cause ya can always install a system that you know works~~ if something breaks.
happy to be running the grandpa of a whole bunch of linux distributions :)
hopefully I'm smarter than I think and this'll be fine~~~ worry I'll break stuff constantly~~~~ and I really don't like not knowing what I'm doing cause I feel stupid but that's how you learn to begin with, isn't it?
#personal#thoughts#thinking#os#operating system#operating systems#linux#debian#debian 12#debian linux#linux debian#let's go~~~~#desktop#desktop environment#desktop environments#xfce#xfce-4#i think anyway#xfce desktop#xfce-4 desktop#there are so many tho#which to choose#lxde is defunct at this point#lxqt#is it any good?#is it like xfce?#sorry for cluttering up the tags#esp if it doesn't belong here
0 notes
Text
Starting out with void linux
Hey hey! welcome back. This is my first post that's not an introduction.
So i've been into linux for almost a year, and since then i've learned a lot. But i haven't limited my options to linux only, but also to other unix systems like bsd. When i was browsing r/unix, i saw someone commenting that one should try void linux, because its similar to bsd in a way: its minimalistic, transparent and easy to understand. its very good for those who are willing to start out with linux by learning how it works.
Its main features are the xbps package manager (you cant install programs via source code compiling like in gentoo) and the fact it uses runit as the init system, which (i think) is supposed to be some weird hybrid between systemd and sysvinit.
So yesterday i decided to give a try and made a bootable usb stick. its relatively easy to install. the hardest thing would be you having to know how to partition your system in a way that actually fits your needs, but even that is explained in the official documentation. Wi-fi support works surprisingly good by default, even better than debian.
I started out from nothing and decided to install i3wm in it, but since i had no prior knowledge in twms, i went to the arch wiki (void's official site said you can consult things there) to see how to install and configure it, and i also looked up yt videos. its nice that you can work on a pc with just a keyboard, not needing to use a mouse. reminds me a lot of those old keyboard-only portable computers. they're kinda cute.
As for the programs...i installed xfce's thunar file browser but it was a bit faulty. i couldn't access the trash bin to recover/delete files. i think i should install mate's caja or something? maybe.
Firefox works nice ig, but if you want really basic web browsing, like browsing sites that dont include js, you should try midori or lynx with framebuffer enabled (havent tried this one. only plain lynx on debian's cli). if i want to listen to a song or something i can use smtube and it doesnt consume much resources. a basic libreoffice install works wonderfully!! my 1.3 ghz cpu could handle calc (linux excel) better and without lagging than let's say debian...
So that was all guys. Can't see what the future awaits for me. maybe i should try openbsd/netbsd sometime soon. they interest me a lot. I hope you all enjoyed reading this. stay safe and see you soon!
1 note
·
View note
Note
What distro of Linux do you use, and what would you recommend to someone who has been using Ubuntu for a decade because ae's scared to move away from aer familiar package manager? You know. Hypothetically.
i use Void, bc Arch was too mainstream slkdfjsdlk (okay no fr i use Void bc i kept seeing it on r/unixporn and i wanted a distro that had the "go nuts show nuts" curate-your-own-experience style Arch has but without systemd - no judgement if you like it, but it's not my vibe).
i used to use Mint and have done on-and-off since version 4 Daryna - Crunchbang was discontinued around that time and i wanted another Ubuntu-based distro to switch to.
so, if someone were looking to try something new (hypothetically, of course d: ) i would recommend considering the following first:
what's aer typical workload (and therefore what would be suitable) ?
how far would ae be willing to explore beyond aer comfort zone ?
how much time would ae have to learn new things ?
trying one or two distros out in a VM might be a good way for aem to familiarise aemself w/ any immediate quirks and pick a distro to install on bare metal (perhaps alongside aer existing distro ?)
for something more familiar i might recommend Debian Testing or LMDE (the version of Mint based directly on Debian) as they share much of the same internal architecture. i believe Debian offers a netinstall that's barebones like Arch/Void/Gentoo if trying new software (perhaps including a new DE/WM/Wayland compositor) without losing all familiarity would be of interest to this person.
for something more adventurous i would suggest Arch and perhaps picking a full DE to start with, then maybe trying an install that's more uh selective. personally, Void is no harder than Arch but the community is smaller and a person who hypothetically chose this as their new distro would not only have the barebones nature of that class of distro + an unfamiliar package manager to contend with, but additionally an unfamiliar init system (though runit is terrifyingly simple, i must say). there's also Artix, which is Arch but w/out systemd (i think they offer runit or openrc).
there are plenty of wacky distros (Bedrock, Fedora Silverblue, NixOS, Qubes, Gentoo) that would be fun to experiment with on a non-critical system/VM but they're very far removed from a decade of Ubuntu.
i appreciate this is a long answer, but you asked a lovely question and it's fun to indulge in uh um what's definitely totally a hypothetical d: if someone were to change distro i hope ae know ae can reach out to ask further questions :3
thanks for your ask ! <3 ^w^
42 notes
·
View notes
Text
The ARM GCC cross-compiler saga
I love macOS and ever since I switched to it in 2018, it has become my favourite platform of all time. However, the thing is that I develop software for embedded Linux devices pretty often too.
Since the devices themselves usually have a stripped down firmware as well as are generally underpowered, the best way to speed up the development process and to make it easier and more comfortable in general is to use a cross-compiler toolchain. On Linux, it’s pretty easy to build one yourself or use Linaro’s pre-compiled GCC binaries if your target uses an ARM processor. On macOS, however, the building process does have some caveats.
One of the things that make compiling a cross-toolchain on macOS targeting Linux is that macOS by default uses a case-insensitive file system, which makes building glibc for the target almost impossible. This can be easily worked around by creating a read-write DMG image containing a single Mac OS Extended (Journaled, Case-sensitive) or APFS (Case-sensitive) partition, mounting it and storing the sources and build directories there.
Compiling the Linux kernel from macOS doesn't really work that well. Usually, you can't get past the configuration step successfully - even the install_headers target fails miserably. A workaround for that would be getting existing kernel headers as a package for the target system and unpacking it manually. For example, if your target runs a distro compatible with RHEL/Fedora, then you can get a pre-built kernel-headers package matching the kernel version of your Linux device and unpacking it manually. This will require compiling RPM, though, or installing it through Homebrew (which is faster).
When it comes to anything else, the build process is mostly similar to the one described in many many available guides on the net. But here is a short guided command-line snippet that will get you going with an ARM64 GCC toolchain for Fedora Linux 33 (use this as a reference). Just changing the toolchain target string ($LINUXARMBRAND) to the one matching your target platform should probably be enough in most cases to get a working toolchain for it.
# set the prefix and the target string variables accordingly $ export LINUXARMTC=/usr/local/builds/gcc-cross-arm64-linux $ export LINUXARMBRAND=aarch64-redhat-linux-gnu # get binutils and gcc $ curl -o- http://mirrors.dotsrc.org/gnu/binutils/binutils-2.36.tar.xz | tar -xvJf - $ curl -o- http://mirrors.dotsrc.org/gnu/gcc/gcc-9.1.0/gcc-9.1.0.tar.xz | tar -xvJf - # build rpm as well as some of its dependencies # 1. build libmagic $ curl -o- http://deb.debian.org/debian/pool/main/f/file/file_5.39.orig.tar.gz | tar -xvzf - $ cd file-5.39 && sh configure --prefix=$LINUXARMTC --enable-static --disable-shared && make -j6 && make install $ cd .. # 2. build openssl $ curl -o- https://www.openssl.org/source/openssl-1.1.1i.tar.gz | tar -xvzf - $ cd openssl-1.1.1i && perl Configure no-hw no-shared no-zlib no-asm --prefix=$LINUXARMTC darwin64-x86_64-cc && make -j6 && make install $ cd .. # 3. build rpm itself $ curl -o- http://ftp.rpm.org/releases/rpm-4.16.x/rpm-4.16.0.tar.bz2 | tar -xvjf - $ cd rpm-4.16.0 && CFLAGS="-I$LINUXARMTC/include" LDFLAGS="-L$LINUXARMTC/lib" LIBS="-lbz2 -lz" sh configure --prefix=$LINUXARMTC --disable-shared --enable-static --with-crypto=openssl --without-archive --disable-plugins --without-lua --disable-openmp $ echo 'void main() {}' > rpmspec.c && make -j6 && make install # 4. build make $ curl -o- http://mirrors.dotsrc.org/gnu/make/make-4.3.tar.gz | tar -xvzf - $ cd make-4.3 && sh configure --prefix=$LINUXARMTC && make -j6 && make install $ cd .. # 5. build bison $ curl -o- http://mirrors.dotsrc.org/gnu/bison/bison-3.7.5.tar.xz | tar -xvJf - $ cd bison-3.7.5 && sh configure --disable-nls --prefix=$LINUXARMTC && make -j6 && make install # get fedora kernel headers $ mkdir rpmextract && cd rpmextract $ curl -o kernel.rpm http://mirrors.dotsrc.org/fedora/linux/updates/33/Everything/aarch64/Packages/k/kernel-headers-5.10.11-200.fc33.aarch64.rpm $ $LINUXARMTC/bin/rpm2cpio kernel.rpm | tar -xvf - # install them into a sysroot $ mkdir -p $LINUXARMTC/$LINUXARMBRAND $ mv -v include $LINUXARMTC/$LINUXARMBRAND $ cd ../.. # build binutils $ cd binutils-2.36 && mkdir build && cd build && sh ../configure --target=$LINUXARMBRAND --prefix=$LINUXARMTC --disable-multilib --disable-werror --disable-libquadmath --disable-libquadmath-support && make -j6 && make install $ cd ../.. # build gcc (stage 1) $ export PATH="$LINUXARMTC/bin:$PATH" $ cd gcc-9.1.0 && sh contrib/download_prerequisites --no-isl --no-graphite && mkdir build && cd build && sh ../configure --prefix=$LINUXARMTC --target=$LINUXARMBRAND --with-static-standard-libraries --disable-libquadmath --disable-libquadmath-support --enable-ld=yes --enable-languages=c,c++ $ make -j6 all-gcc $ make install-gcc # bootstrap glibc $ cd glibc-2.32 && mkdir build && cd build && BISON=$LINUXARMTC/bin/bison MAKE=$LINUXARMTC/bin/make ../configure --prefix=$LINUXARMTC/$LINUXARMBRAND --host=$LINUXARMBRAND --target=$LINUXARMBRAND --with-headers=$LINUXARMTC/$LINUXARMBRAND/include --disable-multilib --disable-werror $ make install-bootstrap-headers=yes install-headers $ make -j6 csu/subdir_lib $ install csu/crt1.o csu/crti.o csu/crtn.o $LINUXARMTC/$LINUXARMBRAND/lib $ $LINUXARMTC/bin/aarch64-redhat-linux-gnu-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o $LINUXARMTC/$LINUXARMBRAND/lib/libc.so # build gcc (stage 2) $ cd ../../gcc-9.1.0/build && touch /usr/local/builds/fedora33-arm64-gcc/aarch64-redhat-linux-gnu/include/gnu/stubs.h && make -j6 all-target-libgcc && make install-target-libgcc # finish glibc $ cd ../../glibc-2.32/build && touch testrun.shT debugglibc.shT iconvdata/MIK.so iconvdata/ISO_11548-1.so iconvdata/ISO8859-9E.so iconvdata/CP77{0,1,2,3,4}.so iconvdata/KOI8-RU.so iconvdata/MAC-CENTRALEUROPE.so && make -j6 && make install # build gcc (stage 3) $ cd ../../gcc-9.1.0/build && make -j6 && make install
Hope this works for you
#linux#macos#gcc#cross-compiler#toolchain#arm#raspberrypi#odroid#technology#tech#c programming#c++#programming#c++ programming
4 notes
·
View notes
Text
What is Wayland and what different with X11?
Hi! It's my first blog here, so let's start with the history of Wayland and its main topic.
Short description
Well generally Wayland is a new protocol for display managers for Linux and UNIX-like OSes. The developing process is started by Krisitian Hosberg as an free and open-source modern implemetation of X11. The main communication protocol is written in C as an shared library. The protocl has two main components:
Server side(libwayland-server).
Client side(libwayland-client).
How it works and what difference betwen Wayland and X11?
Let's start from the working process of Wayland.
So the core for Wayland server and client is an UNIX file sockets. And using the sockets the client and the server can share the information betwen each other.
Now about the server: Generally the Wayland server is called "Wayland compositor" because it's main purpose it's to create, manage, and composite the window buffers into one single, then post the buffer to the framebuffer via the GPU backend. The server and client can communicate betwen each other using the message or other type of IPC(Inter-Process communication).
So the short process of working the server is:
So when the Wayland display got an event, like the screen refresh or the mouse pointetr movement, the Wayland display start the searching of the event handler, if the handled didn't found it's ignored. Then if the event handler is found, it called with to main parameters:
struct wl_listener *listener - an body of the event, generally used by wl_container_of(an method to extract the structure that have the event from the listener structure)
void *data - Generally passed for an event that have an second inforamtion parameter. Like the mouse pointer movement, that have the X and Y coordinatates.
Then if the type is must return the any kind of return value, like for example the surface, then the server must map the specifed region of memory and using shared-memory IPC return it to the client, so the client can show the information on it. And when the surface is updated, generally by the client signal about the surface compositor, the server must render it or can ignore it, for example if the view didn't visible for user.
The user side is very simple it's just connected to the server socket and starts the communication process betwen server.
So what the main differences betwen Wayland and X11? So most visible and big difference betwen Wayland and X11 is the communication process betwen the display manager and the window manager. In X11 the window manager communicated betwen the X11 server itself to receive the external devices events and send info to the client, in Wayland the compositor is an display manager and the window manager in one. The client and the events directly sended to the compositor to process it.
Okay, okay you may have some questions about it all, but for more information, you can read the Wikipedia or other wiki.
How i can test the Wayland and what problems can be given?
Acording to the official Wayland page, the main and the etalony Wayland compositor is Weston. Just install it in our system and run just like any other package. The compositor can be started from any enviroment: X11, other Wayland compositor, or even the shell. The problems that can be given, generally caused by the video drivers, and the Nvidia design of DRM subsystem driver.
Or the sway is an i3-compatible compositor, we have very big list of the compositors, so i can't say what compositor is the best, just select your liked.
Thanks for reading!
1 note
·
View note
Text
OS変更(MacBook Air[Mid 2012])
作業内容
作業用ノートPC(MacBook Air[Mid 2012])のOSをLinux Mint 21 Xfce Editionに入れ換える
C,C++プログラミング作業の準備をする
手順1:事前準備
Windows10のPCで、Linux Mint 21 Xfce EditionのインストールUSBを作成する
Linux Mintの公式ホームページから、インストールDVDのISOファイルをダウンロードする
Rufusを使って、インストールUSBを作成する
手順2:OS入れ換え
Linux Mint 21 Xfce Editionのインストール
MacBook AirにインストールUSBを挿し、Optionキーを押しながら起動する
起動ストレージの選択でUSBアイコンをクリックする
インストーラーのメニューに��って、Linux Mint 21をインストールする
インストール終了後、インストールUSBを抜いて再起動する
OS確認
ログイン後、ターミナルから下記のコマンド操作を行う
taiyo@macbook-air:~$ cat /etc/os-release NAME="Linux Mint" VERSION="21 (Vanessa)" ID=linuxmint ID_LIKE="ubuntu debian" PRETTY_NAME="Linux Mint 21" VERSION_ID="21" HOME_URL="https://www.linuxmint.com/" SUPPORT_URL="https://forums.linuxmint.com/" BUG_REPORT_URL="http://linuxmint-troubleshooting-guide.readthedocs.io/en/latest/" PRIVACY_POLICY_URL="https://www.linuxmint.com/" VERSION_CODENAME=vanessa UBUNTU_CODENAME=jammy
ソフトウェアソースの設定
アプリケーションメニューから、「システム」→「ソフトウェアソース」を選択する
公式リポジトリのミラーを設定する
メイン:http://ftp.jaist.ac.jp/pub/Linux/linuxmint/packages
ベース:http://ftp.riken.jp/Linux/ubuntu
初回アップデート
タスクバーからアップデートマネージャーのアイコンをクリックして、アップデートパッケージをインストールする
日本語入力の設定
アプリケーションメニューから、「設定」→「入力方法」を選択する
「日本語」タブをクリックして、記載されている手順で設定操作を行う
手順3:プログラミング準備
C,C++のプログラミング準備
ターミナルから下記のコマンド操作を行う
taiyo@macbook-air:~$ sudo apt install build-essential [sudo] taiyo のパスワード: パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています... 完了 状態情報を読み取っています... 完了 以下の追加パッケージがインストールされます: g++ g++-11 libc-dev-bin libc-devtools libc6-dev libcrypt-dev libnsl-dev libstdc++-11-dev libtirpc-dev rpcsvc-proto 提案パッケージ: g++-multilib g++-11-multilib gcc-11-doc glibc-doc libstdc++-11-doc 以下のパッケージが新たにインストールされます: build-essential g++ g++-11 libc-dev-bin libc-devtools libc6-dev libcrypt-dev libnsl-dev libstdc++-11-dev libtirpc-dev rpcsvc-proto アップグレード: 0 個、新規インストール: 11 個、削除: 0 個、保留: 2 個。 16.1 MB のアーカイブを取得する必要があります。 この操作後に追加で 64.4 MB のディスク容量が消費されます。 続行しますか? [Y/n] Y [中略] build-essential (12.9ubuntu3) を設定しています ... man-db (2.10.2-1) のトリガを処理しています ... taiyo@macbook-air:~$ vim test.c taiyo@macbook-air:~$ cat test.c #include <stdio.h> int main(void) { printf("Hello C World.\n"); return 0; } taiyo@macbook-air:~$ gcc -o hello test.c taiyo@macbook-air:~$ ./hello Hello C World. taiyo@macbook-air:~$ vim test.cpp taiyo@macbook-air:~$ cat test.cpp #include <iostream> int main(void) { std::cout << "Hello C++ World." << std::endl; return 0; } taiyo@macbook-air:~$ g++ -o hello test.cpp taiyo@macbook-air:~$ ./hello Hello C++ World.
無線LAN経由で作業記録を記入するため、 PukiWikiサーバーまでSSHポート転送する
ターミナルから下記のコマンド操作を行う
taiyo@macbook-air:~$ mkdir Development taiyo@macbook-air:~$ vim Development/pf-pukiwiki.sh taiyo@macbook-air:~$ cat Development/pf-pukiwiki.sh #!/bin/bash ssh -fN -L 46200:192.168.20.60:46200 mac-mini.local taiyo@macbook-air:~$ sh Development/pf-pukiwiki.sh ([email protected]) Password:
PukiWiki確認
WEBブラウザから下記URLを開いて、PukiWikiの内容が表示されることを確認する
PukiWikiの記事を編集して、内容が更新されることを確認する
参照先:http://localhost:46200/WkWiki/
0 notes
Text
.NET Core Platform Agnostic Tracing
While working on a project recently I recommended implementing tracing in some components using .NET Event Sources and ETW. The company were using .NET Core and mix of Windows and Linux operating systems. The architecture team were looking for a platform agnsotic solution. ETW can't work on Linux because it's built into the Windows Kernal and also the clue's in the name Event Tracing for Windows.
Setup
I investigated and immediately found out about LTTng which could do everything needed:
tracing event sources
real time tracing
filtering
I bashed together a .NET Core console application that would trace a message using an Event Source and quickly tested it on Windows using an ETW trace viewer tool.
Event Source
using System.Diagnostics.Tracing; namespace ConsoleApp1 { [EventSource(Name = "TestEventSource")] public class TestEventSource : EventSource { public static readonly TestEventSource Current = new TestEventSource(); private TestEventSource() : base() { } public static class Keywords { public const EventKeywords Messages = (EventKeywords)0x1L; } private const int MessageEventId = 1; [Event(MessageEventId, Level = EventLevel.Informational, Message = "{0}", Keywords = Keywords.Messages)] public void Message(string message) { if (this.IsEnabled()) { WriteEvent(MessageEventId, message); } } } }
Main Program
using System; namespace ConsoleApp1 { class Program { static void Main(string[] args) { Console.WriteLine("Running trace event source test app..."); TestEventSource.Current.Message("Hello World!"); TestEventSource2.Current.Message("World Hello!"); } } }
Then I created a Ubuntu.18.04-x64 server in Azure and transferred the application. To build the .NET Core application for Ubuntu I used this command:
dotnet publish -c release -r ubuntu.18.04-x64
To install LTTng I used the following terminal commands:
apt-get install lttng-tools
apt-get install lttng-modules-dkms
apt-get install liblttng-ust-dev
LTTng has great docs here.
Then I installed the .NET Core SDK following these instructions.
Tracing to file storage
Run the following terminal commands:
lttng create jimssession lttng enable-event --userspace --tracepoint DotNETRuntime:EventSource lttng start
In order for this to work I had to enable the DotNETRuntime environment variable COMPlus_EnableEventLog. There are two ways to do this:
1. With the command to run the .NET Core App
COMPlus_EnableEventLog=1 dotnet ./publish/ConsoleApp1.dll
2. Seperately in the terminal and then it stays set
export COMPlus_EnableEventLog=1
Then you can just run your .NET Core app without using the 'dotnet' command:
./publish/ConsoleApp1
To view your trace output I used a tool called Babeltrace. I think this was with the LTTng install so should already be available.
Run these commands in the terminal to view your trace output:
lttng stop Babeltrace lttng-traces/jimssession-20181124-183519
When you initialised the session you will have been notified of this trace output folder path. Your traces should be shown below after executing the Babeltrace command above.

Real-Time Tracing (live-tracing)
For real time tracing I had to use two terminal sessions seeing as I was using one to execute my console application but if you have an application already running on a Linux machine then you wouldn't need to do that.
Here's what I did:
In terminal 1:
lttng create jimssession --live
lttng enable-event --userspace --tracepoint DotNETRuntime:EventSource
In terminal 2:
babeltrace --input-format=lttng-live net://localhost/host/machineName/jimssession
In terminal 1:
lttng start
and execute the app:
./publish/ConsoleApp1

Here's the output:
There are great instructions for this by Pavel Makhov here and you can easily do remote tracing using the --set-url parmater.
Filtering
With ETW you can filter by event source and that's very useful for reducing noise when you're debugging. I was expecting that the enable-event command parameter --tracepoint would be the event source name and to be honest spent a lot of time scratching my head and wondering why nothing was being traced until I figured out the parameter value must be DotNETRuntime:EventSource. Obviously if it were the event source name then filtering would be easy because you would just enable-event for each source you wished to trace. Well it is easy anyway because there is another parameter on the enable-event command --filter. So to filter by event source I was able to do this:
lttng enable-event --userspace --tracepoint DotNETRuntime:EventSource --filter '(EventSourceName == "TestEventSource")'
The filter syntax is well document here.
Using NET Core ILogger
As ILogger is the preferred method for Logging in NET Core I had to investigate the possibility of using this for tracing also. Event Source tracing is supported in NET Core using ILogger through the EventSource provider but there are some pretty extreme limitations. The docs also say "The provider is cross-platform, but there are no event collection and display tools yet for Linux or macOS" - Not true in a way as I was at least able to collect some traces on Linux using LTTng.
For the default setup you can just use logging.AddEventSourceLogger() as documented here or in my case because I was using a console app I had to do this:
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace ILoggerEventSourceLogging { class ILoggerTestEventSource { private readonly ILogger _logger; public ILoggerTestEventSource(ILogger logger) { _logger = logger; } static void Main(string[] args) { var serviceCollection = new ServiceCollection(); ConfigureServices(serviceCollection); var serviceProvider = serviceCollection.BuildServiceProvider(); var program = serviceProvider.GetService(); program._logger.LogInformation("Hello World"); } private static void ConfigureServices(IServiceCollection services) { services.AddLogging(configure => configure.AddEventSourceLogger()) .Configure(options => options.MinLevel = LogLevel.Information) .AddTransient(); } } }
So I tested this first with my goto ETW trace viewer and I didn't see any output? So I decided seeing as the docs here suggest using the Microsoft PerfView utility (download the exe for here) then I would try that.
I did manage to view my trace output as promised however I wasn't overly satisfied because I'm not a big fan of the PerfView interface:

You can see above that ILogger outputs four traces for each single log statement in your code:
EventSourceMessage
FormattedMessage
Message
MessageJson
Not having any success with my goto ETW trace viewer tool I decided to see if LTTng would capture the events on Linux. It did and here's the output:

First, you can see the four ILogger traces, second there is an error on the 'EventSourceMessage' Exception in Command Processing for EventSource Microsoft-Extensions-Logging: Object reference not set to an instance of an object.
So this suggests to me that the NET Core default EventSource provider does not conform properly to the EventSource format rules.
So to make this work with my goto ETW trace viewer tool and error free with LTTng I had to use a custom provider with ILogger.
Here's what you need:
The logging provider classes I used can be found here:
https://github.com/aspnet/Extensions/tree/master/src/Logging/Logging.EventSource/src
Event Source Logger
using System; using System.Collections.Generic; using System.Diagnostics.Tracing; using System.IO; using System.Linq; using System.Threading; using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace ILoggerEventSourceLogging { internal class EventSourceLogger : ILogger { private static int _activityIds; private readonly ILoggerEventSource _eventSource; private readonly int _factoryId; internal static readonly LogLevel LoggingDisabled = LogLevel.None + 1; public EventSourceLogger(string categoryName, int factoryId, ILoggerEventSource eventSource, EventSourceLogger next) { CategoryName = categoryName; // Default is to turn off logging Level = LoggingDisabled; _factoryId = factoryId; _eventSource = eventSource; Next = next; } public string CategoryName { get; } private LogLevel _level; public LogLevel Level { get { // need to check if the filter spec and internal event source level has changed and update the loggers level if it has _eventSource.ApplyFilterSpec(); return _level; } set { _level = value; } } // Loggers created by a single provider form a linked list public EventSourceLogger Next { get; } public bool IsEnabled(LogLevel logLevel) { return logLevel >= Level; } public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { if (!IsEnabled(logLevel)) { return; } // See if they want the formatted message if (_eventSource.IsEnabled(EventLevel.Critical, _eventSource.FormattedMessageKeyword)) { var message = formatter(state, exception); _eventSource.FormattedMessage(logLevel, _factoryId, CategoryName, eventId.ToString(), message); } #if !NO_EVENTSOURCE_COMPLEX_TYPE_SUPPORT // See if they want the message as its component parts. if (_eventSource.IsEnabled(EventLevel.Critical, _eventSource.MessageKeyword)) { var exceptionInfo = GetExceptionInfo(exception); var arguments = GetProperties(state); _eventSource.ExceptionMessage(logLevel, _factoryId, CategoryName, eventId.ToString(), exceptionInfo, arguments); } #endif // See if they want the json message if (_eventSource.IsEnabled(EventLevel.Critical, _eventSource.JsonMessageKeyword)) { var exceptionJson = "{}"; if (exception != null) { var exceptionInfo = GetExceptionInfo(exception); var exceptionInfoData = new[] { new KeyValuePair("TypeName", exceptionInfo.TypeName), new KeyValuePair("Message", exceptionInfo.Message), new KeyValuePair("HResult", exceptionInfo.HResult.ToString()), new KeyValuePair("VerboseMessage", exceptionInfo.VerboseMessage), }; exceptionJson = ToJson(exceptionInfoData); } var arguments = GetProperties(state); _eventSource.MessageJson(logLevel, _factoryId, CategoryName, eventId.ToString(), exceptionJson, ToJson(arguments)); } } public IDisposable BeginScope(TState state) { if (!IsEnabled(LogLevel.Critical)) { return NoopDisposable.Instance; } var id = Interlocked.Increment(ref _activityIds); // If JsonMessage is on, use JSON format if (_eventSource.IsEnabled(EventLevel.Critical, _eventSource.JsonMessageKeyword)) { var arguments = GetProperties(state); _eventSource.ActivityJsonStart(id, _factoryId, CategoryName, ToJson(arguments)); return new ActivityScope(_eventSource, CategoryName, id, _factoryId, true); } else { #if !NO_EVENTSOURCE_COMPLEX_TYPE_SUPPORT var arguments = GetProperties(state); _eventSource.ActivityStart(id, _factoryId, CategoryName, arguments); #else _eventSource.ActivityStart(id, _factoryID, CategoryName); #endif return new ActivityScope(_eventSource, CategoryName, id, _factoryId, false); } } private class ActivityScope : IDisposable { private readonly string _categoryName; private readonly int _activityId; private readonly int _factoryId; private readonly bool _isJsonStop; private readonly ILoggerEventSource _eventSource; public ActivityScope(ILoggerEventSource eventSource, string categoryName, int activityId, int factoryId, bool isJsonStop) { _categoryName = categoryName; _activityId = activityId; _factoryId = factoryId; _isJsonStop = isJsonStop; _eventSource = eventSource; } public void Dispose() { if (_isJsonStop) { _eventSource.ActivityJsonStop(_activityId, _factoryId, _categoryName); } else { _eventSource.ActivityStop(_activityId, _factoryId, _categoryName); } } } private class NoopDisposable : IDisposable { public static readonly NoopDisposable Instance = new NoopDisposable(); public void Dispose() { } } private ExceptionInfo GetExceptionInfo(Exception exception) { var exceptionInfo = new ExceptionInfo(); if (exception != null) { exceptionInfo.TypeName = exception.GetType().FullName; exceptionInfo.Message = exception.Message; exceptionInfo.HResult = exception.HResult; exceptionInfo.VerboseMessage = exception.ToString(); } return exceptionInfo; } private IEnumerable> GetProperties(object state) { var arguments = new List>(); var asKeyValues = state as IEnumerable>; if (asKeyValues != null) { arguments.AddRange(from keyValue in asKeyValues where keyValue.Key != null select new KeyValuePair(keyValue.Key, keyValue.Value?.ToString())); } return arguments; } private string ToJson(IEnumerable> keyValues) { var sw = new StringWriter(); var writer = new JsonTextWriter(sw) { DateFormatString = "O" }; writer.WriteStartObject(); foreach (var keyValue in keyValues) { writer.WritePropertyName(keyValue.Key, true); writer.WriteValue(keyValue.Value); } writer.WriteEndObject(); return sw.ToString(); } } }
Event Source Logger Provider
using System.Diagnostics.Tracing; using Microsoft.Extensions.Logging; namespace ILoggerEventSourceLogging { public class EventSourceLoggerProvider : ILoggerProvider { // A small integer that uniquely identifies the LoggerFactory assoicated with this LoggingProvider. // Zero is illegal (it means we are uninitialized), and have to be added to the factory. private int _factoryId; private LogLevel _defaultLevel; private string _filterSpec; private EventSourceLogger _loggers; private readonly ILoggerEventSource _eventSource; public EventSourceLoggerProvider(ILoggerEventSource eventSource, EventSourceLoggerProvider next = null) { _eventSource = eventSource; Next = next; } public EventSourceLoggerProvider Next { get; } public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) { // need to check if the filter spec and internal event source level has changed and update the _defaultLevel if it has _eventSource.ApplyFilterSpec(); var newLogger = _loggers = new EventSourceLogger(categoryName, _factoryId, _eventSource, _loggers); newLogger.Level = ParseLevelSpecs(_filterSpec, _defaultLevel, newLogger.CategoryName); return newLogger; } public void Dispose() { // Turn off any logging SetFilterSpec(null); } // Sets the filtering for a particular logger provider public void SetFilterSpec(string filterSpec) { _filterSpec = filterSpec; _defaultLevel = GetDefaultLevel(); // Update the levels of all the loggers to match what the filter specification asks for. for (var logger = _loggers; logger != null; logger = logger.Next) { logger.Level = ParseLevelSpecs(filterSpec, _defaultLevel, logger.CategoryName); } if (_factoryId == 0) { // Compute an ID for the Factory. It is its position in the list (starting at 1, we reserve 0 to mean unstarted). _factoryId = 1; for (var cur = Next; cur != null; cur = cur.Next) { _factoryId++; } } } private LogLevel GetDefaultLevel() { var allMessageKeywords = _eventSource.MessageKeyword | _eventSource.FormattedMessageKeyword | _eventSource.JsonMessageKeyword; if (_eventSource.IsEnabled(EventLevel.Informational, allMessageKeywords)) { return _eventSource.IsEnabled(EventLevel.Verbose, allMessageKeywords) ? LogLevel.Debug : LogLevel.Information; } if (_eventSource.IsEnabled(EventLevel.Warning, allMessageKeywords)) { return LogLevel.Warning; } return _eventSource.IsEnabled(EventLevel.Error, allMessageKeywords) ? LogLevel.Error : LogLevel.Critical; } private LogLevel ParseLevelSpecs(string filterSpec, LogLevel defaultLevel, string loggerName) { if (filterSpec == null) { return EventSourceLogger.LoggingDisabled; // Null means disable. } if (filterSpec == string.Empty) { return defaultLevel; } var level = EventSourceLogger.LoggingDisabled; // If the logger does not match something, it is off. // See if logger.Name matches a _filterSpec pattern. var namePos = 0; var specPos = 0; for (; ; ) { if (namePos < loggerName.Length) { if (filterSpec.Length <= specPos) { break; } var specChar = filterSpec[specPos++]; var nameChar = loggerName[namePos++]; if (specChar == nameChar) { continue; } // We allow wildcards at the end. if (specChar == '*' && ParseLevel(defaultLevel, filterSpec, specPos, ref level)) { return level; } } else if (ParseLevel(defaultLevel, filterSpec, specPos, ref level)) { return level; } // Skip to the next spec in the ; separated list. specPos = filterSpec.IndexOf(';', specPos) + 1; if (specPos <= 0) // No ; done. { break; } namePos = 0; // Reset where we are searching in the name. } return level; } private bool ParseLevel(LogLevel defaultLevel, string spec, int specPos, ref LogLevel ret) { var endPos = spec.IndexOf(';', specPos); if (endPos < 0) { endPos = spec.Length; } if (specPos == endPos) { // No :Num spec means Debug ret = defaultLevel; return true; } if (spec[specPos++] != ':') { return false; } var levelStr = spec.Substring(specPos, endPos - specPos); switch (levelStr) { case "Trace": ret = LogLevel.Trace; break; case "Debug": ret = LogLevel.Debug; break; case "Information": ret = LogLevel.Information; break; case "Warning": ret = LogLevel.Warning; break; case "Error": ret = LogLevel.Error; break; case "Critical": ret = LogLevel.Critical; break; default: int level; if (!int.TryParse(levelStr, out level)) { return false; } if (!(LogLevel.Trace <= (LogLevel)level && (LogLevel)level <= LogLevel.None)) { return false; } ret = (LogLevel)level; break; } return true; } } }
Exception Info
namespace ILoggerEventSourceLogging { #if !NO_EVENTSOURCE_COMPLEX_TYPE_SUPPORT [System.Diagnostics.Tracing.EventData(Name = "ExceptionInfo")] #endif public class ExceptionInfo { public string TypeName { get; set; } public string Message { get; set; } public int HResult { get; set; } public string VerboseMessage { get; set; } // This is the ToString() of the Exception } }
Logger Event Source Interface
using System.Collections.Generic; using System.Diagnostics.Tracing; using Microsoft.Extensions.Logging; namespace ILoggerEventSourceLogging { public interface ILoggerEventSource { ILoggerProvider CreateLoggerProvider(); void FormattedMessage(LogLevel level, int factoryId, string loggerName, string eventId, string formattedMessage); void ExceptionMessage(LogLevel level, int factoryId, string loggerName, string eventId, ExceptionInfo exception, IEnumerable<KeyValuePair<string, string>> arguments); void ActivityStart(int id, int factoryId, string loggerName, IEnumerable> arguments); void ActivityStop(int id, int factoryId, string loggerName); void MessageJson(LogLevel level, int factoryId, string loggerName, string eventId, string exceptionJson, string argumentsJson); void ActivityJsonStart(int id, int factoryId, string loggerName, string argumentsJson); void ActivityJsonStop(int id, int factoryId, string loggerName); bool IsEnabled(EventLevel level, EventKeywords keywords); void ApplyFilterSpec(); EventKeywords MetaKeyword { get; } EventKeywords MessageKeyword { get; } EventKeywords FormattedMessageKeyword { get; } EventKeywords JsonMessageKeyword { get; } } }
Event Source
using System.Collections.Generic; using System.Diagnostics.Tracing; using System.Text; using Microsoft.Extensions.Logging; namespace ILoggerEventSourceLogging { [EventSource(Name = "NetCoreLoggerEventSource")] public class NetCoreLoggerEventSource : EventSource, ILoggerEventSource { public static readonly NetCoreLoggerEventSource Current = new NetCoreLoggerEventSource(); #region Keywords public static class Keywords { // The four keywords below are part of the ASPNetCore logging implementation public const EventKeywords Meta = (EventKeywords)8; /// <summary> /// Turns on the 'Message' event when ILogger.Log() is called. It gives the information in a programatic (not formatted) way /// </summary> public const EventKeywords Message = (EventKeywords)16; /// <summary> /// Turns on the 'FormatMessage' event when ILogger.Log() is called. It gives the formatted string version of the information. /// </summary> public const EventKeywords FormattedMessage = (EventKeywords)32; /// <summary> /// Turns on the 'MessageJson' event when ILogger.Log() is called. It gives JSON representation of the Arguments. /// </summary> public const EventKeywords JsonMessage = (EventKeywords)64; } #endregion #region Code for implementing the ASPNet core logging ILoggerEventSource interface internal static readonly LogLevel LoggingDisabled = LogLevel.None + 1; private readonly object _providerLock = new object(); private string _filterSpec; private EventSourceLoggerProvider _loggingProviders; private bool _checkLevel; public ILoggerProvider CreateLoggerProvider() { lock (_providerLock) { var newLoggerProvider = new EventSourceLoggerProvider(this, _loggingProviders); _loggingProviders = newLoggerProvider; // If the EventSource has already been turned on. set the filters. if (_filterSpec != null) { newLoggerProvider.SetFilterSpec(_filterSpec); } return newLoggerProvider; } } public EventKeywords MetaKeyword => Keywords.Meta; public EventKeywords MessageKeyword => Keywords.Message; public EventKeywords FormattedMessageKeyword => Keywords.FormattedMessage; public EventKeywords JsonMessageKeyword => Keywords.JsonMessage; /// <summary> /// FormattedMessage() is called when ILogger.Log() is called. and the FormattedMessage keyword is active /// This only gives you the human reasable formatted message. /// </summary> #region FormattedMessage events public void FormattedMessage(LogLevel level, int factoryId, string loggerName, string eventId, string formattedMessage) { formattedMessage = formattedMessage ?? ""; switch (level) { case LogLevel.Critical: FormattedMessageCritical(factoryId, loggerName, eventId, formattedMessage); break; case LogLevel.Error: FormattedMessageError(factoryId, loggerName, eventId, formattedMessage); break; case LogLevel.Warning: FormattedMessageWarning(factoryId, loggerName, eventId, formattedMessage); break; case LogLevel.Information: FormattedMessageInformational(factoryId, loggerName, eventId, formattedMessage); break; case LogLevel.Debug: case LogLevel.Trace: FormattedMessageVerbose(factoryId, loggerName, eventId, formattedMessage); break; } } private const int FormattedMessageIdCritical = 111; private const int FormattedMessageIdError = 112; private const int FormattedMessageIdWarning = 113; private const int FormattedMessageIdInformational = 114; private const int FormattedMessageIdVerbose = 115; [Event(FormattedMessageIdCritical, Keywords = Keywords.FormattedMessage, Level = EventLevel.Critical, Message = "{3}")] private void FormattedMessageCritical(int factoryId, string loggerName, string eventId, string formattedMessage) { WriteEvent(FormattedMessageIdCritical, factoryId, loggerName, eventId, formattedMessage); } [Event(FormattedMessageIdError, Keywords = Keywords.FormattedMessage, Level = EventLevel.Error, Message = "{3}")] private void FormattedMessageError(int factoryId, string loggerName, string eventId, string formattedMessage) { WriteEvent(FormattedMessageIdError, factoryId, loggerName, eventId, formattedMessage); } [Event(FormattedMessageIdWarning, Keywords = Keywords.FormattedMessage, Level = EventLevel.Warning, Message = "{3}")] private void FormattedMessageWarning(int factoryId, string loggerName, string eventId, string formattedMessage) { WriteEvent(FormattedMessageIdWarning, factoryId, loggerName, eventId, formattedMessage); } [Event(FormattedMessageIdInformational, Keywords = Keywords.FormattedMessage, Level = EventLevel.Informational, Message = "{3}")] private void FormattedMessageInformational(int factoryId, string loggerName, string eventId, string formattedMessage) { WriteEvent(FormattedMessageIdInformational, factoryId, loggerName, eventId, formattedMessage); } [Event(FormattedMessageIdVerbose, Keywords = Keywords.FormattedMessage, Level = EventLevel.Verbose, Message = "{3}")] private void FormattedMessageVerbose(int factoryId, string loggerName, string eventId, string formattedMessage) { WriteEvent(FormattedMessageIdVerbose, factoryId, loggerName, eventId, formattedMessage); } #endregion FormattedMessage events #region ExceptionMessage events [NonEvent] public void ExceptionMessage(LogLevel level, int factoryId, string loggerName, string eventId, ExceptionInfo exception, IEnumerable> arguments) { var message = new StringBuilder(); foreach (var arg in arguments) message.Append($"{arg.Key} - {arg.Value}"); ExceptionMessage(level, factoryId, loggerName, eventId, exception.Message, message.ToString()); } public void ExceptionMessage(LogLevel level, int factoryId, string loggerName, string eventId, string exception, string message) { exception = exception ?? ""; message = message ?? ""; switch (level) { case LogLevel.Critical: ExceptionMessageCritical(factoryId, loggerName, eventId, exception, message); break; case LogLevel.Error: ExceptionMessageError(factoryId, loggerName, eventId, exception, message); break; case LogLevel.Warning: ExceptionMessageWarning(factoryId, loggerName, eventId, exception, message); break; case LogLevel.Information: ExceptionMessageInformational(factoryId, loggerName, eventId, exception, message); break; case LogLevel.Debug: case LogLevel.Trace: ExceptionMessageVerbose(factoryId, loggerName, eventId, exception, message); break; } } private const int ExceptionMessageIdCritical = 121; private const int ExceptionMessageIdError = 122; private const int ExceptionMessageIdWarning = 123; private const int ExceptionMessageIdInformational = 124; private const int ExceptionMessageIdVerbose = 125; [Event(ExceptionMessageIdCritical, Keywords = Keywords.Message, Level = EventLevel.Critical, Message = "{4}")] public void ExceptionMessageCritical(int factoryId, string loggerName, string eventId, string exception, string message) { WriteEvent(ExceptionMessageIdCritical, factoryId, loggerName, eventId, exception, message); } [Event(ExceptionMessageIdError, Keywords = Keywords.Message, Level = EventLevel.Error, Message = "{4}")] public void ExceptionMessageError(int factoryId, string loggerName, string eventId, string exception, string message) { WriteEvent(ExceptionMessageIdError, factoryId, loggerName, eventId, exception, message); } [Event(ExceptionMessageIdWarning, Keywords = Keywords.Message, Level = EventLevel.Warning, Message = "{4}")] public void ExceptionMessageWarning(int factoryId, string loggerName, string eventId, string exception, string message) { WriteEvent(ExceptionMessageIdWarning, factoryId, loggerName, eventId, exception, message); } [Event(ExceptionMessageIdInformational, Keywords = Keywords.Message, Level = EventLevel.Informational, Message = "{4}")] public void ExceptionMessageInformational(int factoryId, string loggerName, string eventId, string exception, string message) { WriteEvent(ExceptionMessageIdInformational, factoryId, loggerName, eventId, exception, message); } [Event(ExceptionMessageIdVerbose, Keywords = Keywords.Message, Level = EventLevel.Verbose, Message = "{4}")] public void ExceptionMessageVerbose(int factoryId, string loggerName, string eventId, string exception, string message) { WriteEvent(ExceptionMessageIdVerbose, factoryId, loggerName, eventId, exception, message); } #endregion ExceptionMessage events #region MessageJson events public void MessageJson(LogLevel level, int factoryId, string loggerName, string eventId, string exceptionJson, string argumentsJson) { exceptionJson = exceptionJson ?? ""; argumentsJson = argumentsJson ?? ""; switch (level) { case LogLevel.Critical: MessageJsonCritical(factoryId, loggerName, eventId, exceptionJson, argumentsJson); break; case LogLevel.Error: MessageJsonError(factoryId, loggerName, eventId, exceptionJson, argumentsJson); break; case LogLevel.Warning: MessageJsonWarning(factoryId, loggerName, eventId, exceptionJson, argumentsJson); break; case LogLevel.Information: MessageJsonInformational(factoryId, loggerName, eventId, exceptionJson, argumentsJson); break; case LogLevel.Debug: case LogLevel.Trace: MessageJsonVerbose(factoryId, loggerName, eventId, exceptionJson, argumentsJson); break; } } private const int MessageJsonIdCritical = 131; private const int MessageJsonIdError = 132; private const int MessageJsonIdWarning = 133; private const int MessageJsonIdInformational = 134; private const int MessageJsonIdVerbose = 135; [Event(MessageJsonIdCritical, Keywords = Keywords.JsonMessage, Level = EventLevel.Critical, Message = "{4}")] private void MessageJsonCritical(int factoryId, string loggerName, string eventId, string exceptionJson, string argumentsJson) { WriteEvent(MessageJsonIdCritical, factoryId, loggerName, eventId, exceptionJson, argumentsJson); } [Event(MessageJsonIdError, Keywords = Keywords.JsonMessage, Level = EventLevel.Error, Message = "{4}")] private void MessageJsonError(int factoryId, string loggerName, string eventId, string exceptionJson, string argumentsJson) { WriteEvent(MessageJsonIdError, factoryId, loggerName, eventId, exceptionJson, argumentsJson); } [Event(MessageJsonIdWarning, Keywords = Keywords.JsonMessage, Level = EventLevel.Warning, Message = "{4}")] private void MessageJsonWarning(int factoryId, string loggerName, string eventId, string exceptionJson, string argumentsJson) { WriteEvent(MessageJsonIdWarning, factoryId, loggerName, eventId, exceptionJson, argumentsJson); } [Event(MessageJsonIdInformational, Keywords = Keywords.JsonMessage, Level = EventLevel.Informational, Message = "{4}")] private void MessageJsonInformational(int factoryId, string loggerName, string eventId, string exceptionJson, string argumentsJson) { WriteEvent(MessageJsonIdInformational, factoryId, loggerName, eventId, exceptionJson, argumentsJson); } [Event(MessageJsonIdVerbose, Keywords = Keywords.JsonMessage, Level = EventLevel.Verbose, Message = "{4}")] private void MessageJsonVerbose(int factoryId, string loggerName, string eventId, string exceptionJson, string argumentsJson) { WriteEvent(MessageJsonIdVerbose, factoryId, loggerName, eventId, exceptionJson, argumentsJson); } #endregion MessageJson events [NonEvent] public void ActivityStart(int id, int factoryId, string loggerName, IEnumerable> arguments) { var message = new StringBuilder(); foreach (var arg in arguments) message.Append($"{arg.Key} - {arg.Value}"); ActivityStart(id, factoryId, loggerName, message.ToString()); } /// <summary> /// ActivityStart is called when ILogger.BeginScope() is called /// </summary> private const int ActivityStartId = 141; [Event(ActivityStartId, Keywords = Keywords.Message | Keywords.FormattedMessage, Level = EventLevel.Informational, ActivityOptions = EventActivityOptions.Recursive, Message = "{3}")] public void ActivityStart(int id, int factoryId, string loggerName, string message) { WriteEvent(ActivityStartId, id, factoryId, loggerName, message); } private const int ActivityStopId = 142; [Event(ActivityStopId, Keywords = Keywords.Message | Keywords.FormattedMessage, Level = EventLevel.Informational, Message = "")] public void ActivityStop(int id, int factoryId, string loggerName) { WriteEvent(ActivityStopId, id, factoryId, loggerName); } private const int ActivityJsonStartId = 143; [Event(ActivityJsonStartId, Keywords = Keywords.JsonMessage | Keywords.FormattedMessage, Level = EventLevel.Informational, ActivityOptions = EventActivityOptions.Recursive, Message = "{3}")] public void ActivityJsonStart(int id, int factoryId, string loggerName, string argumentsJson) { WriteEvent(ActivityJsonStartId, id, factoryId, loggerName, argumentsJson); } private const int ActivityJsonStopId = 144; [Event(ActivityJsonStopId, Keywords = Keywords.JsonMessage | Keywords.FormattedMessage, Level = EventLevel.Informational, Message = "")] public void ActivityJsonStop(int id, int factoryId, string loggerName) { WriteEvent(ActivityJsonStopId, id, factoryId, loggerName); } protected override void OnEventCommand(EventCommandEventArgs command) { lock (_providerLock) { if (command.Command == EventCommand.Update || command.Command == EventCommand.Enable) { string filterSpec; if (!command.Arguments.TryGetValue("FilterSpecs", out filterSpec)) { filterSpec = string.Empty; // This means turn on everything. } SetFilterSpec(filterSpec); } else if (command.Command == EventCommand.Update || command.Command == EventCommand.Disable) { SetFilterSpec(null); // This means disable everything. } } } /// <summary> /// Set the filtering specifcation. null means turn off all loggers. Empty string is turn on all providers. /// </summary> /// [NonEvent] private void SetFilterSpec(string filterSpec) { _filterSpec = filterSpec; // In .NET 4.5.2 the internal EventSource level hasn't been correctly set // when this callback is invoked. To still have the logger behave correctly // in .NET 4.5.2 we delay checking the level until the logger is used the first // time after this callback. _checkLevel = true; } [NonEvent] public void ApplyFilterSpec() { lock (_providerLock) { if (_checkLevel) { for (var cur = _loggingProviders; cur != null; cur = cur.Next) { cur.SetFilterSpec(_filterSpec); } _checkLevel = false; } } } #endregion } }
Main Program
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace ILoggerEventSourceLogging { class Program { private readonly ILogger _logger; public Program(ILogger logger) { _logger = logger; } static void Main(string[] args) { var serviceCollection = new ServiceCollection(); ConfigureServices(serviceCollection); var serviceProvider = serviceCollection.BuildServiceProvider(); var program = serviceProvider.GetService(); program._logger.LogInformation("Hello World from Jim"); } private static void ConfigureServices(IServiceCollection services) { services.AddLogging(configure => configure.ClearProviders().AddProvider(NetCoreLoggerEventSource.Current.CreateLoggerProvider())) .Configure(options => options.MinLevel = LogLevel.Information) .AddTransient(); } } }
So using this custom log provider I had success and was able to view the traces in my usual ETW trace viewer tool and also on Linux there were now no errors in the output:

and no more errors on Linux with LTTng:

References
http://blogs.microsoft.co.il/sasha/2017/03/30/tracing-runtime-events-in-net-core-on-linux/
https://lttng.org/blog/2018/08/28/bringing-dotnet-perf-analysis-to-linux/
https://lttng.org/
https://lttng.org/docs/v2.10/#doc-lttng-live
https://lttng.org/docs/v2.10/#doc-ubuntu
https://lttng.org/man/1/lttng-enable-event/v2.10/
https://lttng.org/blog/2017/11/22/lttng-ust-blocking-mode/
https://pavelmakhov.com/2017/01/lttng-streaming
https://www.microsoft.com/net/download/linux-package-manager/ubuntu18-04/sdk-current
https://lttng.org/man/1/lttng-enable-event/v2.10/#doc-filter-syntax
http://ctpd.dorsal.polymtl.ca/system/files/TracingSummit2015-LTTngFilteringeBPF.pdf
https://blogs.msdn.microsoft.com/luisdem/2017/03/19/net-core-1-1-how-to-publish-a-self-contained-application
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-2.1#eventsource-provider
https://www.blinkingcaret.com/2018/02/14/net-core-console-logging/
https://codeblog.dotsandbrackets.com/profiling-net-core-app-linux/
1 note
·
View note
Text
How to Install Flutter Software Development Kit in Linux Systems?

Many app developers wish to use flutter as an excellent platform for mobile and web application interfaces. A flutter is a fast-rising tool among many developers. If you run an organization and need an app, you can hire flutter developer and pick up service.
It is famous for a single codebase and works well on the existing code. App Developers and organizations use such a thing because of free and open source. You have a remarkable ability to create cross-platform applications for Android, Windows, iOS, Linux, and others.
Set up a flutter quickly:
It is necessary to focus on the hardware and software requirement before installing flutter on Linux.
Disk space – 600MB plus space for dependent software tools and IDE
Operating system – Linux 64 bit
Software tools – unzip, bash, mkdir, git, curl, and others
There are different ways you install a cross-platform on Linux. People can install a flutter manually or snap. It would help if you switched to the snap package and set up and set up an android studio. It is the best way to save time and effort.
Install flutter:
First, go to the terminal and install the snap package for the flutter by following the excellent command.
sudo snap install flutter --classic
After that, it asks you to search for passwords and enter them, and is ready to move.
People use a software center to install a platform and search flutter quickly.
Complete installation and run a command to make sure that packages install correctly.
Whether you get welcome to flutter, your package is ready and moves to a different process.
Install and organize android studio:
Once flutter SDK installation is over, you can get ready to use the Android SDK.
You need to install the android studio and begin work.
Install android studio by going to the terminal and running the relevant command.
It asks you to search for a password and enter them correctly.
You can utilize the software center to install the android studio, look for the latest version of Android SDK, and click on install.
After you set up an android studio, you can start using them.
sudo snap install android-studio --classic
You must confirm some critical things in the setting and go with the default. Then, you can follow details until android studio begins to install SDK and other elements.
Arrange a flutter and agree to the android license:
If you finish step 2, you can organize flutter in a device and accept the android license. Developers carefully follow simple instructions to set up cross-platform. It is essential to focus on reputation to hire senior Flutter engineer. They provide complete details about everything to you.
You can move to the required place and run a command after finishing the android studio installation.
It is easy to configure the android studio directory to package that you download android studio.
Then, run the command and open the android license.
You should accept the license as much as possible when you ask for input.
When you finish accepting the android license, you can complete the SDK set up in the device.
Validate a flutter set up:
You must set up the flutter properly in the device and verify them carefully. Verification is an important step to check anything missing in the setup. It is the best way to prevent significant problems when running.
Users should run the command to find something that is left. Whether everything is fine, you will acquire the exact output. Users can gain a tick on VS code and chrome once the package installs correctly.
Run the code:
Users keep fluttering perfectly in a device and run code. You can test sample code and understand how it works. Organizations hire flutter developer to learn how code runs and delivers accurate output.
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), ); } }
Easy to understand and learn:
Flutter is a contemporary framework and helps developers and organizations in different forms. It is the most straightforward platform to develop apps. App developers learn the platform quickly and work with various projects without hassle.
To hire flutter developer, you can quickly access the app and implement the right strategy for the organization process.
It is an excellent solution to build apps without any code.
Platform influences client optimized programming language like a dart.
Dart is highly popular because it is productive, easy to comprehend, fast, and scalable.
You may also use an online resource to gain better training. Training documentation is helpful to boost flutter skills and knowledge. The framework performs well on the low-end devices.
Develop versatile applications:
Flutter comes up with many exciting features that allow developers to build an app. You can come across built-in widgets and develop a customized application.
Widgets are a unique element for creating eye-catching user interfaces and delivering a perfect experience to users. Depending on your wish, you have a great chance to make your widget.
A newly built mobile app will appear on the existing version of the system. It is better to construct high-performance apps in diverse domains like education, utility, entertainment, fitness, ecommerce, and more.
App development becomes simple and easy and reduces the third-party integration when using flutter.
It is easy to share the app with potential customers.
Developers assist you in creating an app with the number one development tool.
So, you can access the proper assistance today and gain the ideal support and service to build an app with the necessary features. The platform allows you to make a modification in the app.
Conclusion:
Organizations and developers dive into cross-platform development space confidently. The above details help you understand more about installation and setting up flutter on Linux. flutteragency.com allows you to configure flutter SDK and android studio with flutter and dart and take app development to the next level.
0 notes
Text
Managing a .NET Service with Blazor
In this post I will show you how creating a cross-platform and managing a .NET Service with Blazor that can be installed on Windows (Service) and Linux (systemd).
There is a lot of information on how to run a .NET project as a service, on Windows and on Linux (Mac is not supported yet). I will provide a sample project on GitHub and will only show some of the basics here.
The most interesting part for me is hosting a Blazor Server application with Kestrel as a service on both Windows and Linux. This gives endless possibilities in managing the service, not even from the system itself but also remotely.
Managing service with Blazor
First we create a normal Blazor Server project. I keep the project as-is and just add a few classes to demonstrate the use of Blazor in the service.
Adding the background service
Create a class called CustomBackgroundService. I use the BackgroundService as a base class but I could also implement IHostedService. More information about the different types can be found here.
This service is just logging and then waiting for 5 seconds to simulate a process that runs for a while:
public class CustomBackgroundService : BackgroundService { public bool IsRunning { get; set; } private readonly ILogger<CustomBackgroundService> _logger; public CustomBackgroundService(ILogger<CustomBackgroundService> logger) => _logger = logger; protected override async Task ExecuteAsync(CancellationToken stoppingToken) { try { _logger.LogInformation($"{nameof(CustomBackgroundService)} starting {nameof(ExecuteAsync)}"); IsRunning = true; while (!stoppingToken.IsCancellationRequested) { _logger.LogInformation($"{nameof(CustomBackgroundService)} running {nameof(ExecuteAsync)}"); await Task.Delay(5000); } IsRunning = false; _logger.LogInformation($"{nameof(CustomBackgroundService)} ending {nameof(ExecuteAsync)}"); } catch (Exception exception) { _logger.LogError(exception.Message, exception); } finally { IsRunning = false; } } }
Registering and adding the hosted service:
services .AddLogging(logging => logging.AddConsole()) .AddSingleton<WeatherForecastService>() .AddSingleton<CustomBackgroundService>() .AddHostedService(serviceCollection => serviceCollection.GetRequiredService<CustomBackgroundService>());
I added a new Razor page and added it to the menu (Pages/Service.razor):
@page "/Service" @inject CustomBackgroundService _customBackgroundService <h3>Service</h3> <p><div hidden="@HideIsRunning">Running</div></p> <button name="startButton" class="btn btn-primary" @onclick="Start">Start</button> <button class="btn btn-primary" @onclick="Stop">Stop</button> @code { private bool _isRunning { get; set; } public bool HideIsRunning => !_isRunning; protected override void OnInitialized() { _isRunning = _customBackgroundService.IsRunning; base.OnInitialized(); } private async Task Start() { if(!_customBackgroundService.IsRunning) await _customBackgroundService.StartAsync(new System.Threading.CancellationToken()); _isRunning = _customBackgroundService.IsRunning; } private async Task Stop() { if(_customBackgroundService.IsRunning) await _customBackgroundService.StopAsync(new System.Threading.CancellationToken()); _isRunning = _customBackgroundService.IsRunning; } }
Adding a new menu item to the default Blazor application by changing `Shared/NavMenu.razor’:
<div class="nav-item px-3"> <NavLink class="nav-link" href="Service"> <span class="oi oi-pulse" aria-hidden="true"></span> Service </NavLink> </div>
When debugging the project this should be visible:
Blazor with running service
you can start and stop the service and check the console of your IDE to see the output:
Output from the service
Running and installing the service
To run the application as a Service the following code has to be added to the Program.cs:
public static void Main(string[] args) { var isService = !(Debugger.IsAttached || args.Contains("--console")); if (isService) Directory.SetCurrentDirectory(Environment.ProcessPath!); var builder = CreateHostBuilder(args.Where(arg => arg != "--console").ToArray()); if (isService) { if (OperatingSystem.IsWindows()) builder.UseWindowsService(); else if (OperatingSystem.IsLinux()) builder.UseSystemd(); else throw new InvalidOperationException( $"Can not run this application as a service on this Operating System"); } builder.Build().Run(); }
Next, install the following Nuget packages:
Windows: Microsoft.Extensions.Hosting.WindowsServices
Linux: Microsoft.Extensions.Hosting.Systemd
.NET Service on Windows
First, publish the application to a folder. Make sure to create the correct publish profile for Windows. Also, consider if you need to publish it Framework-Dependent (the .NET framework has to be installed on the host machine) or Self-Contained (everything needed is included, how cool is that!):
.NET Launch Settings Profile
After publishing, open a Powershell command line, go to the directory conaining the newly published service and execute the following commands:
New-Service -Name “Blazor Background Service” -BinaryPath .\BlazorBackgroundservice.BlazorUI.exe
PowerShell registers the Blazor service
Start-Service -Name “BlazorBackgroundService”
PowerShell starts the new service
I could write logs to the Event Logger but I decided to write simple logs to a text file. When you look into the directory of the service you should see a logfile log****.txt. Look into the logfile to see if the service is running. When going to the url’s provided in the logfile be aware that the https port might not work because there are no valid SSL certificates installed.
Logging on Windows
.NET Service on Linux
Same as for Windows: publish the application to a folder, using the correct publish configuration. I can test the application by adding --console to the command line:
Running on Arch Linux
To install it as a service I created the file in/etc/systemd/system/blazorbackgroundservice.service:
[Unit] Description=Blazor Background Service [Service] Type=Notify ExecStart=/home/jacob/blazorbackgroundservice/linux/BlazorBackgroundService.BlazorUI [Install] WantedBy=multi-user.target
Run the following commands:
sudo systemctl daemon-reload sudo systemctl status blazorbackgroundservice
Stopped service
sudo systemctl start blazorbackgroundservice sudo systemctl status blazorbackgroundservice
It works! Check the status output for the url of the Blazor website and browse to the site to check if it works.
You can even auto-start the service by running the following command:
sudo systemctl enable blazorbackgroundservice
Next time you reboot, the service will automatically start.
Resources
Microsoft.Extensions.Hosting.WindowsServices
Microsoft.Extensions.Hosting.Systemd
Background tasks with hosted services in ASP.NET Core
The post Managing a .NET Service with Blazor appeared first on PureSourceCode.
from WordPress https://www.puresourcecode.com/dotnet/blazor/managing-a-net-service-with-blazor/
0 notes
Text
Slack Web

Download Slack
Slack Webinar
Slack Web App
Slack Webex
The @slack/web-api package contains a simple, convenient, and configurable HTTP client for making requests to Slack’sWeb API. Use it in your app to call any of the over 130methods, and let it handle formatting, queuing, retrying, pagination, and more.
Installation
Initialize the client
You’re invited to join the discussion about all things related to Amazon Web Services on Slack. Click here to get started. You will be asked for your email address and will be sent an invite. Once there, choose your channel. Our #general channel is for anyone keen to discuss AWS related topics. The Slack Web API is an interface for querying information from and enacting change in a Slack workspace. Use it on the fly for ad-hoc queries, or as part of a more complex tapestry of platform features in a Slack app. What can you do with the Web API? Web Client The Slack Web API allows you to build applications that interact with Slack in more complex ways than the integrations we provide out of the box. Access Slack’s API methods requires an OAuth token – see the Tokens & Authentication section for more on how Slack uses OAuth tokens as well as best practices. Slack provides mobile apps for iOS and Android in addition to their Web browser client and desktop clients for macOS, Windows (with versions available from the company's website and through the Windows Store), and Linux (beta). Slack is also available for the Apple Watch, allowing users to send direct messages, see mentions, and make simple replies.
The package exports a WebClient class. All you need to do is instantiate it, and you’re ready to go. You’ll typicallyinitialize it with a token, so that you don’t have to provide the token each time you call a method. A token usuallybegins with xoxb or xoxp. You get them from each workspace an app is installed onto. The app configuration pageshelp you get your first token for your development workspace.
Initializing without a token
Alternatively, you can create a client without an token, and use it with multiple workspaces as long as you supply atoken when you call a method.
Call a method
The client instance has a named method for each of the public methods in the Web API. The most popular one iscalled chat.postMessage, and its used to send a message to a conversation. For every method, you pass arguments asproperties of an options object. This helps with the readablility of your code since every argument has a name. Allnamed methods return a Promise which resolves with the response data, or rejects with an error.
Hint: If you’re using an editor that supports TypeScript, even if you’re not using TypeScript to write your code,you’ll get hints for all the arguments each method supports. This helps you save time by reducing the number oftimes you need to pop out to a webpage to check the reference. There’s more information about usingTypeScript with this package in the documentation website.
Note: Use the Block Kit Builder for a playgroundwhere you can prototype your message’s look and feel.
Using a dynamic method name
If you want to provide the method name as a string, so that you can decide which method to call dynamically, or to calla method that might not be available in your version of the client, use the WebClient.apiCall(methodName, (options))method. The API method call above can also be written as follows:
Handle errors
Errors can happen for many reasons: maybe the token doesn’t have the proper scopes tocall a method, maybe its been revoked by a user, or maybe you just used a bad argument. In these cases, the returnedPromise will reject with an Error. You should catch the error and use the information it contains to decide how yourapp can proceed.
Each error contains a code property, which you can check against the ErrorCode export to understand the kind oferror you’re dealing with. For example, when Slack responds to your app with an error, that is anErrorCode.PlatformError. These types of errors provide Slack’s response body as the data property.
More error types
There are a few more types of errors that you might encounter, each with one of these codes:
ErrorCode.RequestError: A request could not be sent. A common reason for this is that your network connection isnot available, or api.slack.com could not be reached. This error has an original property with more details.
ErrorCode.RateLimitedError: The Web API cannot fulfill the API method call because your app has made too manyrequests too quickly. This error has a retryAfter property with the number of seconds you should wait before tryingagain. See the documentation on rate limit handling tounderstand how the client will automatically deal with these problems for you.
ErrorCode.HTTPError: The HTTP response contained an unfamiliar status code. The Web API only responds with 200(yes, even for errors) or 429 (rate limiting). If you receive this error, its likely due to a problem with a proxy,a custom TLS configuration, or a custom API URL. This error has the statusCode, statusMessage, headers, andbody properties containing more details.
Pagination
Many of the Web API’s methods returnlists of objects, and are known to be cursor-paginated. The result of calling these methods will contain a part ofthe list, or a page, and also provide you with information on how to continue to the next page on a subsequent API call.Instead of calling many times manually, the WebClient can manage getting each page, allowing you to determine when tostop, and help you process the results.
The process of retrieving multiple pages from Slack’s API can be described as asynchronous iteration, which meansyou’re processing items in a collection, but getting each item is an asynchronous operation. Fortunately, JavaScripthas this concept built in, and in newer versions of the language there’s syntax to make it even simpler:for await..of.
The for await..of syntax is available in Node v10.0.0 and above. If you’re using an older version of Node, seefunctional iteration below.
Using functional iteration
The .paginate() method can accept up to two additional parameters. The third parameter, stopFn, is a function thatis called once for each page of the result, and should return true when the app no longer needs to get another page.The fourth parameter is reducerFn, which is a function that gets called once for each page of the result, but canbe used to aggregate a result. The value it returns is used to call it the next time as the accumulator. The firsttime it gets called, the accumulator is undefined.
The returned value is a Promise, but what it resolves to depends on whether or not you include the fourth (optional)parameter. If you don’t include it, the resolved value is always undefined. In this case, its used for control flowpurposes (resuming the rest of your program), and the function in the third parameter is used to capture a result. Ifyou do include the fourth parameter, then the resolved value is the value of the accumulator. This is a familiarpattern for people that use functional programming.
Opening modals
Modals can be created by calling the views.open method. The method requires you to pass a valid view payload in addition to a trigger_id, which can be obtained when a user invokes your app using a slash command, clicking a button, or using another interactive action.
Dynamically updating a modal
After the modal is opened, you can update it dynamically by calling views.update with the view ID returned in the views.open result.
Logging
The WebClient will log interesting information to the console by default. You can use the logLevel to decide howmuch information, or how interesting the information needs to be, in order for it to be output. Mac lip pencil in soar. There are a few possiblelog levels, which you can find in the LogLevel export. By default, the value is set to LogLevel.INFO. While you’rein development, its sometimes helpful to set this to the most verbose: LogLevel.DEBUG.
All the log levels, in order of most to least information are: DEBUG, INFO, WARN, and ERROR.
Sending log output somewhere besides the console
You can also choose to have logs sent to a custom logger using the logger option. A custom logger needs to implementspecific methods (known as the Logger interface):
MethodParametersReturn typesetLevel()level: LogLevelvoidsetName()name: stringvoiddebug()..msgs: any()voidinfo()..msgs: any()voidwarn()..msgs: any()voiderror()..msgs: any()void
A very simple custom logger might ignore the name and level, and write all messages to a file.
Automatic retries
In production systems, you want your app to be resilient to short hiccups and temporary outages. Solving for thisproblem usually involves building a queuing system that handles retrying failed tasks. The WebClient comes with thisqueuing system out of the box, and its on by default! The client will retry a failed API method call up to 10 times,spaced out over about 30 minutes. If the request doesn’t succeed in that time, then the returned Promise will reject.You can observe each of the retries in your logs by setting the log level to DEBUG. Try running thefollowing code with your network disconnected, and then re-connect after you see a couple of log messages:
Shortly after re-connecting your network, you should see the Done! message. Did you notice the program doesn’t use avalid token? The client is doing something clever and helpful here. It knows the difference between an error such as notbeing able to reach api.slack.com and an error in the response from Slack about an invalid token. The former issomething that can be resolved with a retry, so it was retried. The invalid token error means that the call isn’t goingto succeed until your app does something differently, so it stops attempting retries.
You might not think 10 reties in 30 minutes is a good policy for your app. No problem, you can set the retryConfig toone that works better for you. The retryPolicies export contains a few well known options, and you can always writeyour own.
Here are some other values that you might want to use for retryConfig:
retryConfigDescriptionretryPolicies.tenRetriesInAboutThirtyMinutes(default)retryPolicies.fiveRetriesInFiveMinutesFive attempts in five minutesretryPolicies.rapidRetryPolicyUsed to keep tests running fast( retries: 0 )No retries (other options)
Note: If an API call results in a rate limit being exceeded, you might still notice the client automaticallyretrying the API call. If you’d like to opt out of that behavior, set the rejectRateLimitedCalls option to true.
Upload a file
A couple methods, files.upload and users.setPhoto, allow you to upload a file over the API. In Node, there are a fewways you might be dealing with files, or more generally, binary data. When you have the whole file in memory (like whenyou’ve just generated or processed an image), then in Node you’d have a Buffer that contains that binary data. Or,when you are reading the file from disk or a network (like when you have a path to file name), then you’d typically havea ReadableStream. The client can handle both of these binary data types for you, and it looks like any other API call.
The following example shows how you can use files.upload to upload afile that is read from disk (as a ReadableStream).
In the example above, you could also use a Buffer object as the value for the file property of the options object.
Proxy requests with a custom agent
The client allows you to customize the HTTPAgent used to create the connection to Slack.Using this option is the best way to make all requests from your app through a proxy, which is a common requirement inmany corporate settings.

In order to create an Agent from some proxy information (such as a host, port, username, and password), you can useone of many npm packages. We recommend https-proxy-agent. Startby installing this package and saving it to your package.json.
Import the HttpsProxyAgent class, and create an instance that can be used as the agent option of the WebClient.
Rate limits
When your app calls API methods too frequently, Slack will politely ask (by returning an error) the app to slow down,and also let your app know how many seconds later it should try again. This is called rate limiting and theWebClient handles it for your app with grace. The client will understand these rate limiting errors, wait theappropriate amount of time, and then retry the request without any changes in your code. The Promise returned onlyresolves when Slack has given your app a real response.
It’s a good idea to know when you’re bumping up against these limits, so thatyou might be able to change the behavior of your app to hit them less often. Your users would surely appreciate gettingthings done without the delay. Each time a rate limit related error occurs, the WebClient instance emits an event:WebClientEvent.RATE_LIMITED. We recommend that you use the event to inform users when something might take longer thanexpected, or just log it for later.
Download Slack
You might not want to the WebClient to handle rate limits in this way. Perhaps the operation was time sensitive, andit won’t be useful by the time Slack is ready for another request. Or, you have a more sophisticated approach. In thesecases, you can set the rejectRateLimitedCalls option on the client to true. Once you set this option, method callscan fail with rate limiting related errors. These errors have a code property set to ErrorCode.RateLimitedError. Seeerror handling for more details.
Request concurrency
Each of the API method calls the client starts are happening concurrently, or at the same time. If your app triesto perform a lot of method calls, let’s say 100 of them, at the same time, each one of them would be competing for thesame network resources (such as bandwidth). By competing, they might negatively affect the performance of all the rest,and therefore negatively affect the performance of your app. This is one of the reasons why the WebClient limits theconcurrency of requests by default to ten, which means it keeps track of how many requests are waiting, and onlystarts an eleventh request when one of them completes. The exact number of requests the client allows at the same timecan be set using the maxRequestConcurrency option.
The lower you set the maxRequestConcurrency, the less parallelism you’ll have in your app. Imagine setting theconcurrency to 1. Each of the method calls would have to wait for the previous method call to complete before it caneven be started. This could slow down your app significantly. So its best not to set this number too low.
Another reason, besides competing for resources, that you might limit the request concurrency is to minimize theamount of state in your app. Each request that hasn’t completed is in some ways a piece of state that hasn’t yet beenstored anywhere except the memory of your program. In the scenario where you had 100 method calls waiting, and yourprogram unexpectedly crashes, you’ve lost information about 100 different things going on in the app. But by limitingthe concurrency to a smaller number, you can minimize this risk. So its best not to set this number too high.
Custom TLS configuration
Each connection to Slack starts with a handshake that allows your app to trust that it is actually Slack you areconnecting to. The system for establishing this trust is called TLS. In order for TLS to work, the host running your appkeeps a list of trusted certificate authorities, that it can use to verify a signature Slack produces. You don’tusually see this list, its usually a part of the operating system you’re running on. In very special cases, like certaintesting techniques, you might want to send a request to another party that doesn’t have a valid TLS signature that yourcertificate authority would verify. In these cases, you can provide alternative TLS settings, in order to change how theoperating system might determine whether the signature is valid. You can use the tls option to describe the settingsyou want (these settings are the most common and useful from the standard NodeAPI).
tls propertyDescriptioncaOptionally override the trusted CA certificates. Any string or Buffer can contain multiple PEM CAs concatenated together.keyPrivate keys in PEM format. PEM allows the option of private keys being encrypted. Encrypted keys will be decrypted with passphrase.certCert chains in PEM format. One cert chain should be provided per private key.pfxPFX or PKCS12 encoded private key and certificate chain. pfx is an alternative to providing key and cert individually. PFX is usually encrypted, if it is, passphrase will be used to decrypt it.passphraseShared passphrase used for a single private key and/or a PFX.
Slack Webinar
Custom API URL
The URLs for method calls to Slack’s Web API always begin with https://slack.com/api/. In very special cases, such ascertain testing techniques, you might want to send these requests to a different URL. The slackApiUrl option allowsyou to replace this prefix with another.
Exchange an OAuth grant for a token
There’s one method in the Slack Web API that doesn’t requires a token, because its the method that gets a token! Thismethod is called oauth.v2.access. It’s used as part of the OAuth2.0 process that users initiate when installing your app into a workspace. In thelast step of this process, your app has received an authorization grant called code which it needs to exchange foran access token (token). You can use an instance of the WebClient that has no token to easily complete thisexchange.
Note: If you’re looking for a more complete solution that handles more of the OAuth process for your app, take alook at the @aoberoi/passport-slack Passport Strategy.
The Slack platform offers several APIs to build apps. Each Slack API delivers part of the capabilities from theplatform, so that you can pick just those that fit for your needs. This SDK offers a corresponding package for each ofSlack’s APIs. They are small and powerful when used independently, and work seamlessly when used together, too.
Just starting out? The Getting Started tutorial willwalk you through building your first Slack app using Node.js.
Slack APIWhat its forNPM PackageWeb APISend data to or query data from Slack using any of over 130 methods.@slack/web-apiEvents APIListen for incoming messages and many other events happening in Slack, using a URL.@slack/events-apiInteractive MessagesRespond to button clicks, dialogs, and other interactions with messages.@slack/interactive-messagesOAuthSetup the authentication flow using V2 OAuth for Slack apps as well as V1 OAuth for classic Slack apps.@slack/oauthRTM APIListen for incoming messages and a limited set of events happening in Slack, using websockets.@slack/rtm-apiIncoming WebhooksSend notifications to a single channel which the user picks on installation.@slack/webhook
Not sure about which APIs are right for your app? Read our blogpost that explains the options.If you’re still not sure, reach out for help and our community can guide you.
If you’re looking for an all-in-one solution that hides the underlying Slack APIs, but simplifies building a bot-styleapp inside Slack, try the Hubot Slack adapter. Hubot is a popular frameworkfor internal apps that automate workflows, perform ChatOps, or just generate silly memes.
Installation
Question symbol copy. Use your favorite package manager to install any of the packages and save to your package.json:
Requirements
This package supports Node v8 LTS and higher. It’s highly recommended to use the latest LTS version ofnode, and the documentation is written using syntax and featuresfrom that version.
Slack Web App
Getting Help
If you get stuck, we’re here to help. The following are the best ways to get assistance working through your issue:
Slack Webex
Issue Tracker for questions, featurerequests, bug reports and general discussion related to this package.
Email us in Slack developer support: [email protected]
Bot Developers Hangout: a Slack community for developersbuilding all types of bots. You can find the maintainers and users of this package in #sdk-node-slack-sdk.

0 notes
Text
Broken L2 cache reporting on crostini
With Google's recent announcement of support for running real Linux apps on Chrome OS, I picked up a Pixelbook, since I've been long awaiting the viability of Chromebooks as development machines.
After setting up a dev VM and experimenting with various projects, I found that one Tensorflow application I was playing with would lock up, hard, inside the Crostini VM on my Chromebook.
After adding some debug prints, I discovered that virtually any calls into numpy.linalg.inv were hanging. I could reproduce as simply as:
python3 -c 'import numpy as np; np.linalg.inv(np.identity(3))'
Googling found https://github.com/numpy/numpy/issues/11041, which was similar, but my bug was far worse, and the workaround on that issue didn't solve my problem. It did, however, point me at the OPENBLAS_NUM_THREADS=1 environment variable, which limited openblas to a single thread; This would prove helpful later.
I suspected a Crostini bug at this point, since this was pretty basic functionality to be broken, but I reported a numpy bug in the interim while I debugged. (numpy ended up (correctly!) also guessing this was a crostini bug, but were also able to provide some helpful debugging pointers)
I stopped a hung process (with OPENBLAS_NUM_THREADS=1 to simplify the situation) in gdb and got a stack trace:
(gdb) bt #0 0x00007ffff445a5b8 in dtrsm_oltucopy_PRESCOTT () from /home/nelhage/.local/lib/python3.5/site-packages/numpy/core/../.libs/libopenblasp-r0-39a31c03.2.18.so #1 0x00007ffff426aad3 in dtrsm_LNLU () from /home/nelhage/.local/lib/python3.5/site-packages/numpy/core/../.libs/libopenblasp-r0-39a31c03.2.18.so #2 0x00007ffff43b0a24 in dgetrs_N_single () from /home/nelhage/.local/lib/python3.5/site-packages/numpy/core/../.libs/libopenblasp-r0-39a31c03.2.18.so #3 0x00007ffff4191965 in dgesv_ () from /home/nelhage/.local/lib/python3.5/site-packages/numpy/core/../.libs/libopenblasp-r0-39a31c03.2.18.so #4 0x00007ffff1e5a103 in ?? () from /home/nelhage/.local/lib/python3.5/site-packages/numpy/linalg/_umath_linalg.cpython-35m-x86_64-linux-gnu.so #5 0x00007ffff3aaed24 in ?? () from /home/nelhage/.local/lib/python3.5/site-packages/numpy/core/umath.cpython-35m-x86_64-linux-gnu.so #6 0x00007ffff3aaf538 in ?? () from /home/nelhage/.local/lib/python3.5/site-packages/numpy/core/umath.cpython-35m-x86_64-linux-gnu.so #7 0x00007ffff3ab0ddf in ?? () from /home/nelhage/.local/lib/python3.5/site-packages/numpy/core/umath.cpython-35m-x86_64-linux-gnu.so #8 0x000055555575d647 in PyObject_Call () #9 0x00005555556d4ee1 in PyEval_EvalFrameEx () #10 0x00005555556d493f in PyEval_EvalFrameEx () #11 0x00005555556d9286 in ?? () #12 0x00005555556d9f9f in PyEval_EvalCode () #13 0x00005555556b89bf in PyRun_StringFlags () #14 0x00005555557a9f3c in PyRun_SimpleStringFlags () #15 0x00005555557d8602 in Py_Main () #16 0x0000555555668c01 in main ()
This confirmed we're hung in OpenBLAS, and in particular tells us that numpy ships its own OpenBLAS. Debug symbols would almost certainly help here, so I installed Debian's OpenBLAS, and the corresponding debug symbols:
$ sudo apt install libopenblas-base libopenblas-base-dbgsym
Now we can force load that version, and get better symbols:
$ env LD_PRELOAD=/usr/lib/libopenblasp-r0.2.19.so OPENBLAS_NUM_THREADS=1 gdb --args python3 -c 'import numpy as np; np.linalg.inv(np.identity(3))' ... (gdb) bt #0 dtrsm_oltucopy_PRESCOTT (m=3, n=0, a=<optimized out>, lda=3, offset=<optimized out>, b=<optimized out>) at generic/trsm_ltcopy_4.c:346 #1 0x00007ffff5e5e8b4 in dtrsm_LNLU (args=args@entry=0x7fffffffbc10, range_m=range_m@entry=0x0, range_n=range_n@entry=0x0, sa=sa@entry=0x7fffecaa5000, sb=sb@entry=0x7fffecaa5100, dummy=dummy@entry=0) at trsm_L.c:153 #2 0x00007ffff5fa7765 in dgetrs_N_single (args=args@entry=0x7fffffffbc10, range_m=range_m@entry=0x0, range_n=range_n@entry=0x0, sa=sa@entry=0x7fffecaa5000, sb=sb@entry=0x7fffecaa5100, mypos=mypos@entry=0) at getrs_single.c:51 #3 0x00007ffff5d7d978 in dgesv_ (N=<optimized out>, NRHS=0x7fffffffbdcc, a=<optimized out>, ldA=<optimized out>, ipiv=<optimized out>, b=<optimized out>, ldB=0x7fffffffbdd4, Info=0x7fffffffbda0) at lapack/gesv.c:127 #4 0x00007fffef583103 in ?? () from /home/nelhage/.local/lib/python3.5/site-packages/numpy/linalg/_umath_linalg.cpython-35m-x86_64-linux-gnu.so #5 0x00007ffff11d7d24 in ?? () from /home/nelhage/.local/lib/python3.5/site-packages/numpy/core/umath.cpython-35m-x86_64-linux-gnu.so #6 0x00007ffff11d8538 in ?? () from /home/nelhage/.local/lib/python3.5/site-packages/numpy/core/umath.cpython-35m-x86_64-linux-gnu.so #7 0x00007ffff11d9ddf in ?? () from /home/nelhage/.local/lib/python3.5/site-packages/numpy/core/umath.cpython-35m-x86_64-linux-gnu.so #8 0x000055555575d647 in PyObject_Call () #9 0x00005555556d4ee1 in PyEval_EvalFrameEx () #10 0x00005555556d493f in PyEval_EvalFrameEx () #11 0x00005555556d9286 in ?? () #12 0x00005555556d9f9f in PyEval_EvalCode () #13 0x00005555556b89bf in PyRun_StringFlags () #14 0x00005555557a9f3c in PyRun_SimpleStringFlags () #15 0x00005555557d8602 in Py_Main () #16 0x0000555555668c01 in main ()
Line numbers! Variable names! Oh my!
After taking a few stack traces to see where we're stuck, I became pretty convinced we were stuck in this loop:
for(is = ls + min_i; is < ls + min_l; is += GEMM_P){ #ifndef TRANSA TRSM_ILTCOPY(min_l, min_i, a + (is + ls * lda) * COMPSIZE, lda, is - ls, sa); #else TRSM_IUNCOPY(min_l, min_i, a + (ls + is * lda) * COMPSIZE, lda, is - ls, sa); #endif TRSM_KERNEL(min_i, min_j, min_l, dm1, #ifdef COMPLEX ZERO, #endif sa, sb, b + (is + js * ldb) * COMPSIZE, ldb, is - ls); }
Looking at the assembly, we find the loop ends with a
0x00007ffff5e5e8f8 : movslq 0x280(%rax),%r10 0x00007ffff5e5e8ff : add %r10,%rbp 0x00007ffff5e5e902 : cmp %r15,%rbp 0x00007ffff5e5e905 : jl 0x7ffff5e5e870 <dtrsm_lnlu>
I set a breakpoint on 0x00007ffff5e5e8ff and inspected %r10, which I was pretty sure was the GEMM_P increment in the for loop above:
gdb) b *0x00007ffff5e5e8ff Breakpoint 1 at 0x7ffff5e5e8ff: file trsm_L.c, line 148. (gdb) c Continuing. Breakpoint 1, 0x00007ffff5e5e8ff in dtrsm_LNLU (args=args@entry=0x7fffffffbc10, range_m=range_m@entry=0x0, range_n=range_n@entry=0x0, sa=sa@entry=0x7fffecaa5000, sb=sb@entry=0x7fffecaa5100, dummy=dummy@entry=0) at trsm_L.c:148 148 in trsm_L.c (gdb) p $r10 $1 = 0
So we're looping forever because we're looping over something by an increment of 0. Hm. Now, where does that come from? We can ask the debugger if that address points to a symbol:
(gdb) x/lx (void*)$rax + 0x280 0x7ffff7dadf40 <gotoblas_prescott>: 0x00000000
so GEMM_P appears to be a macro(?) that expands into an offset after a symbol named gotoblas_PRESCOTT. Github suggests that symbol is a gotoblas_t: https://github.com/xianyi/OpenBLAS/blob/26e1cfb65314a5579cc74aa8d7d30660db3e9ee1/driver/others/dynamic.c#L58
gdb tells us that struct is in fact larger than 0x280 bytes, so we're pulling a field from inside. Scanning the fields (via ptype) we find several named things like gemm_p, and in fact find one at offset 0x280:
(gdb) p sizeof(gotoblas_t) $3 = 3992 (gdb) ptype gotoblas_t type = struct { .... } (gdb) p &((gotoblas_t*)0)->dgemm_p $4 = (int *) 0x280
I tried messing with watchpoints to catch the initialization of dgemm_p, but to no avail. Code search, however, revealed a whole bunch of assignments in a nested maze of #ifdef conditionals, all in one function in setparam-ref.c (I would later learn that OpenBLAS compiles this file once per architecture with a different mix of #defines, but that's mostly just fun trivia...).
We note that it's pulling the size, in most of these branches, based on l2, which is the result of:
int l2 = get_l2_size();
Is it possible the custom hypervisor used by crostini is incorrectly reporting a size-0 L2 cache? We read get_l2_size; the crux of it is:
cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
Some quick googling confirms that cpuid query 0x80000006 returns information about the L2 cache. With the help of the cpuid(1) command-line tool, we can see what our virtual CPU returns:
$ cpuid -1 -r -l 0x80000006 CPU: 0x80000006 0x00: eax=0x00000000 ebx=0x00000000 ecx=0x00000000 edx=0x00000000
All zeros! So, the hypervisor that manages the VMs on Google's new Crostini environment is failing to configure the CPUID values for L2 cache size, resulting in OpenBLAS seeing a 0-size L2 cache, and looping forever as it tries to loop over data in L2-sized chunks!
I filed two bugs, one against Google about the cpuid issue, and one against OpenBLAS asking for greater robustness in this particular edge case. The latter is already fixed, and the former has been confirmed and will hopefully be resolved soon.
2 notes
·
View notes
Text
This is really interesting, and - maybe, in a sense - kind of a subtle step in a very appealing direction...
> ### Repology, the packaging hub > #### https://repology.org/ > > Repology monitors a huge number of package repositories and other sources comparing packages versions across them and gathering other information. Repology shows you in which repositories a given project is packaged, which version is the latest and which needs updating, who maintains the package, and other related information. Repology might be useful: > > For package/port maintainers: > - Discover new releases of software you maintain packages for > - Find new projects to package > - Get in touch with fellow maintainers to improve packages together > - Keep package naming and versioning schemes in sync to other repos for your and your user's convenience > - Fix problems detected by repology, such as broken links > > For software authors: > - Keep track of where and how well your project is packaged > - Keep in touch with your product package maintainers > > For users: > - Discover new releases of software you use > - Pick distribution most suitable for you, in terms of package quantity, freshness or stability > - Keep in touch with maintainers of software you use > > #### Supported repositories > > Linux repositories: Adélie, Alpine, ALT, Amazon Linux, antiX, AOSC, Arch and AUR, Ataraxia, BlackArch, Calculate, Carbs, CentOS, Chakra, CRUX, Debian, Deepin, Devuan, Distri, ELRepo, Entware-ng, EPEL, Exherbo, Fedora, Funtoo, Gentoo, Guix, GoboLinux, Hyperbola, KaOS, KISS, Kwort, LiGurOS, Linuxbrew, Maemo, Mageia, Manjaro, Mer Project, Mint, MX Linux, Nix, openEuler, OpenMandriva, openSUSE, OpenWrt, Parabola, Pardus, Parrot, PCLinuxOS, Pisi, PLD Linux, PureOS, Raspbian, RebornOS, Rosa, Sabayon, Salix, Siduction, SlackBuilds, Slackware, SliTaz, Solus, SparkyLinux, T2 SDE, Tails, Trisquel, Ubuntu, Void > *BSD repositories: DragonFly DPorts, FreeBSD ports, MidnightBSD Mports, OpenBSD packages, pkgsrc, Ravenports > Third party repositories: Deb Multimedia, Gentoo overlays, KDE neon, OpenPKG, openSUSE additional repositories, PackMan, UnitedRPMs, RPM Fusion, RPM Sphere > Other *nix repositories: AIX Open Source Packages, HaikuPorts, Homebrew, HP-UX, IBM i, OpenIndiana, MacPorts > And non-*nix repositories: Chocolatey, ConanCenter, Cygwin, F-Droid, just-install, MSYS2 (msys2, mingw), Npackd, OS4Depot, ReactOS rapps, Scoop, Termux, Vcpkg, winget, YACP > Upstream module collections or programming language specific package managers: Buckaroo, CPAN, CRAN, crates.io, GNU ELPA, Hackage, LuaRocks, MELPA, PyPi, RubyGems, Stackage > F/OSS news sites: DistroWatch, freshcode.club, libregamewiki > Other sources: Wikidata
#repology #distros #floss #freesoftware #freesw #libresoftware #debian #arch #trisquel #ubuntu #hyperbola #f-droid #fdroid #code #source #software #apps #packages #development #hub #community #resources #tools #bsd #gnu #linux
original post
0 notes
Text
Flutter Crash Course for JavaScript Developers
Welcome! I’m glad you’re here again for some more Dart and Flutter magic.
✨ In the previous episode of this series, we looked at Dart and went from basically zero to hero with all those types, classes and asynchrony. I hope you had enough practice on Dart because today, we’ll move forward to Flutter. Let’s get started!
Quick heads up: the “👉” emoji will compare JS and React with Dart and Flutter language examples as of now. Just like in the previous episode,, the left side will be the JS/React, and the right side will be the Dart/Flutter equivalent, e.g. console.log("hi!"); 👉 print("hello!");
What is Flutter, and why we’ll use it
Flutter and Dart are both made by Google. While Dart is a programming language, Flutter is a UI toolkit that can compile to native Android and iOS code. Flutter has experimental web and desktop app support, and it’s the native framework for building apps for Google’s Fuchsia OS.
This means that you don’t need to worry about the platform, and you can focus on the product itself. The compiled app is always native code as Dart compiles to ARM, hence providing you the best cross-platform performance you can get right now with over 60 fps.
Flutter also helps the fast development cycle with stateful hot reload, which we’ll make use of mostly in the last episode of this series.
Intro to the Flutter CLI
When building apps with Flutter, one of the main tools on your belt is the Flutter CLI. With the CLI, you can create new Flutter projects, run tests on them, build them, and run them on your simulators or emulators. The CLI is available on Windows, Linux, macOS and x64-based ChromeOS systems.
Once you have the CLI installed, you’ll also need either Android Studio, Xcode, or both, depending on your desired target platform(s).
(Flutter is also available on the web and for desktop, but they are still experimental, so this tutorial will only cover the Android and iOS related parts).
If you don’t wish to use Android Studio for development, I recommend VSCode. You can also install the Dart and Flutter plugins for Visual Studio Code.
Once you’re all set with all these new software, you should be able to run flutter doctor. This utility will check if everything is working properly on your machine. At the time of writing, Flutter printed this into the console for me:
[✓] Flutter (Channel stable, v1.17.4, on Mac OS X 10.15.4 19E287, locale en-HU) [✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2) [✓] Xcode - develop for iOS and macOS (Xcode 11.5) [!] Android Studio (version 3.5) ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. [✓] VS Code (version 1.46.1) [!] Connected device ! No devices available
You should get similar results for at least for the Flutter part too. Everything else depends on your desired target platforms and your preferred IDEs like Android Studio or VS Code. If you get an X for something, check again if everything is set up properly.
Only move forward in this tutorial if everything works properly.
To create a new Flutter project, cd into your preferred working directory, and run flutter create <projectname>. The CLI will create a directory and place the project files in there. If you use VS Code on macOS with an iOS target, you can use this little snippet to speed up your development process:
# Create a new project flutter create <projectname> # move there cd projectname # open VS code editor code . # open iOS Simulator - be patient, it may take a while open -a Simulator.app # start running the app flutter run
And boom, you’re all set! 💅
If you don’t wish to use the iOS simulator, you can always spin up your Android Studio emulator. Use Genymotion (or any other Android emulation software), or even connect a real device to your machine. This is a slower and more error-prone solution, so I recommend to only test on real devices when necessary.
Once they have booted, you can run flutter doctor again and see if Flutter sees the connected device. You should get an output something just like this:
... [✓] Connected device (1 available) ...
If you got this output - congratulations! 🎉 You’re all set to move on with this tutorial. If, for some reason Flutter didn’t recognize your device, please go back and check everything again as you won’t be able to follow the instructions from now on.
Hello world! 🌍
If you didn’t run the magic snippet previously, run these commands now:
# Create a new project flutter create <projectname> # move there cd projectname # open VS code editor (optional if you use Studio) code . # start running the app flutter run
This will spin up the Flutter development server with stateful hot reload and a lot more for you. You’ll see, that by default, Flutter creates a project with a floating action button and a counter:
Once you’re finished with playing around the counter, let’s dig into the code! 👨💻
Flutter project structure
Before we dig right into the code, let’s take a look at the project structure of our Flutter app for a moment:
├── README.md ├── android │ └── ton of stuff going on here... ├── build │ └── ton of stuff going on here... ��── ios │ └── ton of stuff going on here... ├── lib │ └── main.dart ├── pubspec.lock ├── pubspec.yaml └── test └── widget_test.dart
We have a few platform-specific directories: android and ios. These contain the necessary stuff for building, like the AndroidManifest, build.gradle, or your xcodeproj.
At this moment, we don’t need to modify the contents of these directories so we’ll ignore them for now. We’ll also ignore the test directory as we won’t cover testing Flutter in this series (but we may look into it later if there’s interest 👀), so that only leaves us to these:
├── lib │ └── main.dart ├── pubspec.lock ├── pubspec.yaml
And this is where the magic happens. Inside the lib directory, you have the main.dart: that’s where all the code lives right now. We’ll peek into it later, but let’s just have a look at the pubspec.yaml and pubspec.lock.
What are those?
Package management in Flutter - pub.dev
When building a project with JavaScript, we often use third party components, modules, packages, libraries, and frameworks so that we don’t have to reinvent the wheel. The JavaScript ecosystem has npm and yarn to provide you with all those spicy zeroes and ones, and they also handle the dependencies inside your project.
In the Dart ecosystem, this is all handled by pub.dev.
So, just a few quick facts: npm 👉 pub.dev package.json 👉 pubspec.yaml package-lock.json 👉 pubspec.lock
We’ll look into installing packages and importing them into our app in the last episode of this series, in which we’ll create a fun mini-game.
Digging into the Dart code
The only thing left from the file tree is main.dart. main is the heart of our app, it’s like the index.js of most JS-based projects. By default, when creating a project with flutter create, you’ll get a very well documented code with a StatelessWidget, a StatefulWidget, and its State.
So instead of observing the demo code line by line together, I encourage you to read the generated code and comments by yourself and come back here later.
In the next part, we’ll look into what are widgets and the build method.
We’ll learn why it is @overrided, and what’s the difference between stateful and stateless widgets. Then we’ll delete all the code from main.dart and create a Hello world app by ourselves so that you can get the hang of writing declarative UI code in Flutter.
Go ahead, read the generated code and the documentation now! 👀
In Flutter, everything is a widget!
As you have been reading the code, you may have noticed a few things. The first thing after importing Flutter is the entry method I have been talking about in the previous episode:
void main() { runApp(MyApp()); }
And then, you could see all those classes and OOP stuff come back with the line class MyApp extends StatelessWidget.
First things first: in Flutter, everything is a widget! Oh, and speaking of widgets. Components 👉 Widgets!
The StatelessWidget is a class from the Flutter framework, and it’s a type of widget. Another kind of widget is StatefulWidget and we’ll look into the difference between those and how to use them later.
We can create our reusable widget by extending the base class StatelessWidget with our own build method. (By the way, render in ReactJS 👉 build in Flutter). We can see that the build returns a Widget because the return type is defined, and we can see an odd keyword in the previous line: @override.
It’s needed because the StatelessWidget class has a definition for build by default, but we want to replace it (or override it) with our own implementation - hence the keyword @override. Before we dig further into the code, let’s have a peek at using widgets in Flutter:
// using a React component <button onClick={() => console.log(‘clicked!’)}>Hi, I’m a button</button>
// using a Flutter widget RawMaterialButton( onPressed: () { print("hi, i'm pressed"); }, child: Text("press me!"), ),
You can see that Flutter has a different approach with declarative UI code.
Instead of wrapping children between ><s and passing props next to the component name (e.g. <button onClick ...), everything is treated as a property. This enables Flutter to create more flexible and well-typed widgets: we’ll always know if a child is supposed to be a standalone widget or if it can accept multiple widgets as a property, for example. This will come in handy later when we’ll build layouts with Rows and Columns.
Now that we know a bit more about widgets in Flutter, let’s take a look at the generated code again:
@override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); }
The build method returns a MaterialApp that has a type of Widget and - unsurprisingly - comes from Flutter. This MaterialApp widget is a skeleton for your Flutter app. It contains all the routes, theme data, metadata, locales, and other app-level black magic you want to have set up. 🧙
You can see the MyHomePage class being referenced as the home screen. It also has a property, title, set up. MyHomePage is also a widget, and we can confirm that by looking at the definition of this class.
Quick tip: if you are using VSCode as your editor, hold Command and hover or click on the class reference and you’ll be directed to the code of the class.
We can see that MyHomePage extends a StatefulWidget. However, the structure of the code itself is a bit squiggly and weird. What’s this MyHomePage({Key key, this.title}) : super(key: key); syntax? Why doesn’t this widget have a build method? What’s a State? What is createState?
To answer these questions, we’ll have to look into one of the more hard-code topics in Flutter: state management.
Local state management in Flutter: StatefulWidgets
I previously talked about the two main types of widgets in Flutter: StatelessWidgets and StatefulWidgets. StatelessWidgets are pretty straightforward: a snippet of code that returns a Widget, maybe some properties are being passed around, but that’s all complexity.
However, we don’t want to write applications that just display stuff! We want to add interactivity! And most interactions come with some state, whether it’s the data stored in an input field or some basic counter somewhere in your app. And once the state is updated, we want to re-render the affected widgets in our app - so that the new data is being displayed for the user.
Think of state management in React: it has the very same purpose with the goal of being as efficient as possible. It’s no different in Flutter: we want to have some very simple widgets (or StatelessWidgets), and some widgets with a bit of complexity and interactivity (or StatefulWidgets).
Let’s dive into the code: a StatefulWidget consists of two main components:
a StatefulWidget (that is called MyHomePage in our case)
a typed State object (that is called _MyHomePageState in this example)
We’ll call these “widget” and “state” (respectively) for the sake of simplicity. The widget itself contains all the props, and a createState overridden method. As you can see, the prop is marked with a final - that’s because you cannot change the prop from within the widget. When you modify a prop of a widget, Flutter throws the current instance away and creates a brand new StatefulWidget.
Note that changing either the prop or the state will trigger a rebuild in Flutter - the key difference between the two is that changing the state can be initiated from within the widget while changing a prop is initiated by the parent widget.
Props help you pass data from parent to children. State helps you handle data change inside the children.
Now, let’s look into changing the state: inside the widget, we have a createState method that only returns the state, _MyHomePageState(). When modifying the state with the setState method, this createState method gets called and returns a new instance of your state. The old instance gets thrown away, and a new instance of your widget will be inserted into the widget tree.
(Sidenote: the widget tree is only a blueprint of your app, the element tree is the one that gets rendered for the user. It’s a bit more advanced, under-the-hood topic, so it won’t be covered in this series - however, I’ll link some video resources later on that will help you understand how Flutter works and what’s the deal with the widget tree and the element tree.)
The _MyHomePageState class has a type of State, typed with MyHomePage.
This is needed so that you can access the properties set in the MyHomePage instance with the widget keyword - for example, to access the title prop, write widget.title. Inside the state, you have an overridden build method, just like you’d see in a typical StatelessWidget. This method returns a widget that renders some nice data, both from props (widget.title) and from the state (_counter).
Notice that you don’t need to type in anything before the _counter. No this.state._counter, no State.of(context)._counter, just a plain old _counter. That’s because from the perspective of the code, this variable is declared just like any other would be:
int _counter = 0;
However, when modifying this variable, we need to wrap our code in setState, like this:
setState(() { _counter++; });
This will tell Flutter that “Hey! It’s time to re-render me!”.
The framework will call the previously discussed createState method; a new instance of your state gets created; built; rendered; and boom! 💥 The new data is now on-screen.
It may seem a bit complicated or seem like you have to write a lot of boilerplate code to get this running. But don’t worry! With VS Code, you can refactor any StatelessWidget into a stateful one with just one click:
And that’s it for managing your widget’s state! It may be a lot at first, but you’ll get used to it after building a few widgets.
A few notes about global state management in Flutter
Right now, we only looked at working with local state in Flutter - handling app-level, or global state is a bit more complex. There are, just like in JS, tons of solutions, ranging from the built-in InheritedWidget to a number of third-party state management libraries. Some of those may already be familiar, for example, there is RxDart and Redux, just to name a few. To learn more about the most popular solutions, and which one to choose for your project, I suggest you watch this awesome video about global state management in Flutter by Fireship.
Widgets, widgets, and widgets
I already talked about how everything is a widget in Flutter - however, I didn’t really introduce you to some of the most useful and popular widgets in Flutter, so let’s have a look at them before we move on!
Flutter has widgets for displaying texts, buttons, native controls like switches and sliders (cupertino for iOS and material for Android style widgets), layout widgets like Stack, Row, Column and more. There are literally hundreds of widgets that are available for you out of the box, and the list keeps growing.
The whole widget library can be found here in the Widget Catalog, and the Flutter team is also working on a very nice video series with new episodes being released weekly. This series is called Flutter Widget of the Week, and they introduce you to a Flutter widget, it’s use cases, show you code examples and more, in just about one minute! It’s really binge-worthy if you want to get to know some useful Flutter widgets, tips, and tricks.
Here a link for the whole series playlist, and here is the intro episode.
Some useful widgets in Flutter
As you’ll work with Flutter, you’ll explore more and more widgets, but there are some basic Flutter widgets you’ll absolutely need to build your first application. (We’ll probably use most of them in the next and last episode of this series, so stay tuned!)
First and foremost: Text.
The Text widget delivers what its name promises: you can display strings with it. You can also style or format your text and even make multiline texts. (There’s are a lot of line of text-related widgets available, covering your needs from displaying rich text fields to creating selectable texts.)
An example Text widget in Flutter:
Text('hello world!'),
Adding buttons to your Flutter app is also easy as one two three. There are numerous button-related widgets available for you ranging from RawMaterialButton to FlatButton, IconButton, and RaisedButton, and there are also specific widgets for creating FloatingActionButtons and OutlineButtons. I randomly picked 🎲 the RaisedButton for us so that we can have a peek at how easy it is to add a nice, stylish button into our app:
RaisedButton( onPressed: () { print( "hi! it's me, the button, speaking via the console. over.", ); }, child: Text("press meeeeeee"), ),
Building layouts in Flutter
When building flexible and complex layouts on the web and in React-Native, the most important tool you used was flexbox. While Flutter isn’t a web-based UI library and hence lacks flexbox, the main concept of using flexible containers with directions and whatnot is implemented and preferred in Flutter. It can be achieved by using Rows and Columns, and you can stack widgets on each other by using Stacks.
Consider the following cheatsheet I made:
Remember how I previously praised typing the props of a widget and how it’s one of the best tools in Flutter’s declarative UI pattern? The Row, Column and Stack widgets all have a children property that want an array of widgets, or [Widget]. Lucky for you, the VS Code automatically completes the code for you once you start working with these widgets:
Just hit tab to let Code complete the code for you! Maybe in the future, you won’t need to write code at all, Flutter will just suck out the app idea out of your brain and compile that - but until then, get used to hitting tab.
Let’s look at an example where we display some names underneath each other:
Column( children: <Widget>[ Text("Mark"), Text("Imola"), Text("Martin"), Text("Zoe"), ], ),
You can see that you create a typed list with the <Widget>[] syntax, you pass it as a prop for the Column, create some amazing widgets inside the list, and boom! The children will be displayed underneath each other. Don’t believe me? Believe this amazing screenshot. 📸
Alignment
The real power of Columns and Rows isn’t just placing stuff next to each other, just like flexbox isn’t only about flex-direction either. In Flutter, you can align the children of a Column and Row on two axes, mainAxis and crossAxis.
These two properties are contextual: whilst in a Row, the main axis would be horizontal, and the crossing axis would be vertical, it would be switched in a Column. To help you better understand this axis concept, I created a handy cheat sheet with code examples and more.
So, for example, if you want to perfectly center something, you’d want to use either the Center widget; or a Row or Column with both mainAxisAlignment and crossAxisAlignment set to .center; or a Row and Column with their mainAxisAlignments set to .center. The possibilities are basically endless with these widgets! ✨
Rendering lists (FlatLists 👉 ListViews)
Whilst thinking about possible use cases for columns, you may have wondered about creating scrollable, dynamic, reorderable, or endless lists.
While these features could be achieved by using Columns, it would take a lot of effort to do so, not even mentioning updating your list data or lazy rendering widgets when there’s a crapton of data. Lucky you, Flutter has a class for rendering lists of data, and it’s called a ListView!
There are several ways to use a ListView, but the most important ones are the ListView(...) widget and the ListView.builder method. Both of them achieve the very same functionality from the perspective of the user, but programmatically, they differ big time.
First, let’s look into the ListView(..) widget. Syntactically, they are very similar to a Column except that they lack the main and cross-axis alignment properties. To continue on with our previous example for columns when we placed names under each other, I’ll display the very same column converted into a ListView:
ListView( children: <Widget>[ Text("Mark"), Text("Imola"), Text("Martin"), Text("Zoe"), ], ),
Tada! 🎉 Your first ListView in Flutter! When refreshing or rebuilding the app (by either pressing a small or capital R in the Flutter CLI), you’ll see the very same thing you saw previously.
However, if you try to drag it, you are now able to scroll inside the container! Note that when a Column has bigger children than its bounds, it will overflow, but a ListView will be scrollable.
ListView builder
While the ListView widget is cool and good, it may not be suitable for every use case. For example, when displaying a list of tasks in a todo app, you won’t exactly know the number of items in your list while writing the code, and it may even change over time. Sure, you are able to run .map on the data source, return widgets as results, and then spread it with the ... operator, but that obviously wouldn’t be performant, nor is it a good practice for long lists. Instead, Flutter provides us a really nice ListView builder.
Sidenote: while working with Flutter, you’ll see the word “builder” a lot. For example, in places like FutureBuilder, StreamBuilder, AnimatedBuilder, the build method, the ListView builder, and more. It’s just a fancy word for methods that return a Widget or [Widget], don’t let this word intimidate or confuse you!
So how do we work with this awesome method? First, you should have an array or list that the builder can iterate over. I’ll quickly define an array with some names in it:
final List<String> source = ["Sarah", "Mac", "Jane", "Daniel"];
And then, somewhere in your widget tree, you should be able to call the ListView.builder method, provide some properties, and you’ll be good to go:
ListView.builder( itemCount: source.length, itemBuilder: (BuildContext context, int i) => Text(source[i]), ),
Oh, and notice how I was able to use an arrow function, just like in JavaScript!
The itemCount parameter is not required, but it’s recommended. Flutter will be able to optimize your app better if you provide this parameter. You can also limit the maximum number of rendered items by providing a number smaller than the length of your data source.
When in doubt, you can always have a peek at the documentation of a class, method, or widget by hovering over its name in your editor:
And that sums up the layout and list-related part of this episode. We’ll look into providing “stylesheets” (or theme data) for your app, look at some basic routing (or navigation) methods, and fetch some data from the interwebs with HTTP requests.
Theming in Flutter
While building larger applications with custom UI components, you may want to create stylesheets. In Flutter, they are called Themes, and they can be used in a lot of places. For example, you can set a default app color, and then the selected texts, buttons, ripple animations, and more will follow this color. You can also set up text styles (like headings and more), and you’ll be able to access these styles across the app.
To do so, you should provide a theme property for your MaterialApp at the root level of the application. Here’s an example:
return MaterialApp( title: 'RisingStack Flutter Demo', theme: ThemeData( // Define the default brightness and colors. brightness: Brightness.light, primaryColor: Colors.green[300], accentColor: Colors.green, // Define button theme buttonTheme: ButtonThemeData( buttonColor: Colors.green, shape: CircleBorder(), ), // Define the default font family // (this won’t work as we won’t have this font asset yet) fontFamily: 'Montserrat', // Define the default TextTheme. Use this to specify the default // text styling for headlines, titles, bodies of text, and more. textTheme: TextTheme( headline1: TextStyle(fontSize: 72.0, fontWeight: FontWeight.bold), headline6: TextStyle(fontSize: 36.0, fontStyle: FontStyle.italic), bodyText2: TextStyle(fontSize: 14.0, fontFamily: 'Muli'), ), ), home: Scaffold(...), );
These colors will be used throughout our app, and accessing the text themes is also simple as a pickle! I added a RaisedButton on top of the app so that we can see the new ButtonThemeData being applied to it:
It’s ugly and all, but it’s ours! 🍋 Applying the text style won’t be automatic, though. As we previously discussed, Flutter can’t really read your mind, so you explicitly need to tag Text widgets as a headline1 or bodyText2, for example.
To do so, you’ll use the Theme.of(context) method. This will look up the widget tree for the nearest Theme providing widget (and note that you can create custom or local themes for subparts of your app with the Theme widget!) and return that theme. Let’s look at an example:
Text( "cool names", style: Theme.of(context).textTheme.headline6, ),
You can see that we are accessing the theme with the Theme.of(context) method, and then we are just accessing properties like it’s an object. This is all you need to know about theming a Flutter app as it really isn’t a complex topic!
Designing mobile navigation experiences
On the web, when managing different screens of the app, we used paths (e.g. fancysite.com/registration) and routing (e.g., react-router) to handle navigating back and forth the app. In a mobile app, it works a bit differently, so I’ll first introduce you to navigation on mobile, and then we’ll look into implementing it in Flutter.
Mobile navigation differs from the web in a lot of ways. Gestures and animations play a very heavy role in structuring out the hierarchy of the app for your user. For example, when a user navigates to a new screen, and it slides in from the right side of the screen, the user will expect to be able to move back with a slide from the left. Users also don’t expect flashy loadings and empty screens when navigating - and even though there are advancements on the web in this segment (e.g. PWAs), it’s by far not the default experience when using websites.
There are also different hierarchies when designing mobile apps. The three main groups are:
Hierarchical Navigation (e.g. the Settings app on iOS)
New screens slide in from left to right. The expected behavior for navigating back is with a back button on the upper left corner and by swiping from the left edge of the screen to the right.
Flat Navigation (e.g. the Apple Music app)
The default behavior for this hierarchy is a tab bar on the bottom.
Tabs should always preserve location (e.g. if you navigate to a subscreen inside on tab one, switch to tab two and switch back to tab one, you’d expect to be on the subscreen, not on the root level screen.)
Swiping between tabs is optional. It isn’t the default behavior and it may conflict with other gestures on the screen itself - be cautious and think twice before implementing swipeable tab bars.
Custom, content-driven, or experimental navigation (Games, books and other content)
When making experimental navigation, always try to be sane with the navigation. The user should always be able to navigate back and undo stuff.
I created a handy cheat sheet for you that will remind you of the most important things when in doubt:
Also, all of these can be mixed together, and other screens like modals can be added to the stack. Always try to KISS and make sure that the user can always navigate back and undo things. Don’t try to reinvent the wheel with navigation (e.g., reverse the direction of opening up a new screen) as it will just confuse the user.
Also, always indicate where the user is in the hierarchy (e.g., with labeling buttons, app title bar, coloring the bottom bar icons, showing little dots, etc.). If you want to know more about designing mobile navigation experiences and implementing them in a way that feels natural to the user, check out Apple’s Human Interface Guideline’s related articles.
Navigation in Flutter
When routing on the web with React or React-Native, you had to depend on third-party libraries to get the dirty work done for you (e.g. react-router). Luckily, Flutter has native navigation capabilities out of the box, and they cover every need of most of the apps, and they are provided to you via the Navigator API.
The applications of this API and the possibilities to play around with navigation are endless. You can, for example, animate a widget between screens; build a bottom navigation bar or a hamburger menu; pass arguments; or send data back and forth. You can explore every navigation-related Flutter cookbook here. In this series, we’ll only look into initializing two screens, navigating between them, and sharing some widgets between them.
To get started with navigation, let’s create two widgets that we’ll use as screens and pass the first into a MaterialApp as the home property:
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', home: ScreenOne(), ); } } class ScreenOne extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Text("hey! 👋"), ), ); } } class ScreenTwo extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Text("hi! 👋👋"), ), ); } }
This was easy as a breeze. If you run this app in a simulator, you’ll see “hey! 👋” on the center of the screen. Now, inside the MaterialApp, we can define our routes:
return MaterialApp( title: 'Flutter Demo', home: ScreenOne(), routes: <String, WidgetBuilder>{ '/hey': (BuildContext context) => ScreenOne(), '/hi': (BuildContext context) => ScreenTwo(), }, );
Then, we’ll need something that will trigger the navigation. I’ll add a RaisedButton to the ScreenOne:
return Scaffold( body: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Text("hey! 👋"), RaisedButton( child: Text("take me there"), onPressed: () { print("hi!"); }, ), ], ), );
And now, we can navigate the user to the next screen when the button is pressed. Notice that I replaced the Center with a Column with both its main and cross axises centered. This was required because I wanted to have two children underneath each other: a Text and a RaisedButton. Inside the RaisedButton, we only have to push the route to the stack and let Flutter handle the routing and animation:
Navigator.pushNamed(context, '/hi');
By default, we can navigate back to the previous screen by swiping from the left edge of the screen. This is the expected behavior, and we don’t intend to change it, so we’ll leave it as it is. If you want to add a button on the second screen to navigate back to the first screen, you can use Navigator.pop(); method.
Don’t ever push to the same screen the user is on, nor the previous screen. Always use pop when navigating backward.
This will be just enough to cover your basic navigation needs. Don’t forget, if you want to check out more advanced navigation features such as animating widgets between screens or passing data back and forth, check out the related Flutter cookbooks.
Networking, HTTP requests
Now that you can build widgets, layouts, display lists, and you can navigate between screens with Flutter, there’s only one thing left: communicating with your backend API. One of the most popular BaaS providers for mobile and Flutter is Firebase by Google. It allows you to use real-time databases, push notifications, crash reporting, app analytics, and a lot more out of the box. You can find the Flutter Firebase packages on pub.dev or you can follow this step-by-step tutorial.
If you are a more experienced developer and you have a complex project with a custom backend in mind, or if you are just genuinely looking forward to using your own selection of backend APIs - Firebase just won’t suit your needs.
That’s where the http package comes in handy.
Just add it into your dependency list inside the pubspec.yaml, wait until flutter pub get finishes (VSCode automatically runs it for you if it detects changes in the pubspec.yaml), and then continue reading:
dependencies: flutter: sdk: flutter http: any
http is a Future-based library for making HTTP requests. To get started with it, just import it:
import 'package:http/http.dart' as http;
And then, you can start making requests with top-level methods like http.post or http.get. To help you experiment with making HTTP requests in Flutter, I have made a demo API that you can GET on. It will return some names and ages. You can access it here (https://demo-flutter-api.herokuapp.com/people).
Parsing JSON data in Flutter and Dart
After making your GET request on the API, you’ll be able to get data out of it by accessing properties like this:
void request() async { final response = await http.get("https://demo-flutter-api.herokuapp.com/people"); print(response.body); // => [{"name":"Leo","age":17},{"name":"Isabella","age":30},{"name":"Michael","age":23},{"name":"Sarah","age":12}] print(json.decode(response.body)[0]["name"]); // => Leo }
However, this solution should not be used in production. Not only it lacks automatic code completion and developer tooling, but it’s very error-prone and not really well documented. It’s just straight-up crap coding. 💩
Instead, you should always create a Dart class with the desired data structure for your response object and then process the raw body into a native Dart object. Since we are receiving an array of objects, in Dart, we’ll create a typed List with a custom class. I’ll name the class Person, and it will have two properties: a name (with a type of String) and age (int). I’ll also want to define a .fromJson constructor on it so that we can set up our class to be able to construct itself from a raw JSON string.
First, you’ll want to import dart:convert to access native JSON-related methods like a JSON encoder and decoder:
import 'dart:convert';
Create our very basic class:
class Person { String name; int age; }
Extend it with a simple constructor:
Person({this.name, this.age});
And add in the .fromJson method, tagged with the factory keyword. This keyword informs the compiler that this isn’t a method on the class instance itself. Instead, it will return a new instance of our class:
factory Person.fromJson(String str) => Person.fromMap(json.decode(str)); factory Person.fromMap(Map<String, dynamic> json) => new Person( name: json["name"], age: json["age"], );
Notice that I created two separate methods: a fromMap and a fromJson. The fromMap method itself does the dirty work by deconstructing the received Map. The fromJson just parses our JSON string and passes it into the fromMap factory method.
Now, we should just map over our raw response, use the .fromMap factory method, and expect everything to go just fine:
List<Person> listOfPeople = json .decode(response.body) .map<Person>((i) => Person.fromMap(i)) .toList(); print(listOfPeople[0].name); // => Leo
Sidenote: I didn’t use the .fromJson method because we already parsed the body before mapping over it, hence it’s unneeded right now.
There is a lot to unwrap in these few lines! First, we define a typed list and decode the response.body. Then, we map over it, and we throw in the return type <Person> to the map so that Dart will know that we expect to see a Person as a result of the map function. Then, we convert it to a List as otherwise it would be an MappedListIterable.
Rendering the parsed JSON: FutureBuilder and ListView.builder
Now that we have our app up and running with our basic backend, it’s time to render our data. We already discussed the ListView.builder API, so we’ll just work with that.
But before we get into rendering the list itself, we want to handle some state changes: the response may be undefined at the moment of rendering (because it is still loading), and we may get an error as a response. There are several great approaches to wrap your head around handling these states, but we’ll use FutureBuilder now for the sake of practicing using new Flutter widgets.
FutureBuilder is a Flutter widget that takes a Future and a builder as a property. This builder will return the widget we want to render on the different states as the Future progresses.
Note that FutureBuilder handles state changes inside the widget itself, so you can still use it in a StatelessWidget! Since the http package is Future-based, we can just use the http.get method as the Future for our FutureBuilder:
@override Widget build(BuildContext context) { return Scaffold( body: FutureBuilder( future: http.get("https://demo-flutter-api.herokuapp.com/people"), ), ); }
And we should also pass a builder. This builder should be able to respond to three states: loading, done and error. At first, I’ll just throw in a centered CircularProgressIndicator() to see that our app renders something:
return Scaffold( body: FutureBuilder( future: http.get("https://demo-flutter-api.herokuapp.com/people"), builder: (BuildContext context, AsyncSnapshot<http.Response> response) { return Center( child: CircularProgressIndicator(), ); }, ), );
If you run this app, you’ll see a progress indicator in the center of the screen running indefinitely. We can get the state of the response by the response.hasData property:
builder: (BuildContext context, AsyncSnapshot<http.Response> response) { if (response.hasData) { // loaded! } else if (response.hasError) { // error! return Center( child: Text("error!"), ); } else { // loading... return Center( child: CircularProgressIndicator(), ); } },
And now, we can be sure that nothing comes between us and processing, then rendering the data, so inside the response.hasData block, we’ll process the raw response with previously discussed parsing and mapping method, then return a ListView.builder:
// loaded! List<Person> listOfPeople = json .decode(response.data.body) .map<Person>((i) => Person.fromMap(i)) .toList(); return ListView.builder( itemCount: listOfPeople.length, itemBuilder: (BuildContext context, int i) => Text( "${listOfPeople[i].name} (${listOfPeople[i].age})", ), );
And that’s it! 🎉 If you run this snippet right now, it will render four names and their corresponding ages next to them. Isn’t this amazing? It may have seemed like a lot of work for a simple list like this, but don’t forget that we created a whole-blown class, parsed JSON, and converted it into class instances, and we even handled loading and error states.
Summing it all up
Congratulations on making it this far into the course! You have learned a lot and came along a long way since we started in the previous episode.
You went from zero to hero both with Dart (types, control flow statements, data structures, OOP, and asynchrony) and Flutter (CLI, widgets, alignment, lists, themes, navigation and networking).
This really has been a lot of work, and you’ll still have to learn a lot until you get fluent in Flutter, but in the end, the only thing that will matter is the result of your hard work. And that’s what we’re going to harvest in the next and last episode of this Flutter series: we’ll build a fun mini-game with Flutter! 🎲
I’m really looking forward to seeing you here next week. Until then, stay tuned, and happy Fluttering! ✌️
All the bests, 🍻 Daniel from RisingStack
Flutter Crash Course for JavaScript Developers published first on https://koresolpage.tumblr.com/
0 notes