Friday, December 25, 2020

update-hosts version 3

A major version update has been released for update-hosts bringing it to version 3.

Version 3 is largely compatible with the older version 2, except that the script now requires you to select what is outputted from the tool, instead of outputting a hosts file by default. The tool can output hosts, dnsmasq, and ipset formatted files. Support for changing file names, output IP addresses, and adding additional sources on the fly is still present, but the unbreak list has been dropped as it was too far out of date to maintain accurately.

The script has been largely simplified and much of the output noise has been removed. Instead of logging each individual step, the script only outputs errors and success points. The average user doesn't care that the script is currently stripping line endings or parsing IP addresses, so that logging information has been removed.

Find the latest version here.

Stay tuned!

========================
Follow pyamsoft around the Web for updates and announcements about the newest applications!
Like what I do?

Send me an email at: pyam.soft@gmail.com
Or find me online at: https://pyamsoft.blogspot.com

Follow my Facebook Page
Check out my code on GitHub
=========================

Thursday, December 24, 2020

git-ssh version 3

git-ssh has seen a major version refresh with version 3.0.0

Version 3 drops the python language as well as support for config file version 1 and instead moves to POSIX shell script with support for only config version 2.

For anyone using git-ssh 2 this change means very little as it is still config compatible, but for users using v1 you would honestly be better off just starting from scratch, it's quick I promise.

Some major behavior changes in this version though.

Gone are any of the --long-option flags, operation is strictly through commands now.

Use git-ssh create and pass it a name and an ssh keyfile path to create a config. Similarly use git-ssh delete and give it a name to remove configs. Use git-ssh list to show all your possible configs.

git-ssh in version 1 and 2 operated as a git subtool, meaning you woul call it along with other arguments to git itself. In version 3 it fills a role more like an outside manager, it's default and only mode of operation is now the equivalent of version 2 --ssh-alias mode

Calling git-ssh export with a config name will export a special environment variable that git will read when handling ssh commands. You can eval the result of this export command to set up your keyed environment. You can then call git as normal, so stuff like shell completion and git performance will remain as normal.

The choice was made to move away from python for performance reasons. Python took a couple hundred milliseconds to start up, which would slow down basically all git operations when git-ssh was used. Moving to shell script allows faster startup performance, and since the requirement to support old configs is gone, the tool is greatly simplified as well.

Find the new git-ssh here

Stay tuned!

========================
Follow pyamsoft around the Web for updates and announcements about the newest applications!
Like what I do?

Send me an email at: pyam.soft@gmail.com
Or find me online at: https://pyamsoft.blogspot.com

Follow my Facebook Page
Check out my code on GitHub 
=========================

Tuesday, December 22, 2020

Flashing Lights

Not gonna make the joke.

ZapTorch has received some updates today which simplify the code base and bring support for 2 new supported sequences!

Double tapping the Volume Down button will still turn the flashlight on, as it always has.

Double tapping the Volume Up button will turn the flashlight on and pulse it at a slow speed of about half a second. The light will flicker on and off every half-second or so, until you stop it by entering the sequence again. Cool!

Tapping Volume Down once and Volume Up once afterwards will put the light on in a strobe effect, flickering on and off quickly about once every 50 milliseconds or so. Seizure inducing!

This will be released in a future update.

Stay tuned!


========================
Follow pyamsoft around the Web for updates and announcements about the newest applications!
Like what I do?

Send me an email at: pyam.soft@gmail.com
Or find me online at: https://pyamsoft.blogspot.com

Follow my Facebook Page
Check out my code on GitHub
=========================

Managing Multiple Heroku Accounts

Let's say you have multiple accounts on Heroku for whatever reason, maybe some personal, some business.

When using heroku-cli, it expects you to basically always be signed in to only one account, meaning you have to keep logging in and jumping back and forth between different accounts via heroku login. It's kind of annoying.

I took ten minutes today to write a shell script called herotate which manages your heroku-cli active login file, a hidden file called .netrc in your home directory.

The script will move this file into a configuration directory and create a symlink to it, so all your heroku stuff will work as it normally does. When you want to add a different account, simply herotate unlink, and sign into a new account. 

 To make things even faster, you can manage multiple configurations inside of herotate as long as they all have different file names and live in the same configuration directory, which the script will echo out to you if you run it. By default, your config is named main but you can rename it and the tool will automatically continue to populate the directory with any new .netrc files.

You can symlink a config of your choosing at any time using >herotate link <config> and list all of your configs using herotate list.

Hopefully this simple script helps you manage multiple heroku-cli logins just like it helped me!

Stay tuned!

========================
Follow pyamsoft around the Web for updates and announcements about the newest applications!
Like what I do?

Send me an email at: pyam.soft@gmail.com
Or find me online at: https://pyamsoft.blogspot.com

Follow my Facebook Page
Check out my code on GitHub
=========================

Saturday, December 19, 2020

More Flexible PYDroid

PYDroid 22.2.8 was recently released which allows you to create a component which is composed of multiple UiViews which all handle different subsets of a UiViewEvent instead of handling the same UiViewEvent. This allows you to separate UiViewEvent models up into things like just events for list loading, versus just events for error message displays, and the like.

Imagine the following:


sealed class MyViewEvent : UiViewEvent {

  object ButtonEvent : MyViewEvent()
  object ListEvent : MyViewEvent()

}

class MyViewModel : UiViewModel<MyState, MyViewEvent, MyControllerEvent> {

  handleViewEvent(event: MyViewEvent) {
    return when (event) {
      -> ListEvent -> listWork()
      -> ButtonEvent -> buttonWork()
    }
  }
}

class MyButton : BaseUiView<MyState, MyViewEvent, MyControllerEvent> {

  // Because it implements MyViewEvent, which was 
  // a requirement to be in a Component,
  // it is aware of, and can wrongly use MyViewEvent.ListEvent

}

class MyList : BaseUiView<MyState, MyViewEvent, MyControllerEvent> {

  // Because it implements MyViewEvent, which was 
  // a requirement to be in a Component,
  // it is aware of, and can wrongly use MyViewEvent.ButtonEvent

}


you can now separate the view concerns like so


sealed class MyViewEvent: UiViewEvent {

  sealed class ButtonEvents : MyViewEvent() {

    object Clicked : ButtonEvents()

  }
  
  sealed class ListEvents : MyViewEvent() {

    object Loaded: ListEvents()
  }

}

class MyViewModel : UiViewModel<MyState, MyViewEvent, MyControllerEvent> {

  handleViewEvent(event: MyViewEvent) {
    return when (event) {
      -> ListEvents.Loaded -> listWork()
      -> ButtonEvents.Clicked -> buttonWork()
    }
  }
}

class MyButton : BaseUiView<MyState, MyViewEvent.ButtonEvents, MyControllerEvent> {

  // Because it implements MyViewEvent.ButtonEvents, 
  // it can only use the Clicked action
  // and it can still be created into a component
  // with MyViewModel, so no code changes in the
  // createComponent callsite.

}

class MyList : BaseUiView<MyState, MyViewEvent.ListEvents, MyControllerEvent> {

  // Because it implements MyViewEvent.ListEvents,
  // it can only use the Loaded action
  // and it can still be created into a component
  // with MyViewModel, so no code changes in the
  // createComponent callsite.

}


More changes will be coming soon to PYDroid to help you better share your component views between different ViewModels and UiControllers.

Stay tuned!

========================
Follow pyamsoft around the Web for updates and announcements about the newest applications!
Like what I do?

Send me an email at: pyam.soft@gmail.com
Or find me online at: https://pyamsoft.blogspot.com

Follow my Facebook Page
Check out my code on GitHub
=========================

Thursday, December 17, 2020

A Weekend with Animal Crossing

I was asked by my girlfriend to create a tool for her and her other Animal Crossing playing friends where she could keep track of a "wishlist" of items in the game that she wanted and her other friends would be able to check off items that they were planning on gifting to her, like an Elfster
for Animal Crossing.

Using simple Firebase tools and some React I built a simple frontend for the ACNH Api which I could use to display all of the items in the game. I used Firebase's realtime database to power a collaborative editing experience which handled the requesting and gifting flows of the items. It uses Firebase Auth to handle a email link based sign in, and uses Firebase hosting to power the web page. Neat!

It's called Celeste, named after the cute friend who comes to visit islands on a starry night. Since you wish upon a star, and this is a wishlist for you and your friends, I found it appropriate to name it after Celeste.

Since this was just a simple weekend project I won't be continuing it much further for the time being. My girlfriend found a fully running replacement site which I highly recommend you look at if something like Celeste has interested you. All in all, a fun weekend project and a nice look at how simple some of the hosting and platform services have become.

Find Celeste here

Stay tuned!

========================
Follow pyamsoft around the Web for updates and announcements about the newest applications!
Like what I do?

Send me an email at: pyam.soft@gmail.com
Or find me online at: https://pyamsoft.blogspot.com

Follow my Facebook Page
Check out my code on GitHub
=========================

Saturday, December 12, 2020

Some updates

PYDroid has been updated a bunch over the past couple of days to test the new in-app rating and update systems. I believe it finally to be stable, so the PYDroid version you should upgrade to from 22.0.4 is actually 22.2.7

Yeah, it took that many different build-test-deploy cycles until I finally ironed out all (most (some)) of the bugs.

FridgeFriend has been published with a new version bringing support for multiple Groups of Items, and all other apps are going through the internal and public beta channels. They will be published most likely later in the week.

I strongly recommend you update to these latest versions as they contain a bunch of fixes and improvements and better prepare you for any future updates as well.

Stay tuned!

========================
Follow pyamsoft around the Web for updates and announcements about the newest applications!
Like what I do?

Send me an email at: pyam.soft@gmail.com
Or find me online at: https://pyamsoft.blogspot.com

Follow my Facebook Page
Check out my code on GitHub
=========================

Tuesday, December 8, 2020

PYDroid Autopsy

PYDroid Autopsy is a new library which helps during development by showing a crash report page on the device when an application exits due to an uncaught exception.

PYDroid Autopsy is a debug only library which requires 0 code changes to use as it self-installs via a debug only ContentProvider. It overrides the UncaughtExceptionHandler, and does not call through to any other handlers, so be warned if you are using other tools during development that Autopsy is currently not compatible with other tools which override the handler.

PYDroid Autopsy shows a red crash screen as well as the stack trace whenever a crash occurs and the device is able to capture the crash before exiting. While this is not a 100% solution, it more often than not will help catch crashes in development. It will also fire the stacktrace to logcat for those connected to the Android debug tools.

Try it out today! Find it here.

Stay tuned!

========================
Follow pyamsoft around the Web for updates and announcements about the newest applications!
Like what I do?

Send me an email at: pyam.soft@gmail.com
Or find me online at: https://pyamsoft.blogspot.com

Follow my Facebook Page
Check out my code on GitHub
=========================

Faster Apps Better Libraries

It

Has

Been

A

While

First, the nerd stuff

PYDroid

Remember in your past life, PYDroid took this sort of stance

"When PYDroid triggers your view on a render event, it does not take the care to avoid duplicate re-renders when no data has actually changed. We believe it is best to handle re-renders in the UiView layer itself."

Ya so, times have changed thanks to StateFlow and its amazing ability to only fire events when attributes of a state have changed. Yay!

The old onRender(state: S) has changed to an onRender(state: UiRender<S>). The UiRender<S> is an interface which can allows the calling view to subscribe to changes and either emit the full state object, or only emit when a particular attribute on a state changes.

interface UiRender<S> {

  fun render(scope: CoroutineScope, onRender: (S) -> Unit): Unit

  fun <T> distinctBy(distinct: (S) -> T): UiRender<T>

}

This can improve performance dramatically in apps because now only certain relevant parts need to render when their relevant state piece changes. You still have all of the strengths of knowing that your state object is a single source of truth, but also gain the performance benefits of only drawing when you need to.

The distinctBy() function is useful for cases like, you want to show or hide a view based on a loading boolean, but the boolean does not control what data is present in the view. Before you would have:

fun onRender(state: S) {

  handleComplexChange(state)

  handleLoadingChanged(state.isLoading)

  handleDataChanged(state.data)

}

and both of these methods would get called even when just the loading state changed, or just the data state changed. Now you can be more specific:

fun onRender(state: UiRender<S>) {

  state.render { full -> handleComplexChange(full)

  state.distinctBy { it.isLoading }.render { loading -> handleLoadingChanged(loading) }

  state.distinctBy { it.data }.render { data -> handleDataChanged(data) }

}

For views that are more complex or derive their state from multiple attributes, the old expensive way can still be had by simply calling state.render() without any distinct filtering.

Migration should be made less painful by the fact that existing onRender(state: S) functions will continue to work, but are deprecated. Note that if you use your own custom class extending UiView instead of BaseUiView or PrefUiView, you will have to make a small API change to respect the new API. To keep existing behavior, call a plain render similar to the example above's handleComplexChange function call.

For UiViewModels, the state handling has been separated out to make the ViewModel less complex. UiStateViewModel<S> is a ViewModel which only handles accessing and mutating view state, it does not have bind hooks or clear hooks, and does not publish events to a controller. UiStateViewModel is powered by a UiStateModel<S> which is the class that actually handles a view state with accessors and mutators. This can allow you to use the PYDroid state model without needing to extend the full-fat UiViewModel, or even re-use a UiViewState modeled via a UiStateModel but have it interact with completely different UiViewEvents and UiControllerEvents in multiple UiViewModels.

The UiStateModel withState() function has been deprecated. To get the current state from within a state model, simply access it via the state variable. The setState function has also received an extra optional parameter, called andThen: (S) -> Unit, which is called only if the setState call results in a state change. In a future major version these deprecated functions will be removed.

PYDroid has also removed its custom update checking code and review prompting code in favor of Google's Play Store solutions for in-app updates and in-app reviews. This is done to make it easier to maintain these features, as before we were using a home-grown solution and Google's is much more battle tested, despite it resulting in a reliance on the Play Store. But, pyamsoft applications have only ever been published on the Play Store, so I do not see this lock in as a huge issue.

All pyamsoft applications have received support for the full-bleed window style when using gesture navigation. Gone are the days of a colored sliver of navbar where the gesture bar sits on the bottom of the device. Now the gesture bar will be transparent and will give a more modern Android look and feel.

FridgeFriend has gained support for multiple Groups of items instead of just one large Group of items. The multiple groups can be broken up into anything you find logical, like locations, or different fridges, or even by meal or food group. There is no strict system around what you can, and cannot do.

With recent Google restrictions to accessing location, FridgeFriend has made some changes about when it suggests you stores that are nearby. We already did not use Geofencing because of these restrictions, and do not request BACKGROUND_LOCATION, but Google has decreed that even a foreground permission level request, but made by something like WorkManager counts as background work. As such, you will only be able to receive nearby notifications from now on when you open the application.

Plenty more is soon to come and I hope to have a release out soon, but for now enjoy the holidays and stay safe.

Stay tuned!

========================
Follow pyamsoft around the Web for updates and announcements about the newest applications!
Like what I do?

Send me an email at: pyam.soft@gmail.com
Or find me online at: https://pyamsoft.blogspot.com

Follow my Facebook Page
Check out my code on GitHub
=========================

Saturday, September 26, 2020

On managing expectation, burnout, and monotony

Hey there, it's been a hot minute.

Couple of updates, nothing major in a sense, something huge in another. Let's get the elephant out of the room and back to the zoo - I'm tired.

Moment is dead. I've realized that my ambition to get it working was rather silly - given that plenty of other open source stock ticker applications exist and I could get the volume detection feature working much faster by just contributing to an existing project rather than rolling my own. Moment was a spark of inspiration that was edged mostly by not-invented-here syndrome. It was unrealistic to expect that I would be able to understand an industry and create an application tailored to a specific industry problem as an outsider in just a couple of months. The project is dead but the idea lives on in my brain, and may one day be contributed to another project. Here's the app that I currently use - maybe it will accept a contribution from a tired man one day.

Application updates are put on the shelf for about a week or two. While I did just release an update for FridgeFriend, I won't be doing much more work for the next few weeks unless something horrible blows up in the apps. I've noticed I'm getting into this mental rut of go to work (from home) and program. Get off work and program. Struggle with work problems that are a result of past coding decisions that now are affecting or limiting business opportunities and future business decisions. Struggle with personal project problems which are a result of past coding decisions that now affect or limit future coding enjoyment. Don't misunderstand, I still love doing this. I just don't love doing this all the damn time. I think I'll just need a small break - not from work since I need to pay the bills, but at least from a hobby which begins to feel more and more like work each day. Although that being said, I still am inspired now and again from the academic pursuits of programming, I just updated the PYDroid library with some hopefully less coupled ways to adopt the PYDroid MVI architecture, via adopting a lighter ViewModel into an existing architecture without needing to adopt the UiView and Component model. It's a longer technical talk which I'd love to indulge in one day - but not now.

To escape the bland monotony of my programming life, I've been attempting a couple of different activites. One being sleeping - the classic sign of depression. But aside from that, I've been playing music (and listening to music), I've taken a deeper interest in the puzzle game Tetris over at this lovely website, I've gotten back into smash, and I've been reading lightly to get myself into the hobby, and out of the mindset of just programming all the time.

Music has helped me to relax and engage a more creative side of my brain in a pursuit other than coding Though I would argue is programming of the most creative pursuits the human condition can take part in, the way of thinking becomes too result orientated in many instances and limits the creative expression that one needs to mentally and emotionally thrive. Both the consumption and creation of music engages the creative side that is less result orientated and lends itself better to simply creating for the sake of exploring the artistic side of ones process.

In a similar way, griding out games of Tetris like a giant fucking nerd also helps me engage a creative side of my brain that has been left out for a while. While I would argue there is a "best and most" efficient way to play Tetris, I would also argue that the human component of the game prevents the best and most efficient way from ever actually being used. People have comforts and preferences and style which they imbue into many facets of their life, including how they play a simple puzzle game. Do you stack on the side in a 9-0 or closer to a 6-3? Do you react to garbage with defensive downstacking or aggressive compounding? Do you go for a guaranteed T double now, or take a chance on setting up a Trinity? Do you even care at all? It is - after all - just a game. How one chooses to find enjoyment in a game is up to the player. Creative expression through a restrictive medium often brings out the best in us all.

Smash is like Tetris for me though I've had more experience with it. Simple to pick up, impossible to master. Let's not overestimate here, I'm awful at Melee. I love the game, I'm awful at it. But it is probably one of the most creative and rewarding video games I've ever experienced. If you practice you will be rewarded. If you can dream it, one day you will do it. Hands down the best fighting game I've ever failed at - one of my favorite games of all time. Eternally frustrating, but magically relaxing and exciting all at once. I highly recommend it to anyone who even has a passing interest in fighting games. You will love it. You will hate it. You will suck at it. Fair warning, you'll hate every other fighting game though. Not to the point that you'll never play them again, but just to the point that you'll know in your heart - whenever you play anything else, you could be playing Melee. Learning to play Melee will change your life - I don't know if it will be for the better or not, but you'll at least get really good at pushing the right buttons at the right time at the right speed. You'll play one of the greatest fighting games to grace the medium, and you may make some friends along the way. You'll always suck though. That one never changes.

I've always been a music guy, I've always been a gamer. I've - for a while now - been a programmer. It's no surprise to me that I would gravitate towards these activities when I felt like I needed a break, as I have done in the past and will continue to do.

Reading has been the most surprising escape for me. I don't read. I'm not a book lover, I'm not a literature guy. I read Harry Potter growing up. Stopped at the second book and just watched the movies. I owned the Lord of the Rings, and Redwall. I read the first page, the middle, and the last page of each (although I did read the Lord of the Rings appendix and extra bits). I just never cared for reading much. Sure, I read tech blogs, or video game reviews. But almost never books, except for school. Certainly never non-fiction books. Absolutely never any book that required me to think hard. How strange then - I've read and finished Man in the Holocene (again) last week, and I'm currently reading the Republic during my brief trips to the bathroom. I love it. It makes me think, really think, about things that will never show up in or affect my day to day life, and are yet so fascinating to consider and question. As a nice reprieve from the result oritentated rutt of programming, some of the questions posed in reading have no answer, and expect no answer. It is refreshing to not need a response. It is liberating to be able to think solely for the purpose of contemplation. It is refreshing to see an author pose a question, take a position, and leave the floor open for debate. It's a nice change of pace.

This has been long, and rambling, and I apologize. I've never been the strongest writer - perhaps because I was never the strongest reader. Hopefully after a couple of weeks of break and refreshment, I will return the strongest programmer.

Stay tuned.


========================
Follow pyamsoft around the Web for updates and announcements about the newest applications!
Like what I do?

Send me an email at: pyam.soft@gmail.com
Or find me online at: https://pyamsoft.blogspot.com

Follow my Facebook Page
Check out my code on GitHub
=========================