Quickly adding .desktop menu files

For those who use Linux with a Gui, you may be like me and haven't found a good way to create .desktop files for any new applications you downloaded. I googled and tried many stackoverflow posts, and found Alacarte which allows you to edit menu items and re-org your menu. But never found anything that I could use from the CLI.

This weekend I spent a couple hours and build a simple tool called "desktopmenuitem".

It allows me to do this:

Animated adding of a new .desktop file

Basically you can just run it and point it at the executable and it does the rest. However, it does allow you to change up a lot of items from the cli.

Hopefully this helps others. You can install it via npm;

npm i -g @master.technology/desktopmenuitem

and the repo for the source code and issues is here: https://github.com/master-technology/desktop-menuitem

PSA: Your Android and iOS Application is not secure...

I was talking to a community member about some of the sites I run (and I mentioned a site called https://AppProtection.net) as they didn't realize I also do a lot of server side work. However, she was shocked that the source code for her app was easily accessible by everyone.

If you write an application with NativeScript, React Native, Cordova/PhoneGap/Ionic (and many other platforms) are you aware you ship the entire JavaScript source code, styles, layout code in your app.

For simplicity we are going to look at a NativeScript application that we will generate quickly so you can easily follow along. These steps apply equally for React Native and the Cordova based eco-systems.

You can uses tools like apkeep to download APK's directly from Google play store, or you can use something like Apple Configurator 2 on Macintosh to download the IPA from the Apple iOS store to your computer. Anything published to either store can be retrieved to your computer directly, and that is when the fun begins...

How easy is it?

 ns create demo --js
 cd demo

This command creates a demo application, for simplicity I'm just going to use pure JS, but again this applies to all the NativeScript flavors, Vue, Angular, TypeScript, React, etc.

Now we are going to make some minor changes to the main-page.js file to look like this, as we want emphasize that any secrets are NOT secret! This includes all Tokens, your http(s) URL endpoints, API keys, passwords, usernames, etc....

import { createViewModel } from './main-view-model';

const secret_HTTP_APIKey = "Hi_IM_A_SECRET_TOKEN_USED_ACCESS_SOME_API";
const private_Firebase_Token = "Hi_IM_your_Secret_Firebase_token";

export function onNavigatingTo(args) {
  const page = args.object
  doSomethingWith(secret_HTTP_APIKey);
  doSomethingWith(private_Firebase_Token);

  page.bindingContext = createViewModel()
}

function doSomethingWith(value) {
  <strong><em>console</em></strong>.log("Pretend HTTP Call with token", value);
}

Now we will build it:

ns build android --copy-to .

I'm using the <strong>--copy-to .</strong> so that we copy the final apk to this folder so we don't have to go looking for it in the platforms/android... folder, you should have something like this now...

The app-debug.apk (or .ipa for ios) is basically what is uploaded to Google Play or the Apple iOS store. Lets look at this file. If you unaware a .apk is just a .zip file with a different file extension. In my case, I just renamed it to .zip so that Midnight Commander (my favorite terminal shell) can navigate inside and view files directly....

Opening up the .zip/.apk file, and for NativeScript navigating to assets/app you will see the files that matter. The bundle.js is your application code, the vendor.js is all the plugins and NativeScript core code, so 99.9% of the time this is a pointless file for reversing your app. However, if you have custom plugins this would have that code. You can also see any worker javascript files if you are using any workers, and angular has some code splitting that can create some other separate javascript files. The bundle is typically the most important file... Lets just copy it out of the zip file so we can open it into a real editor....

How secure is my JavaScript, lets see the main-page.js?

Opening bundle.js up in PHPStorm, this is what we see:

Opening up bundle.js

Interesting it tells us we have 6 files that were compiled into this app.

Lets look for the main-page.js inside the bundle! Simply do a search for main-page.js and this what we find around line 100 in the bundle.js file (that is because the prior 80 lines or so is all the CSS that was bundled from app.css and the default imported theme css files)

main-page.js entry

Wow, 100% full source code including all your awesome secret keys and tokens (which I selected)... If you compare this to our file above, the only difference in this code is that we original did <meta http-equiv="content-type" content="text/html; charset=utf-8">export function onNavigatingTo(args) and this removed the <strong>export</strong> from the function on 114 and added it on line 105 - 107 as a __webpack_exports__. Otherwise this code is identical.

What about the layout, Main-Page.xml?

Lets search for main-page.xml, oh it shows up on line 193...

main-page.xml entry

It is just one long string... What happens if we copy & paste it to a newly created test.xml file. How different is this from the original main-page.xml file, not a single change. It is the exact same file.

Uh oh...

Can anyone tell me how quickly I can take your fully released app, that you spent months or years on creating and make my own 100% full clone? Or perhaps even do things more nefarious and add, edit, or steal any data from any of your private endpoints?

What can you do about this?

There is three things that I'm aware of

  • Minification (Built in to NativeScript & React Native)
  • Obsfucation (Lots of different tools)
  • Encryption

Minification

Well, the first thing people think of the minimization using Terser (or uglify). NativeScript uses Terser by default.

Lets see what happens when we minimize the code using NativeScript 8. Here is the bundle.js file using minification.

Minimized output

This looks hard to parse... But lets see what happens if we use the awesome "Reformat code" option in phpStorm/webStorm...

Code automatically reformatted.

Well, it is different, but still totally readable. How about the main-page.js and our secret keys?

Well that id disappointing, the code is perfectly readable and usable. All your secrets api keys are well, not at all secret. The only thing missing is all the comments were stripped and my "console.log" was removed from the doSomethingWith routine. But the code is very readable and can be dropped virtually as-is in a new main-file.js javascript file. If I wanted to make this file to work in a new app, I would just need to replace "r" with "require" and add the "export" to the onNavigatingTo function and it would be 100% working. Add a couple refactors like "t" to "page" and extract the API keys to variables and it would be virtually identically to the original you wrote. Lets see, hacker 5 minutes, you 5 months.

As you can see minification does nothing really to hinder anyone. But it is a good step for optimization but adds zero security.

Obfuscation

What about obfuscation, this really depends on the tool. I have a blog post about this security of this. However, rather than re-iterate it, it is almost as trivial to reverse as we just did with minification. The only tool that took me longer than a few minutes to reverse was JSScrambler. However for JSScrambler to work you have to set this at its highest level and enable code protections so that a hacker can't easily modify the code. Unfortunately, the last time I tried this is slowed all of the code down by 30-50% the entire life time of the application.

Compiled Code

This is probably the next best thing, if you create a function that has your api keys encrypted in it and you have to call a couple functions to return them before you use them they won't be visible in the source which seems like an awesome win. However, if your JavaScript code has:

const api = getAPI(); 
const key = getKey; 
https.get(api+key);

Do you have any idea how quickly I'll get your api & key, I'll just change the code to be:

const api = getAPI();  
const key = getKey;  
console.log(api+key);

Did you slow me down, yes, by how much -- maybe 15 seconds to modify the apk and upload it to by emulator (or a jail broken android/ios device) . So if you use this method, please do NOT telegraph how to get your Key & api endpoints. At least be more discrete as when I do a search for "https" or "firebase" in your code base you don't want to point me to where I need to go next.

React Native offers a engine called Hermes where it partially compiles the code, this is more secure than the pure JS code mode, but obviously not as secure as pure compiled. However, even in pure compiled code, if you do nothing to obfuscate your keys and api end points, just running strings against it will give you everything a hacker needs to attack your end points.

Encrypted Code

First a major disclaimer here -- I am the author of the AppProtection system, of course I recommend it. Second disclaimer, this is currently NativeScript only, but if I get enough interest for a React Native version, I'll port it as I have all the code all done for both v8 and JavaScriptCore engines. But I have to spend the time adding it to the React Native tooling. Basically this encrypts the source code for your release apps. This is what a release file looks like:

Encrypted Code

The source code AES encrypted, and the only unencrypted copy is in memory (never saved to disk) while the app is running. The actual v8/JSC runtime engine itself has the modifications for understanding AES encrypted JS code, no extra code is shipped in your app. Is it perfect? Nope, but it adds another very difficult wall to climb...

The 100% Solution

Click bait! Sorry there is no 100% solutions. I haven't heard of any of the AppProtection applications being cracked, but that doesn't mean it can't be (or hasn't been). I will tell you upfront everything can be cracked, including AppProtection. Even Denovo which is used in high profile games and has millions of dollars in revenue. Eventually, each new release gets cracked. Everything can be hacked with enough time, patience and knowledge. However, the whole idea of security is you put enough walls in front of your attacker to make him want to go to a much easier target. If they leave, then you have thwarted an attack. Do you really think most attackers or application cloners want to spend weeks pulling your data or cloning your app, or switch to something that only takes them a few minutes?

More information

  • I have another blog post I wrote in 2019, everything is still valid and I discuss other things you can do in your app for security and other security gotcha's.
  • I am available to do consulting work to help you beef up your security both server and mobile. I also do core reviews, and training if your developers need to learn some better practices.
  • You can email me at nathan@master.technology

Fond memories, and onto new adventures....

For those who may or may not know me, I was one of the very earliest NativeScript developers. Started the Facebook and Google groups NativeScript forums. Created some of the very first plugins, helped train a wide number of early NativeScript developers, wrote books, and have some of the most widely used plugins in the entire eco-system. I also run a whole slew of different NativeScript related sites like PNR & SearchCode all under the Master Technology brand. Sufficed to say, I have been a advocate and cornerstone of NativeScript eco-system since it first started.

I also co-founded the nStudio company several years back with a couple other co-owners to focus solely on NativeScript work, and leave Master Technology to do everything else I do (i.e. servers, security, desktop, etc) . nStudio became the largest NativeScript development houses. Then awesome fortune came our way and we were able to take ownership of NativeScript. Finally over the last several months, nStudio was able to join and transfer NativeScript to the OpenJS Foundation (the foundation that supports projects like NodeJs, webpack, electron). So it now has a awesome open source home and foundation to support it for the foreseeable future.

However, unfortunately, during this season of time we had some large disagreements in nStudio leadership, on a myriad of issues. Do to some of these disagreements, I was abruptly terminated from the NativeScript TSC (a couple months back) and finally I officially left nStudio this week. So my work as an NativeScript Core/TSC member ended. I might still push a PR here and there for any client issues I run into, but that is probably the extent of it.

NativeScript...

Before the fallout, I had several ideas for NativeScript that I really wanted to pursue, and never could get any internal nStudio support. Since I am now 100% funded again by my clients work. I'm curious to know if anyone in the eco-system is interested in helping fund any of the following, if we have enough interest I'm willing to pursue any/all of them. I have the experience to make them work.

  • More NativeScript targets:
    • Web (A web front end, so you can use your NS skills and create web sites or apps that run inside of electron/tauri)
    • Desktop (actual native desktop front end, not using html)
    • Sailfish
    • PureOS
  • NativeScript build servers (i.e. easy ability to build everything from the cloud)
  • NativeScript front end, basically like the old SideKick, with lots of helpful tooling.
  • Compiled NativeScript (ios & android), your JS compiled to 100% native code.

Of course you can still hire me for any other NativeScript work you might have, if you have no interest in any of the above ideas.

New Adventures

Interestingly enough towards the end of this period of time, shortly after I finally decided to leave nStudio. Another technology stack was opened up basically exclusively for me to use externally. It is not a stack directly for mobile development, but a stack for rapid application database development. Virtually all applications use a database for the data, this takes the concept to the next logical leap. I've been doing database development for 30 years, and this technology stack excites me. You might compare it to Clarion, Filemaker or even Access (but way better). Designed from the ground up to have per field/row/screen security & auditing, mobile first, charts, reporting, etc. If you company needs any type of desktop/mobile application built let me know, this stack allows us to build it a lot faster meaning we can save you a lot in development costs. It doesn't matter if what you need is as simple as a contact database to something as complex as something that can fully run every part of your company. It scales and allows tying of different data sources very seamlessly.

In addition, if you have existing Access databases you want to convert to be modernized and intranet facing. I'm already pursuing working on a Access DB conversion to allow your app to hopefully seamlessly transition into this platform with little or no changes. I'm not opposed to writing converters from other platforms also, feel free to hit me up if you have some internal company apps you want modernized.

NativeScript 8 Released

NS 8.0

Been a while since I posted; but I figured I need to get a post out on this one. There was a lot of cool things that went into NS 8. The best item is that overall your code in NS 7 should work as-is in NS 8.

There are a couple minor exceptions.

1. If you are using <strong>Tabs</strong> or <strong>BottomNavigation</strong> you will want to install the

As we have depreciated and removed them from NS 8 because the community version are a much better versions and it eliminates conflicts between the cocoapod we were including by default and the cocoapod that the ui-material group of components is using.

2. In NativeScript prior to NS 8 when using Alpha, we were using #AARRGGBB for colors, we have finally become consistent to the web and now colors are #RRGGBBAA, so any CSS has to be adjusted to be in the new format.

New major features:

  • Webpack 5 support, which is considerably faster, with very simple and easily extended configurations.
  • First class a11y support!
  • New RootLayout (This is very cool!)
  • Apple m1 support
  • CSS Box & Text Shadow support
  • New ns migrate command
  • @nativescript/debug-ios - Cool run time debugging for iOS
  • @nativescript/apple-pay - Apple Pay Support
  • @nativescript/google-pay - Google Pay support
  • All New Website and new Docs!

Awesome NativeScript

Sometimes I REALLY love NativeScript.

So I have a really hard time tracking my time. Tested multiple time tracking apps over the years and still have many issues with all of them. Always been a real pita for me. So about a year ago I wrote a very simple NS time tracking app which works pretty well for me when I remembered to use it. Meh, problem is I really hate time tracking…

My son, being the smart one and not as picky, found a fairly nifty time tracking app on Android that he liked and he showed me that when you unlocked the phone it would popup immediately. I'm like that is a awesome feature, makes it easy to make sure you don't forget to switch tasks; unlock and click on the new task.

So a couple searches later I added the ability to my own NS timer app. So now, unlocking my phone, the app immediately goes into the foreground and lets me switch the timer task if need be…

Of course I could stop their, but NOOOOO, not me…. I'm out to make this be very functional, so I will actually use it with much better consistency…

So, another thing I kept thinking about over the last year was the ability to control it with voice commands. However, I have always been very privacy focused and REALLY REALLY hated using remote servers for almost anything. Let alone sending Google (or Apple) any voice recognition data. So it has been a non-starter for a while for me…

A couple searches later this last weekend, and I found a awesome open source offline voice recognition system. Works on both Android & iOS (I only integrated the Android side, as that is all I need for my time tracking).

So now I can unlock my device (which of course immediately triggers my app to the foreground) and SAY: "Timer X". The app then searches all the timers for anything that matches, if it matches; it switches to that timer and then uses (also offline) Text to Speech to say: "Starting timer X", so I have a confirmation without having to look at the screen…

All in a simple NativeScript application… If I had to do this all in many other frameworks, this would have been a many day project -- NativeScript was only a couple hours to get it all working...

NativeScript, Master Technology, ProPlugins, and nStudio.

So since this question has come up multiple times; I decided to write a brief history of my involvement with NativeScript, Master Technology, ProPlugins, LLC and nStudio, LLC.

So this story begins a little over 5 years ago; I had been doing some Cordova/Phonegap development on a simple application for my wife; and its performance ended up being sub-par, ran into screen sizing issues, and a whole myriad of the common standard issues you run into with programming for a webview. Most these hybrid issues are much better now. At that point -- frustration was enough to make me decide to see if their was anything better.

I downloaded a huge number of platforms, React Native, Titanium, Fuse, Xamarin, you name it; I found a link to it I downloaded it and tried it out. After spending multiple days installing and testing things, I finally decided to using React Native -- it was the best of the bunch. A few days later I saw a article on a news site; saying checkout something called NativeScript. I figured, might as well -- I wasn't totally sold on React-Native and I hadn't started my project.

So I downloaded NativeScript v0.90 or v0.91, which was the first official "open" release in early March of 2015. I totally fell in love with it. It has a good template syntax, data binding and best of all full easy access to the entire native platform all using JavaScript. It really was the "perfect" mobile development system.


Now as to Master Technology, it was started a long long time ago, in a galaxy far far away... Almost 30 years now... So basically, in a nutshell this was the company I did all of my contracting work under. As such, when I started doing NativeScript work I continued to do all of my work under it. This is why you see a large number of plugins and NativeScript related sites with the Master Technology logo. One of the first, https://plugins.nativescript.rocks, started as a simple MD file on github...

However, that soon became unworkable when the community started adding multiple new plugins a week. So I created the first version of https://plugins.nativescript.rocks... From there images, searchcode, compatibility chart and many other community resources have been added...


After a couple years of working in the NativeScript community, I realized that as a sole contractor it was very hard to handle larger jobs by myself. In early 2017, I had the brilliant idea to start a company that would be more like a law firm, with senior and junior partners but geared for developers. I enlisted my co-owners Brad Martin, and Nathan Walker and we created a brand new company called nStudio in early 2017. From there we grew a bit, to the point we even added a new co-owner in 2019, Dave Coffin. We continued to grow adding several partners known highly in the community to our team like: Igor Randjelovic (NativeScript-Vue), Osei Fortune (author of many awesome plugins), Alex Ziskind (the tutorial master of NativeScripting.com). In addition we have developed strong ties with many other companies in the greater developer eco-system.

When any new NativeScript clients would contact me, I move them to nStudio. Any other clients (Servers, PHP, Clarion, Node, etc) stayed on Master Technology as that company is now more oriented to server side stuff, and nStudio was for all the mobile development.

One strange thing about having two companies is dealing with IP, so any IP that I had developed at Master Technology, remained with Master Technology. You will still see Master Technology on a LOT of sites and plugins in the NativeScript eco-system even though Master Technology only does a small amount of work in the NativeScript eco-system now.


In early 2019; as still one of the major open source plugin NativeScript developers; I realized that NativeScript community needed some way to fund plugin maintenance. We were seeing a great number of plugins that were not maintained and no longer working. The maintenance time on my own plugins, that were free to the community, became far too excessive for me to be able to keep them to a standard I'd be happy to have my name on, and still be able to feed my family. I got together with several other large plugin developers and we started ProPlugins, LLC. This has helped at least with a chunk of the plugins under our control; and so ProPlugins, was founded and is owned by Master Technology.


Now comes the most interesting turn of events in this entire story, one that I would NEVER have expected in a million years.

Because of NativeScript, I helped found two additional successful companies. Which just by itself is totally awesome! However, now nStudio, LLC has been able to purchase NativeScript and its assets. We now have control over not only our companies future, but the framework that was directly responsible for spawning nStudio, LLC.

As such, you should now see my name (and the other partners from nStudio, LLC) on the all the new pull request approvals and reviews for NativeScript. I do want to sincerely thank all the developers over the last 5 years who actually built NativeScript, and if any of you want to continue to work on the framework, please feel free to drop us a line at team (@) nativescript org.

(c) Adam Carter, https://www.flickr.com/photos/44811338@N05/7505286308

Optimization Gotcha's for for/i and forEach

So I mentioned something on my interview with Alex of NativeScripting.com that he did with me. And someone asked about this in the comments, so I decided to create a blog article on this specific optimization tip.

I am going to code this to a browser rather than in NativeScript because well JS in a browser is just plain easier to show the memory issues because you can plop the code in to a new browser tab and step through the code instantly. 🙂

&lt;html>
&lt;body>&lt;div id="stacklayout">&lt;/div>&lt;/body>
&lt;script type="application/javascript">

// Pretend Color class to be similar to NativeScript
class Color {
    constructor(val) { this._color = val; }
    toString() { return this._color; }
}

const <strong><em>colors </em></strong>= ["#ff0000", "#00ff00", "#0000ff"];
for (let i=0;i&lt;<strong><em>colors</em></strong>.length;i++) {
    const labels=["Wow","Awesome","Interview", "Alex", "Created!"];
    for (let j=0;j&lt;labels.length;j++) {
        const clr = new Color(<strong><em>colors</em></strong>[i]);
        const txt = <strong><em>document</em></strong>.createElement("div");
        txt.innerText = labels[j];
        txt.style.backgroundColor = clr.toString();
        const parent = <strong><em>document</em></strong>.getElementById("stacklayout");
        parent.appendChild(txt);
    }
}
&lt;/script>
&lt;/html>

And you should see something like this:

We are repeating the labels for each of the primary colors...

Or you might be used to doing something like this instead:

&lt;html>
&lt;body>&lt;div id="stacklayout">&lt;/div>&lt;/body>
&lt;script type="application/javascript">

class Color {
  constructor(val) { this._color = val; }
  toString() { return this._color; }
}

["#ff0000", "#00ff00", "#0000ff"].forEach((clr) => {
  ["Wow","Awesome","Interview", "Alex", "Created!"].forEach((word) => {
     const txtColor = new Color(clr);
     const txt = <strong><em>document</em></strong>.createElement("div");
     txt.innerText = word;
     txt.style.backgroundColor = txtColor.toString();
     const parent = <strong><em>document</em></strong>.getElementById("stacklayout");
     parent.appendChild(txt);
  });
});

&lt;/script>
&lt;/html>

Both have several issues, however the second one can be vastly worse than the first one depending on how many iterations. So lets walk through the issues.

So the Color class is fine, we are using it to show creating objects... So just ignore it for now.

const <strong><em>colors </em></strong>= ["#ff0000", "#00ff00", "#0000ff"];
for (let i=0;i&lt;<strong><em>colors</em></strong>.length;i++) {

These lines are fine, we allocated colors, then looped through them. So far so good. Lets proceed, what about:

const labels=["Wow","Awesome","Interview", "Alex", "Created!"];

Well here is the first issue; Fortunately for us, the v8 JS engine actually pre-allocates the 5 different string "Wow" through "Created!" when it parses the JavaScript however, each loop through it does create a brand new Labels array and then links those strings into it. So in this case it is small overhead; however in the 3 loops that still is 2 more sets of allocations and all new GC enties that have to be cleaned up after the loop is completed. If you were to put this single line of code outside the loop; your code runs the same, but no less memory usage and less processing.

 const clr = new Color(<strong><em>colors</em></strong>[i]);

What about this line, well in this case all 15 times it creates a brand new Color object. You can easily make this only be ran 3 times just by moving it outside the inner for (j) loop into the for (i) loop. In this example the Color class is very light weight. But many classes you create inside loops will be very heavy with lots of allocations going on when you allocate the class. So pay attention, 3 allocations vs 15 allocations, all by putting the line in the wrong spot...

Continuing on, most the rest of the lines has to be inside the loop; but I tossed another item into the loop, that wasn't needed... This line is very easy to accidentally end up in the loop because you needed it at that point.

     const parent = <strong><em>document</em></strong>.getElementById("stacklayout");

Yep, this has to do an expensive lookup in the dom to find this element, it never changes. It also has to allocate it to that "parent" variable 15 times. If you dropped it before/outside of both loops, you would have a single lookup and allocation...

---

Finally lets look at the last example; it suffers from the same issues. However, this one I used a Array.forEach rather than the simple for (i) loop. Why do I say it can be worse then? Well in small numbers, the difference is actually pretty tiny. The extra amount of memory it uses over a for (i) loop is also reasonable. But in larger loops (especially loops inside of loops inside of loops); the difference can end up being exponentially larger.

Your creating and calling functions, and all those functions now has added scopes and the engine has to setup all the callstacks for each and every iteration, additional error checking and just plain running a lot more code behind the scenes. So what is a simple for (i) loop in the first example, now became 15 EXTRA functions calls with all the extra overhead of cpu and memory that entails. Again in small chunks they are perfectly fine, but if you are wanting performance, every ms and gc adds up and sometimes they can add up very quickly when dealing with the Array helper functions that use callbacks...

As a better way to phrase this; imagine you have a for (i) loop that takes 5ms and a forEach loop takes 25ms to finish. Both are still dang fast, hard to even benchmark. But now you embed it in another forEach that also by itself takes 25ms. 25ms * 25ms = 625ms. More than half of a second. But, if you were to switch this to a for (i) loop each of them is 5ms. So, 5ms * 5ms = 25ms. Both are exponentially larger, but 25ms vs 625ms and the difference starts becoming much clearer. Now add a third loop; 5ms*5ms*5ms = 125ms. 25ms*25ms*25ms=15,625ms (or > 15 seconds!) In small chunks the time and memory used from a forEach is minuscule. But depending on how many times it is called; it can add up very quickly to be a major difference.

Please note this goes for all the nice Array helper functions, .map, .reduce, .filter, etc. Everyone of them that uses a callback, has somewhere between 2 times and 50 times as much overhead as a simple for (i) loop. Remember, despite this overhead; these functions are extremely fast. So don't be afraid to use them, but be more wary of using them in deeply nested code that can easily be called in loops when the datasets they are working against are also large.

As many items that you can actually move outside of your loop, the better off you are. This Includes any expensive calculations! You might be able to do 99% of the expensive calculation outside of the loop; and then finish off the last part of the calculation inside the loop...

I hope this answers the question about loops and performance. Every loop is a golden opportunity to greatly enhance your app,

Oculus and their horrible support policy, a tale of woe!

I've had a lot of bad experiences with companies over the years; but this one takes the cake (The cake is a lie!) for me, in how not to treat a customer (let alone a developer in your ecosystem).

For those who don't know who I am, I have written somewhere around a 100 plugins both open source and many for different clients. Primarily for the cross platform framework NativeScript. So I have plugins from making Unity run and communicate with NativeScript to even making ColdFusion be able to drive an NativeScript app. On the Hardware side, everything from mobile printers, credit card readers and just a week or so ago the cool SocketMobile barcode scanner. All of them work great with NativeScript. So in a nutshell, I play with lots of hardware and software and write a lot of code in a lot of industries, including optimizing business practices...

As such I have a number of phones, one of them is the Samsung Galaxy, which supports the GearVR, so as such I have been a Oculus developer for multiple years. I've been working on a couple ideas; and even created a couple concept Unreal apps on my GearVR devices.

So as many of you might not be aware of getting a Oculus Quest is a an experience in frustration, they are sold out everywhere (unless you want to be scalped and pay twice as much).

So, I thought I scored last week. I read an article that Oculus finally had some stock again. Connected to their site; found that they were already out of stock on the 64 gig version, so decided because I have no idea when they will be in stock again, I'd spring for the larger more expensive version... So placed my order, had an order number, everything seemed to be great...

Then the pain begins....

Two days later around midnight, I get this message:

I'm like what the HELL, I've been waiting forever and they just CANCELLED my order, no contact, no nothing; just lets cancel it... (Serious question, Oculus, why don't you put in this message why it was cancelled, since the person cancelling it knows.)

Make it stop...

Ugh, of course, I went immediate to their site and guess what:

Yep, all sold out again.. Shoot, well maybe they can undo the cancellation; and we can figure out why they would cancel a order and fix whatever mistake was made. Clicked the support link and of course it brings you to the generic support site (Serious question, Why doesn't the email link put you on the proper url?). Spend a few minutes finding the right form to fill out and send them a question asking the simple easy question of "Can you tell me why my order XXX was cancelled?"

Lets apply the thumb screws...

The automated system sent and email response and stated, it could be up to two business days; but they did respond in one! Very late the next day I get a message from CS saying thanks for contacting us... But man my heart dropped.

  1. do not create any new orders (Not than I can, its out of stock already!)
  2. WE ARE UNABLE TO RE-INSTATE IT.

At this point, I realize, I am screwed, I can't reorder even if I wanted to; and that they won't re-instate the order. They officially jumped from well this experience so far just sucks, wasting my time... to Oculus customer service/order system really sucks. WHY THE HELL DO YOU CANCEL A ORDER, IF YOU CAN'T RE-INSTATE IT? Seriously bad customer interaction at this point... If their is a order issue, and you can't re-instate it, then suspend/pause the order and deal with the issue, don't just CANCEL the order leaving the customer with NO recourse...

Electric shock therapy is best...

And to top it off; lets see why the cancelled it (this message came the next day)

So basically:

- If I'm in the military and serving anywhere outside of the United States and decide to buy a US model, I can't...
- If I'm a expat living anywhere else in the world; apparently we can't either.
- If I'm uncertain where I'm going to be in the near future (like was in college, now at home), and decide that I want to make sure all my mail is handled and sent to where I am currently, no matter when this ships and arrives... I can't...
- Worried about spouse abuse and sending all mail through a third party to eliminate the ability for them to track me via my mail. I can't....

Really, Oculus! You f**kin cancelled my order because I ordered a SINGLE device, am a known developer in your developer program for several years and wanted to ship it to a place that can re-ship it to where I'm actually located right now. Your going to cancel the order, leaving me no recourse...

Maybe Bleach will work...

Then state I can order it this way from any of your support partners, seriously? You say we can't do this; but you can get around us, this way. Here's a link to make it much simpler!

Honestly, management needs to make some heads roll, that has to be the stupidest policy I've ever heard of...

But for those who typically use a Reshipper/concierge for your mail; you need to use a friend (which I would have done had I known that up front, now it is too late!)...

GitLab Verified Email account issue

I use a privately hosting Gitlab's instance for a bazillion projects; and have a lot of users from around the world. Unfortunately, I have ran into a long standing bug that has never been fixed in many years. It only crops up occasionally now, but it is still a major pain for everyone involved. Many, many reports and many issues in the gitlabs issue database on this issue.

Basically, the end user never sees a "verify this email" email. And without that email; they can not login. Catch-22. In addition the "Confirm" button in the administrator account also fails to work in this situation, so neither the user nor the admin can do anything to fix it. Which then basically means I have a dead account that no one can do anything with. Until today.

These notes are so that I can easily fix it in the future.

First thing you do is go to the https://yourinstance/users/confirmation/new and create a new verification email. This way the token you will get later is now valid (as tokens expire after a number of hours).

Next thing is login to the Docker instance; if you aren't running docker; then don't worry about this step:

docker exec -it gitlab bash

Then once inside the docker bash shell; you launch the gitlab's interactive shell -- technically you can just the gitlab-rails runner "command; command; command" but the docker instance I run doesn't seem to have it present -- so we will launch the full gitlab rails console.

bundle exec rails console -e production

Once in this the rails console; we search for the user:

u = User.find_by_username('USERNAME')
(or u = User.find_by_any_email("emailaddress"))

Once we have the u variable; we can do a huge number of items on it; but what we really need to do is output the current confirmation token.

u.confirmation_token

And it will print a token that looks like this: "s2vzxVeWYhkzzDsBN8fC"

Type, exit, to exit the gitlab console. Then exit again to exit the docker instance. Go to your browser; and then use a modified version of this url:

https://yourinstance/users/confirmation?confirmation_token=<strong>s2vzxVeWYhkzzDsBN8fC</strong>

And let your browser go to it; and if you did everything correctly; you should see gitlab say it verified your email address and that you can now login.

Please note their are a lot of features/functions/data off the user "u" variable (over 3000); however, after spending over an hour trying confirmation, verification and other related features -- everything "looked" correct on the user record; but in the web admin page still showed the account was unverified. I just realized their might be some sort of user save record which then would have persisted my changes; but I didn't think about it until I was writing this blog.

However, since I could not get any of the other u.* functions to fix the record, I finally figured that the simplest way to fix this was just to have gitlab run its OWN verification code and so all I need to do is provide the token it generated myself to its verification page to make gitlab believe the end user got the email and now verified it.

VMWare - Shrinking disk size Macintosh/Linux

If you have a Macintosh or Linux based image; the tooling to shrink the hard drives is basically broken in the Gui (and/or, don't work). So to shrink these types of containers; the easiest method is to force the entire empty area to be Zero's, then defragment, and finally shrink all ..

First thing we need to do is Zero all blocks that are no longer used. Please note this will make your container grow to the maximum size your container is allowed to grow; so you might need a lot of disk space!

cat /dev/zero > zerofile; rm zerofile

Next you need to shutdown the client, so on linux it might be shutdown now -h or clicking a couple buttons to shutdown cleanly. After the VM has been shutdown you need to run the following commands from the command line.

vmware-vdiskmanager -d <diskimage.vmdk>

This command will defragment the image; moving all the data to the front of the image and all the empty blocks to the end. You obviously need to point the &lt;diskimage.vmdk> at wherever the vmdk you are working with is located, and if the vmware-vdiskmanager is not on your path; you will have to manually call it from wherever it resides. Finally you need to call

vmware-vdiskmanager -k <diskimage.vmdk>

As this will shrink the image; and if you are lucky, your 280 gig image will shrink to 80 gigs.