NativeScript-Core replacing the root view...

Please note this to my knowledge only works with NativeScript-Core / PAN (Plain Awesome NativeScript) applications. I do not believe this will work with the Vue or Angular variations of NativeScript. There maybe another way to accomplish this with those variations, and if you know how -- please let me know and I'll update this post.

So I was minding my own business again, and I saw this question pop up in NativeScript GitHub. Take this scenario; you want to have a SideDrawer that is active on all pages.

Seems simple enough you create the /app-root.xml as this:

&lt;nsDrawer:RadSideDrawer xmlns:nsDrawer="nativescript-ui-sidedrawer"><br>    &lt;nsDrawer:RadSideDrawer.drawerContent><br>        &lt;GridLayout backgroundColor="#ffffff"><br>            &lt;Label text="Go to Cool Page" tap="page1"/><br>            &lt;Label text="Go to Another Cool Page" tap="page2"/><br>        &lt;/GridLayout><br>    &lt;/nsDrawer:RadSideDrawer.drawerContent><br>    &lt;nsDrawer:RadSideDrawer.mainContent><br>        &lt;Frame defaultPage="/pages/main/main-page">&lt;/Frame><br>    &lt;/nsDrawer:RadSideDrawer.mainContent><br>&lt;/nsDrawer:RadSideDrawer><br>

But now I need a login page... And my awesome side drawer is now active on the login page. Uh-oh -- it even has a ton of links that go to places and so we don't want that if they haven't even logged in. In fact we probably don't want them to even have access to the side drawer when not logged in...

What is the solution?

My solution, is fairly simple is you revert your code back to close to the default app-root.xml:
Your <strong>app-root.xml</strong> actually is changed to this:

<Frame defaultPage="/pages/login/login-page"/>

That is because we want the main frame of the app to load my login page; in this case my login page will force them to login if they don't already have a valid stored login token... Notice, their is no SideDrawer, because it is no longer the root.. So part one is working great, no side drawer during login...

So now how do we get our cool SideDrawer to be active on the rest of all the pages...

const Application = require('tns-core-modules/application');<br><br>function loginIsValid() {<br> <strong> Application._resetRootView("/pages/root/root");</strong><br>}<br>

Yep, look their -- there is a cool feature in the framework that allows you to REPLACE (or RESET) the root view. So by doing this, my /pages/root/root.xml file now contains the SideDrawer root layout which I displayed at the top of this post.

Notes:

My own personal applications typically are laid out in such a fashion that I have a "pages" folder, and in the "pages" folder I have each separate page js, CSS, and XML. This typically allows me to quickly find the page I want to work on.

NativeScript AndroidX support and Plugins

The next major version of NativeScript (version 6) will be switching from the android.support packages to the new androidx namespace. This will be a hard break; as you can only use the support api's or androidx api's; but not both. This is something Google has been implementing for a while; and NativeScript is getting on board to eliminate later issues and give us great support. The awesome developers at Progress have already created a fork of NativeScript; which you can install to test which uses androidx instead of using the support libraries.

Since one of my plugins is affected by the changes; I took a look into what was required to support both the current versions of NativeScript and the new upcoming version of NativeScript.

For any of you who have plugins; this code is what I basically devised.

let androidSupport=null;
if (android.support && android.support.v4) {
  androidSupport = android.support.v4;
} else if (global.androidx && global.androidx.core) {
  androidSupport = global.androidx.core;
}

Then you can use androidSupport to access the namespace, and it pretty much works the same as what you would access using android.support.v4 or the new androidx.core replacement. Because we used feature detection; this allows us to support both namespaces in the same code base.

So if you have JavaScript or TypeScript code that uses android.support.* then you can use this technique to make your plugin forwards compatible with the next major version of NativeScript while retaining support for the prior versions.

Here is a list of classses that are being moved from android support to androidx: https://developer.android.com/jetpack/androidx/migrate

VMWare Network Hickups ( sent link down event. )

I ran into this because I went to a hotel that had DHCP renew every 300 seconds, trying to download something inside the VM was getting clobbered...

If you check your syslog or kern.log and see the following entries; then I might have the solution for you:

kernel: [235397.022939] userif-3: sent link down event.
kernel: [235397.022943] userif-3: sent link up event.

Then the issue is one that when your DHCP renews it calls into the kernel with the new information; unfortunately this causes VMWare Workstation & Player (might effect other VMWare products?) to reset its network stack, even though nothing changed...

The solution after a lot of time googling different terms and trying to figure out what exactly was going on. I finally found it here (by Jan Just Keijer): https://www.nikhef.nl/~janjust/vmnet/ it was for an much older version of VMWare Player; but the solution still applies to VMWare workstation 15...

To make sure the information doesn't just disappear in the future (and so I can easily find it myself) I'm going to quote the relevant code and/or modifications I did..

Extract the /usr/lib/vmware/modules/source/vmnet-only.tar tar file, you need to modify the userif.c file. Search it for VNetUserIfSetUplinkState function and right after the variable declaration add if (!linkUp) return 0;

// Around line 966
VNetUserIfSetUplinkState(VNetPort *port, uint8 linkUp)
 {
    VNetUserIF *userIf;
    VNetJack *hubJack;
    VNet_LinkStateEvent event;
    int retval;

    /* ADD: never send link down events */   
    if (!linkUp) return 0;
    /* END Added code */
    
    ... rest of code ...

This will eliminate the linkdown events; which disconnect the internet from the VMWare network driver...

After you do that; recreate the vmnet-only.tar and replace the original. Then you can run: /usr/bin/vmware-modconfig --console --install-all

And then either
systemctl restart vmware
or
service vmware restart

If you still see " sent link down event." in your logs; then the patch wasn't applied properly.

NativeScript 5.30 Released

NativeScript 5.3 only offers a smaller number of fixes and features than usual; but is still well worth upgrading to.

The most interesting update (for me) is actually the Android V8 engine has been upgraded yet again, but this time to a version that offers some nice performance benefits. It is always nice when an upgrade will increase the speed of your app with just a rebuild of it.
In addition some awesome work has been done on the iOS engine that should also result in a speed enhancement.

So just upgrading the runtimes to 5.3 should give you a faster app...

Important Depreciation Notice

In version 5.2 short imports have been depreciated; I do not know when they will no longer actually work; but basically things like require("http") are no long valid; you need to do require("tns-core-modules/http"). The primary reason for this is that webpacking requires the full path; and it has problems with short imports.

Core Modules

The core modules offers the following enhancements and fixes...

Resource ID on Android error fixed during Navigation
Webview and TabView fixes
Icons on Tabview and ActionBar should look better
View classes now have the missing .background* Style options.

Android

Upgrade to V8 7.3.492 - which offers
- Faster Await
- Faster JS Parsing
- Faster Spread Elements
- Embeddins supported in ia32 now
NativeScript Arm64 support built in on release versions
Static Binding Generator fixes and enhancements
Gradle 3.3.2 support.

iOS

Lazy Evaluation - Performance
Many Debugger fixes

CLI

HMR is no longer considered Beta; almost all critical issues with HMR are now resolved.
Several debugger issues resolved



Updating NativeScript

To get updated; you first need to do:
npm i -g nativescript@latest

That will get you the latest version of NativeScript CLI; once you have it; do a "tns --version" and verify it prints out "5.3.x".  Then do a "tns doctor" to verify your environment is up to date and has all the newest support tools you need for a successful build.  

To update a project; you need to do the following:

Latest Runtimes:
tns platform remove android && tns platform add android@latest
tns platform remove ios && tns platform add ios@latest

Latest Core modules:
npm r tns-core-modules --save
npm i tns-core-modules@latest --save

To install Webpack & HMR support:
npm i nativescript-dev-webpack@latest --save-dev
Note: you need to have nativescript-dev-webpack as a development dependency for HMR to work.  

To install latest NativeScript Angular plugin
npm i nativescript-angular@latest --save
You will then need to install the actual angular bits; which as of this post v6 is currently supported.

The addition of all the additional analytics/tracking to the CLI reminded me; you can disable it permanently; if you value your privacy by doing:
tns usage-reporting disable && tns error-reporting disable


Known issues

  • Android Q is not supported properly; The fix is slated for 3.3.1
  • TNS frequently (for me at least) kills the build with "Error is: cp: cannot create directory " and to fix you have to reset your platforms. (This might be more plugin development related corner case)

NativeScript 5.2.0 Released

NativeScript 5.2 offers a wide number of fixes, and is well worth upgrading to. Checkout what has now been fixed and/or enhanced in this awesome release from the NativeScript team.

One of the more interesting things for iOS is the In App Podfile and Src code support. Drop your any src code into the /App_resources/ios/src and/or a Podfile in /App_Resources/ios and your app will automatically build it with your app. So you don't need to create a plugin to test or embed things in your app anymore. Plugins still are good for reusable code; but sometimes you might just have a simple function or Podfile that you just want added to your app.

Important Depreciation Notice

In version 5.2 short imports have been depreciated; I do not know when they will no longer actually work; but basically things like require("http") are no long valid; you need to do require("tns-core-modules/http"). The primary reason for this is that webpacking requires the full path; and it has problems with short imports.

Core ModulesT

The core modules offers the following enhancements and fixes...

Dialog now supports Decimal type
ImageCache now has onError exposed
onDiscardedError now officially in the typings
Android model fixes
iOS Flat Actionbar fixes
Password hint support
Multiple crashes fixes

Android

Upgrade to V8 7.1.302 - which offers
- Stable Sorting
- More bytecode embedded saving 200kb of memory per engine.
- Escape analysis improvements (up to 40% faster)
- globalThis support
- Intl.RelativeTimeFormat support
Android X support
Ability to free Java memory that is being retained by a JS object
Gradle 3.3.1 support.

iOS

OnDiscardedError handler now works properly.
Can now manually free OBJC memory that is being retained by a JS object
Can now call ObjC methods with the same name but different parameters. (I've ran into this bug myself -- woohoo!)
GC tuning parameters
JSC tuning parameters

Fixes in Exception handling
Memory allocation fixes
In App Podfile and native Src code support

CLI

Node 11 support
Angular HMR support (finally fully working!)
--debug-brk on iOS should be working again.
Unit testing should work on Android again.
Fixed High CPU usage issue.
generate splashscreens should work again.
HMR will now update styles.


Updating NativeScript

To get updated; you first need to do:
npm i -g nativescript@latest

That will get you the latest version of NativeScript CLI; once you have it; do a "tns --version" and verify it prints out "5.2.x".  Then do a "tns doctor" to verify your environment is up to date and has all the newest support tools you need for a successful build.  

To update a project; you need to do the following:

Latest Runtimes:
tns platform remove android && tns platform add android@latest
tns platform remove ios && tns platform add ios@latest

Latest Core modules:
npm r tns-core-modules --save
npm i tns-core-modules@latest --save

To install Webpack & HMR support:
npm i nativescript-dev-webpack@latest --save-dev
Note: you need to have nativescript-dev-webpack as a development dependency for HMR to work.  

To install latest NativeScript Angular plugin
npm i nativescript-angular@latest --save
You will then need to install the actual angular bits; which as of this post v6 is currently supported.

The addition of all the additional analytics/tracking to the CLI reminded me; you can disable it permanently; if you value your privacy by doing:
tns usage-reporting disable && tns error-reporting disable


Known issues

NativeScript-SQLite Multi-Threading!

The first release of NativeScript-SQLite was April 19th, 2015 on GitHub, and April 26th to NPM. I am happy to say this plugin is now almost 4 years old, and it was one of the first plugins available to NativeScript. I believe there was two or three others released before, like NativeScript-Flashlight. By June of 2015 we had a grand total of 18 (eighteen) plugins in the NativeScript eco-system, where today we are at almost 1,000 plugins.

NativeScript-Sqlite has had a lot of upgrades like encryption, prepared queries, and several bug fixes over the last 4 years. But the newest feature; I'm probably the most proud of. Without your app changing a thing (besides setting a simple option flag); NativeScript-Sqlite can now be fully multithreaded. What do I mean by that? In a nutshell all SQLite calls can now happen in a background thread. This means that if you are inserting or reading 20 records the UI won't freeze.

A couple years ago I did a session on Performance and NativeScript; my sample app showed how doing several different things could freeze the UI easily; and the best way to deal with this was to move as much of your work to background threads.

Now if you watch this image; every time I hit the SQLite button, the "n" freezes for a few seconds. This is because the work loading and processing the records is all done on the main thread which is the UI thread, causing the Animation to stop and/or stutter.

Since NativeScript-Sqlite has always been Promise (and/or Callback) based ASYNC code; it ended up that I could preserve the entire API as is; when allowing you to use multithreading. You just need to set a flag when opening up the connection and it will become multithreaded.

And this is what it looks like when sqlite is doing everything in a background thread. Notice how smooth it is. This is because the main thread is just waiting for the acknowledgement back that everything has been loaded.

If you check out the demo app; the code change is just this:

[[code]]czoxMDk6XCJuZXcgc3FsaXRlKGRibmFtZSwge2tleTogXFxcJ3Rlc3RpbmdcXFwnLCBtdWx0aXRocmVhZGluZzogISFzcWxpdGUuSEFTX0NPe1smKiZdfU1NRVJDSUFMfSwgZnVuY3Rpb24oZXJyLCBkYkNvbm5lY3Rpb24pIHtcIjt7WyYqJl19[[/code]]

Basically if the commercial plugin has been loaded; we flip on the multithreading flag. Otherwise we leave it off. (This way the app can test, Encryption, Multithreading, Commercial features, and no extra features all in the same codebase.)

The open source version of the plugin can be easily installed by typing tns plugin install nativescript-sqlite@latest, the open source repo can be seen at https://github.com/NathanaelA/nativescript-sqlite.

The commercial version which includes Encryption, transactions, prepared queries, and now multithreading can be purchased from my site at nativescript.tools.

NativeScript 5.1.1 Released

Even more fixes have come down the pike. Based on some of the bugs that have been squashed it appears that if you are using v5.1.0 you want to upgrade to v5.1.1 as it should make your life a little easier.

Core ModulesT

Technically they released 5.1.1 of the core modules last month; as it was a quick release that fixed several issues with 5.1.0.

v5.1.1 several android issues; and added a new ios model system, they moved context into an options hash that you now pass in its place; in addition several other parameters that used to be separate parameters are now part of the context. This cleanup allows new features to be added in the future. The old showModal function is still supported, but marked as depreciated.

5.1.2 was released with the rest of the updates this week; this version fixes the Android crash in Listview switching templates.

Android

Nothing done which needed a new Android runtime version...

iOS

Debug logs show in Chrome again

CLI

Debugging on iOS when using HMR is now fixed, many issues resolved
Many Yarn support issues fixed
Sidekick and Preview app fixes
A couple CLI crashes fixed when running/debugging.


Updating NativeScript

To get updated; you first need to do:
npm i -g nativescript@latest

That will get you the latest version of NativeScript CLI; once you have it; do a "tns --version" and verify it prints out "5.1.x".  Then do a "tns doctor" to verify your environment is up to date and has all the newest support tools you need for a successful build.  

To update a project; you need to do the following:

Latest Runtimes:
tns platform remove android && tns platform add android@latest
tns platform remove ios && tns platform add ios@latest

Latest Core modules:
npm r tns-core-modules --save
npm i tns-core-modules@latest --save

To install Webpack & HMR support:
npm i nativescript-dev-webpack@latest --save-dev
Note: you need to have nativescript-dev-webpack as a development dependency for HMR to work.  

To install latest NativeScript Angular plugin
npm i nativescript-angular@latest --save
You will then need to install the actual angular bits; which as of this post v6 is currently supported.

The addition of all the additional analytics/tracking to the CLI reminded me; you can disable it permanently; if you value your privacy by doing:
tns usage-reporting disable && tns error-reporting disable


Known issues

Australian AABill

If you look at my blog; I do believe this is the first article I've ever written about something political.  I tend to be anti-political because I feel like it just divides us and tends to be just complaining with no one actually doing anything meaningful about it.

However two days ago I noticed in the news that the AABill was about to be passed.  I had read about it before, but since I'm not Australian (and I don't work in Australia) it really doesn't affect me "personally" right this minute.   However, the reality hit me later, that it does affect my friends; and it has a very high chance of affecting all of us in the future.  What the Australian government gets away with now; the rest of the "civilized" countries will also attempt to implement someday.    

Our own (USA) FBI has been hankering for this power for years; and so far they have been thwarted; the Canadians have thwarted similar issues in their country.   Europe; has caved to a lot.   So much of what Australia did; they took from Europe.  They just went a lot farther.  The more nations that cave; the easier it is for the other nations to do the same thing and go farther.   

This bill is BAD!    So bad, if it was meat it would have to be launched into the sun to actually eliminate the deadly bacteria.   If it was a meteor we would all be wiped out instantly.   

In a nutshell the bill gives the Australian government the right to require people and/or companies to implement back doors into any systems (web, phones, your apps, banks, encryption, etc).   

  • No real  over sight   "Trust us; we won't abuse it..."   (I bet they  have a bridge to sell us too.)
  • Massive mandatory punishments for speaking about the request; to anybody -- even if it is to defend your reputation or job when the back door is found..
  • Severe Anti-whistle-blower rules to eliminate anyone attempting to do the right thing, when the government is doing the wrong thing.   Trust us we won't abuse it...
  • The improbability that the person served with the "backdoor" order can actually bypass the security of any company that is multinational is... well, rather ludicrous.  More than like instead it will cause their own termination and potential black balling of the poor developer in the industry since he can't defend himself nor mention why he tried to subvert the software.
  • Trying to backdoor anything, is a criminal paradise.    We all know that no bad guys ever fine issues in any thing, never happens...
  • Backdoored encryption, what a joke.   
  • What Australian developer (or company) can I now trust with my code, data or hosting?
  • Beware of that bridge for sale...

I can go on an on about the terrible things in this bill...   Suffice to say; this is a very bad bill and that it has world wide implications.

I posted on twitter that I thought that maybe the internet community should route all the Australian government IP's to a banned page saying that until the bill is repealed they are being segregated to limit any more damage they can generate.

Several people posted they thought that was a good idea.   And it dawned on me, all I was doing was still just complaining and offering ideas that nobody would probably do.   In all reality I wasn't really doing anything at all.

So I got off my butt; and actually did something.   I purchased the domain name internetprotests.com; I then proceeded to setup a simple site.  Figured out several blocks of Australian government IP's to be routed to the banned page.    Figured out how to make the routing work in both Apache 2.4 and Nginx, and published the site.

I have attempted to start something here; and I cannot do it alone.   

If you are a internet provider or you have control over a website.  I urge you to check out the internetprotests.com site and become involved.  The more sites that blackhole all the Australian Government IP's; the more likely they will be forced to actually repeal the law if they want to be able participate on the internet.   

 If you don't own any websites; please pass this blog and/or the site around.  If you do copy editing, graphics works or technical work; the site is open source and could use more work prettying it up and making it more appealing to the masses and the press.   It was built quickly to try and spread the word because the tech world is starting to understand just how bad this law is.

If we can get the law repealed in Australia; then that will make all the other nations have second thoughts about trying it in their nation.   Maybe we the people of the internet can actually get our government to listen to us and follow our lead...

Security with Apps on iOS and Android.

Recently a person on twitter asked about a statement that Max made in a blog article which he did on the official ionic blog.  For those who know me; I actually am pretty heavily into security; and I happen to have used many mobile technologies  Cordova/Phonegap/ionic, Flutter, Titanium, React Native, Java, NativeScript, ObjC, Swift, etc -- so this article is right up my alley.   So lets start with the quote that started the tweet...

Some toolkits, like NativeScript, take the approach of exposing every Native SDK API to JavaScript. We think the security implications of that are undesirable, and it doesn’t remove your need to learn platform-specific APIs. We don’t think you should have to learn those APIs if you don’t want to, and we don’t think you should expose all Native APIs to JavaScript for security reasons.

(Quoted from Max's blog post linked above)

Initially I saw this tweet and was well saddened that Max feels he had to bad mouth his competitors to make his product potentially look good.   Unfortunately the statement Max made is 100% pure marketing FUD (Fear, Uncertainty, & Doubt).  He is just try and make a competing framework look bad with the hot button topic called security.    All it does in my opinion is make him, and his product look bad, and it is on the official ionic blog.   Compete on what you do great; not on trying to make the competition look bad (especially with FUD).

The real truth of this matter is that no matter the framework the same security surface exists.  Unfortunately for Max, this includes ionic!

So lets say I'm a evil person and I want to take over the world with my evil ionic app.   What do I do?

[I]...wrap a Native SDK and expose it as a reusable component that can be easily consumed in JavaScript ... Native Views provide a structure for wrapping and consuming a Native SDK so that it can be easily and safely exposed to JS...

(Quoted: from the same blog post linked above)

Oops; I guess I safely exposed some very bad methods  and succeeded in doing the exact same thing in ionic.  The only thing is I had to add the exact same code in a different place and expose it so it is easily consumed  using my exposed call "doBadThing()" in the JavaScript side of ionic when I need it to do my evil bidding.      Does that mean ionic shouldn't be trusted since I can easily and safely do very bad things in ionic?   See the problem, for me to do GOOD things in ionic; that gives me the same power to do BAD things in it.  

The reality is this means that just like I can do bad things in 100%  pure Java app, Kotlin, C/C++, NativeScript, React Native, ObjC, and Swift (name the framework); I can do it just as easily in Ionic.  None of them are immune!     This doesn't mean any specific platform is worse or better; they all have the ability in one way or another to access the exact same api's which can be used for evil purposes.   The bad code in all of them is literally the same; just the location in the app calling it is different.   

Now not to get into a more technical discussing; there are some areas where the frameworks do have some differences that may allow certain things to be easier to miss.  For example; using proguard can hide method calls in native Java code.  However overall this does not change the relative security of each of the frameworks.   You name the framework; and I know a way to make it hard for you to detect my evil code..   They all have pretty close to the same level of security surface.  

Now that I've explained the FUD and debunked Max's unfortunate dig at his competitor; I would like to explain where I see the real security issues with Android and iOS.

The real security vulnerabilities is our trust model.   We are now seeing it play out more and more where a developer creates a decent app.  It gets a decent reputation and then it gets sold to another developer.   The "other" developer is sadly not your friend.  Unfortunately; they add "bad" code; upload it as a minor fix to the app; and bam your Android or iPhone now is doing stuff you would rather it not be.   This has happened on ALL platforms, ALL types of code bases and so far none are immune.   Eventually they are caught (at least we hope) and the app is removed from the stores and you see a article about how 20 apps by XYZ dev had malicious code in them...

But the root problem is trust was built; and then outside of our control and knowledge; the app transferred to a different vendor who hasn't proved himself.  This is a hard issue to solve.     Do we say when you sell your app; it no longer can be auto-updated and has to be manually updated the next time so a notice will appear?    Or can we make the stores possibly notify us on the next upgrade with a re-install dialog announcing that the app has changed hands?    What has the best chance to be detected by the community and looked into?

I think that either of those ideas would be a good first step; but it won't solve this issue.  Bad actor then waits several months and then posts his "bad" changes.   Likely hood of being caught went drastically down, as we all get busy and our trust level goes up...  But at least the community is aware of the change of ownership and so some of them might still be diligent...

My next suggestion, is something unfortunately neither Google nor Apple will ever implement because our personal information is their bread and butter...   

I believe the real solution is that our devices should have two additional features: 
1. Built in firewall added to the OS.  The firewall is allowed to block all traffic for a specific application.   Easily enabled and disabled per application.   
2. Lying Data Module - This is a little harder to explain and a bit more advanced but basically you can tell the OS to lie to the app.  The app asks for your location and you have pre-configured the OS to always say you are at the north pole.   The app asks for the temperature; and again you pre-configured the OS that the temperature is 200 degrees.   It asks for your phone number and it returns 555-555-1212.   For the apps that need the real data (like maps, needs your location) you tell OS to tells the truth about GPS location.  But otherwise the same dummy data is passed by DEFAULT to every app.   If your map app asks about your phone number, it gets the same 555-555-1212.   This eliminates the app (& companies) from actually gathering any valuable data, and effectively the database will be poisoned making it virtually worthless to the company trying to collect the data.

With those two items; you could take control of your digital lives on your android or ios devices.  Yes, it requires more setup as when an app starts you have to tell it what you want to allow it to have access to data wise.  (or maybe when it requests something).

If anyone has an idea how to actually get Google or Apple to implement this in their Operating systems; I would love to hear feedback as I feel this could drastically improve our digital lives.    (and yes I know if you have a rooted android phone -- both are available to use right now.)     

Disclaimer: I have written books, blog posts, and plugins for NativeScript; so I currently do have a preference towards NativeScript.  However, anyone in the community that knows me; knows I'm the first person to call a spade a spade and argue about how this feature is horrible in NativeScript and awesome it is in framework X.  I can tell you several things I think that NativeScript is doing wrong or poorly.  (Just look on github)    I have written apps and/or thoroughly investigated the security and software stacks of each of the frameworks I've mentioned in this article.    I am not employed by Progress, nor is this blog sponsored by them -- all posts are strictly my own opinions.