donderdag 25 april 2019

Node.js caching of required scripts

When I started exploring node.js I was wondering how the require() thing worked and how it would cache the scripts I required.

Would it return a new instance every time, basically functioning as a factory? Or would it return the same instance over and over?

So I did some reading up and found out that node.js caches it and returns the cached object/instance. Good, but then I read that it uses the filename for cache key, but it wasn't clear if the absolute file name is used as cache key or the relative file name.

So I did a test.

./index.js:

1
2
3
4
5
var test = require('./modules/test/test2.js');
console.log('expect world', test.hello);
test.hello = "dirt";
require('./modules/testbed.js');
console.log('expect universe', test.hello);

./modules/test/test2.js

1
2
3
module.exports = {
    hello: 'world'
}


./modules/testbed.js

1
2
3
var test2 = require('./test/test2.js');
console.log('expect dirt', test.hello);
test2.hello = "universe";

And then the output becomes

index.js:2   expect world world
testbed.js:2 expect dirt dirt
index.js:5   expect universe universe

Giving me confidence that it doesn't matter from which file or directory you require the module, as long as the filename is the same.

The only caveat is that if you use a case insensitive file system, things will break down if you're not consequent in your filename strings.

For example: if you change testbed.js to contain this:

1
2
3
var test2 = require('./test/Test2.js');// Note the uppercase T
console.log('expect dirt', test2.hello);
test2.hello = "universe";

The output will become:

index.js:2   expect world world
testbed.js:2 expect dirt world
index.js:5   expect universe dirt

because test.js and Test.js are different strings. So make sure to either always use consistent case for filenames.

dinsdag 26 februari 2019

How to recreate encryption by MCRYPT_RIJNDAEL_256 in PHP 7.2 and higher.

So with PHP7.2 around the edge and the deprecation of mcrypt, sometimes you still need to be able to encrypt with MCRYPT_RIJNDAEL_256

So I got around this question on stackoverflow: https://stackoverflow.com/questions/54887285/exact-alternate-to-mcrypt-encrypt-in-php-7-2

Researching this issue I found that openssl when it comes to MCRYPT_RIJNDAEL_256 says "Screw you, update your methods". So, the OP already had found a library which could do what he wanted it to do, but somehow the OP was using an outdated version.

This sent me on an experimenting spree which led to the code in the answer, a method to be able to encrypt and decrypt with the MCRYPT_RIJNDAEL_256  method as given in that answer.

To get this answer to work you'll need to incorporate the library phpseclib and install it in your code path.

Then you can use this code to translate the encrypted strings back and forth as you please.
Happy coding!

set_include_path(get_include_path() . PATH_SEPARATOR . 'phpseclib');
include('Crypt/Rijndael.php');
include('Crypt/Random.php');
use phpseclib\Crypt\Rijndael as Crypt_Rijndael;
function encryptRJ256($key,$iv,$text)
{
    $cipher = new Crypt_Rijndael('cbc'); 
    $cipher->setBlockLength(256);
    // keys are null-padded to the closest valid size
    // longer than the longest key and it's truncated
    $cipher->setKeyLength(256);
    $cipher->setKey($key);
    // the IV defaults to all-NULLs if not explicitly defined
    $cipher->setIV($iv);
    $cipher->disablePadding();
    $length = strlen($text);
    $pad = 32 - ($length % 32);
    $text = str_pad($text, $length + $pad, chr(0));
    return base64_encode($cipher->encrypt($text));
}
function decryptRJ256($key,$iv,$text)
{
    $cipher = new Crypt_Rijndael('cbc'); // could use CRYPT_RIJNDAEL_MODE_CBC
    $cipher->setBlockLength(256);
    // keys are null-padded to the closest valid size
    // longer than the longest key and it's truncated
    $cipher->setKeyLength(256);
    $cipher->setKey($key);
    // the IV defaults to all-NULLs if not explicitly defined
    $cipher->setIV($iv);
    $cipher->disablePadding();
    return $cipher->decrypt(base64_decode($text)); 
}   

vrijdag 17 augustus 2018

Trying to install Gogs on Ubuntu 16.04 - A journey

Trying to install Gogs on an Ubuntu server is not as easy as it seems if all the conditions are not peacy perfect. I wen through the hoops, and I documented them here hoping that you will find it easier to jump through them instead of having to find several parts of answers scattered around the internet like I had.

So my current stats: Ubuntu 16.04, MariaDB 10.0, Nginx something

First off:

Upgrading your Maria db.

How to do that is copied from https://websiteforstudents.com/upgrading-mariadb-from-10-0-to-10-1-to-10-2-on-ubuntu-16-04-17-10/ but copied here in case it goes down/vanishes etc.. like stuff on the internet likes to do, but do visit that site, it has tons of useful information.

This is assuming you have a mariadb installation already present at a lower version than 10.2, if you don't have it yet just skip to the 10.2 step.

First off log onto your database.

sudo mysql -u root -p Run the following command
mysql> SET GLOBAL innodb_fast_shutdown = 0; Make a backup of your databases if needed to be then stop the mysql service

Ubuntu 16.04sudo systemctl stop mysql.service On Ubuntu 17.10 and up, run the command below: sudo systemctl stop mariadb.service
Now remove the Maria DB server from your system.sudo apt remove mariadb-server In stall the software properties and the keys.
sudo apt-get install software-properties-common
sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
Now we do the upgrade shuffle. I read in several places it was best to do the upgrade in steps to keep database integrity, so first upgrading to 10.1 and then then 10.2. If you like to live dangerously upgrade right away to 10.2.
sudo sh -c "echo 'deb [arch=amd64,i386] https://mirrors.evowise.com/mariadb/repo/10.1/ubuntu '$(lsb_release -cs)' main' > /etc/apt/sources.list.d/MariaDB-10.1.list"
sudo apt-get update
sudo apt-get install mariadb-server
Now to upgrade your databases to 10.1
sudo mysql_upgrade
If you happen to get the below error message:
ERROR 1524 (HY000): Plugin 'unix_socket' is not loaded
FATAL ERROR: Upgrade failed
You will need to follow the steps as laid out on https://websiteforstudents.com/fix-mariadb-plugin-unix_socket-is-not-loaded-error-on-ubuntu-17-04-17-10/

sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf Then add the line below right below the [mysqld] marker.plugin-load-add = auth_socket.so After adding the line into the file, run the commands below to restart Maria DB sudo systemctl restart mariadb.service
Then try to run the upgrade command again
sudo mysql_upgrade
When the upgrade command has completed we are going to do the tricks again to upgrade to 10.2sudo systemctl stop mysql.service sudo apt remove mariadb-server sudo sh -c "echo 'deb [arch=amd64,i386] https://mirrors.evowise.com/mariadb/repo/10.2/ubuntu '$(lsb_release -cs)' main' > /etc/apt/sources.list.d/MariaDB-10.2.list" sudo apt-get update sudo apt-get install mariadb-server mariadb-client sudo systemctl restart mariadb.service sudo mysql_upgrade And now we have a Maria DB upgrade complete.
We needed this upgrade because otherwise there are going to be problems with database keys being too big and you getting an error like Error 1071: Specified key was too long; max key length is 767 bytes or like Error 1071: Specified key was too long; max key length is 1000 bytesBut when we're at Mariadb 10.2 we're good to go, that error doesn't happen.

Now to install Gogs. 

I chose to install via packages, you can decide another method but then you're on your own unfortunately.

 According to the installation page https://gogs.io/docs/installation/install_from_packages they supply their packages via packager.io which leads us to this wonderful overview https://packager.io/gh/pkgr/gogs

There I clicked on the Ubuntu 16.04 icon of the most recent package to get to the installation instructions
https://packager.io/gh/pkgr/gogs/builds/687/install/ubuntu-16.04


wget -qO- https://dl.packager.io/srv/pkgr/gogs/key | sudo apt-key add - sudo wget -O /etc/apt/sources.list.d/gogs.list \ https://dl.packager.io/srv/pkgr/gogs/pkgr/installer/ubuntu/16.04.repo sudo apt-get update sudo apt-get install gogsIf for some reason it doesn't run on the first try you'll might have to run this command first.apt-get install wget apt-transport-https We have Gogs now, we have an upgraded Maria DB, we already had an Nginx.
After this warm up let's try to party and actually start setting things up.

Setting up the database

We need a database set up for Gogs, so lets set up a user and database for it. mysql -uroot -p create database gogs; create user gogs; grant privileges on gogs.* to `gogs`@`localhost` identified by 'a_fancy_password_here'; exit
Being able to see Gogs

Now we need to have access to Gogs. Default Gogs will run it's configure server on port 6000. Default this will be blocked by Chrome and Firefox with ERR_UNSAFE_PORT.
We can't access Gogs yet to put in our database credentials. Unless you're fine working with internet explorer. That'll work with port 6000 just fine and dandy, or you wish to fiddle with your chrome settings to allow port 6000, but you'll have to remember to do that with every chrome you'll work with.

Up to nginx configuration: cd /etc/nginx/sites-available sudo nano gogs And insert there the following code(I chose port 8080 since it's whitelisted by chrome and I have other things running on 80, but do as you please): server { listen 8080; server_name your_server_name_here; location / { proxy_pass http://localhost:6000; } } Press CTRL + X to exit and answer yes on the question if you wish to save.
 Now we need to make a symlink to sites enabled sudo ln -s /etc/nginx/sites-available/gogs /etc/nginx/sites-enabled/gogs Now to restart Nginx to have our server up and running sudo service nginx restart Now browse to your website at http://your-domain:8080 and you should see all the configuration settings you can enter for Gogs.

If you can't see it or you get a connection refused, you might need to whitelist port 8080 in your firewall:

ufw allow 8080/tcp
And that's how it's made "easy" to set up Gogs :-)

donderdag 8 maart 2018

How to use html5 <template> with jQuery

So you have decided to go full html5 in your website. Congrats, welcome to 2018 where Internet Explorer is closer to death.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template -->

<table id="producttable">
  <thead>
    <tr>
      <td>UPC_Code</td>
      <td>Product_Name</td>
    </tr>
  </thead>
  <tbody>
    <!-- existing data could optionally be included here -->
  </tbody>
</table>

<template id="productrow">
  <tr>
    <td class="record"></td>
    <td></td>
  </tr>
</template> 


Now if you wish to use template, but don't wish to use the code that's shown on MDN because you are more comfortable with jquery, you only need this one sentence to get the template into a jQuery object you can manipulate and later append to your favorite node.

The full sample for createing, modifying and appending a node from a template.


1
2
3
4
$content = $(document.importNode($('template#productrow').prop('content'), true));
$content.find('td.record').text('foo');
$content.find('td:not(.record)').text('bar');
$('#producttable thead').append($content);

You can fiddle with it here: https://jsfiddle.net/Ld9421o1/

Now a little breakdown of what does what

This is the entire line needed to turn a template into a jquery object you can manipulate.

1
var $content = $(document.importNode($('template#productrow').prop('content'), true));
Below the breakdown of the individual components

This searches a <template> element with the id attribute with the value productrow.
Then it accesses the property 'content' on that object.

1
$('template#productrow').prop('content')
An alternative could be

1
2
$('template#productrow').get(0).content;
$('template#productrow')[0].content;
The document-fragment you have now is not attached to the window.document object. It's free floating without parents. This also means you can't append it to any node you have on your document.

This is why you call this code. What it does is clone the fragment you have supplied(that's what the true is for) setting window.document to the documents fragment parent, but it's still not attached to any DOM element you have in your body. It is as if you called $('selector').detach() on an element.
And then it returns the cloned node to you.
1
document.importNode(documentFragment, true)

Now we wrap the clone in jQuery so we have a nice manipulatable object we can change without changing the template around and because it's still detached from the DOM, these manipulations will happen really fast because there's no re-rendering of the page involved.

1
$(document.importNode(documentFragment, true))

donderdag 4 mei 2017

Alternative to touchpal emoji keyboard

So if you're a bit like me and you're on Android, you might like all the features and dodad's that Touchpal gives, but you absolutely hate the jackpot, the popup ads, the constant nagging bulbs on the sides etc...

Well, I found a solution for it, that doesn't involve shelling out 5 euro's per year in a subscription service to remove overly intrusive ads.
I mean for 5 euro's/dollars I would be willing to buy it, not to a subscription service. my treshold for subscription would be 1 dollar/euro per year to consider it.

Anyhows, I've tried out several other keyboards, but none of them had the nifty features touchpal has that makes it easy to code on android(I can recommend buying AIDE, it's great, terrific, the best there is)

But lately Touchpal started having big banner ads ABOVE the keyboard. That totally turns me off, even hindered input by making the keyboard vanish mid sentence because of something the ad did.
So I shopped around for alternatives, but none of them came with the perfect package deal Touchpal has. If Touchpal had a buy ad free version i'd buy it even if it cost 15 euros, but sadly it only has the subscription service.

To remove the annoying ads(Every 3rd keyboard popup had big banner ads of an inch high) and allowing me to code on, or shitpost on imgur I used no root firewall https://play.google.com/store/apps/details?id=app.greyshirts.firewall&hl=nl going in the firewall to apps and double tapping the checkboxes by Touchpal so that the red crosses appear.

And voila, no more banners, no more ads. I can type happy again.


donderdag 28 mei 2015

Simple jQuery plugin to make checkbox values readable/settable by $(checkbox).val() isnstead of attr

If you put this little script in your document after jQuery has loaded you can simply read the values of a checkbox with $('#checkboxid').val() and set it with val.

 I added comments to explain what line of code does what.

I hope this makes your life a little bit easier.


 To have a live example to fiddle with, check out http://jsfiddle.net/e3q8cmum/



if(typeof window['$'] !== 'undefined' || typeof window['jQuery'] !== 'undefined') {
 jQuery(function(){
  // Saving the old instance so this can do stuff when we don't need it.
  jQuery.fn.ZAGREUSoldoldoldVal = jQuery.fn.val;
  // Making our own value function!
  jQuery.fn.val = function(value){
   // Check if it's  a checkbox. If so, do our magic!
   if(typeof value !== 'undefined' && (this[0] instanceof HTMLInputElement && this[0].getAttribute('type') == 'checkbox')) {
    // Saving our instance for scoping
    var that = this;
    // Generic setvalue function to prevent code duplication.
    var setval = function(bool) {
     var oldbool = that[0].checked;
     that[0].checked = bool;
     // Remove this if you don't want a trigger whent he value changes.
     if(oldbool !== bool) {
      that.trigger('change');
     }
    }
    // All possible values that can be entered. False means unchecked, true means checked.
    // Modify as needed.
    switch(value) {
     case 'j' : setval(true);break;
     case 'y' : setval(true); break;
     case 'n' : setval(false); break;
     case true : setval(true);break;
     case false : setval(false);break;
     case 1 : setval(true);break;
     case 0 : setval(false);break;
     case 'checked' : setval(true);break;
     case '' : setval(false);break;
    } 
   }
   // We didn't get an argument, so we assume we want to read the data
   else if(typeof value === 'undefined' && (this[0] instanceof HTMLInputElement && this[0].getAttribute('type') == 'checkbox')) {
    return this[0].checked// ? 'y' : 'n';//<-- optional string return... depends on what you want
   }
   else{
    // Default handling of the val function.
    return typeof value !== 'undefined' ? jQuery(this).ZAGREUSoldoldoldVal(value) : jQuery(this).ZAGREUSoldoldoldVal();
   }
  }; 
 });
}