Category: UI5

  • Encrypting and Decrypting Data in SAP UI5 using aes.js

    Introduction

    In this article, we will go through the encryption and decryption of any data in SAP UI5 using Aes.js

    What is Encryption

    Encryption is a methodology to convert data that can be hacked into another unreadable format. In this way, only the right user can convert the data back into readable format.

    How to Encrypt and Decrypt data using Aes.js

    To encrypt and decrypt data using Aes.js, you can use two way:

    1. Implementing Aes.js using NodeJs
    2. Implementing Aes.js using cdn

    To implement Aes.js encryption and decryption in SAP UI5, we use CDN and add it to the index.html file.

    Encrypting and Decrypting Data in SAP UI5 using aes.js

    Encrypting and Decrypting Data in SAP UI5 using aes

    Index.html

    Either Add CDN in the index.html file as shown below:

    <script type="text/javascript" src="https://cdn.rawgit.com/ricmoo/aes-js/e27b99df/index.js"></script>
    

    or Download the content from here https://cdn.jsdelivr.net/gh/ricmoo/aes-js@e27b99df/index.js

    and add it in a new file called as aesjs.js inside a folder js within webapp.

    /**
     * @Author: Rudramani Pandey
     * Purpose: External API for Encryption and Decryption
     * Modified: 16.04.2023
     */
    "use strict";
    
    (function (root) {
    
        function checkInt(value) {
            return (parseInt(value) === value);
        }
    
        function checkInts(arrayish) {
            if (!checkInt(arrayish.length)) {
                return false;
            }
    
            for (var i = 0; i < arrayish.length; i++) {
                if (!checkInt(arrayish[i]) || arrayish[i] < 0 || arrayish[i] > 255) {
                    return false;
                }
            }
    
            return true;
        }
    
        function coerceArray(arg, copy) {
    
            // ArrayBuffer view
            if (arg.buffer && ArrayBuffer.isView(arg) && arg.name === 'Uint8Array') {
    
                if (copy) {
                    if (arg.slice) {
                        arg = arg.slice();
                    } else {
                        arg = Array.prototype.slice.call(arg);
                    }
                }
    
                return arg;
            }
    
            // It's an array; check it is a valid representation of a byte
            if (Array.isArray(arg)) {
                if (!checkInts(arg)) {
                    throw new Error('Array contains invalid value: ' + arg);
                }
    
                return new Uint8Array(arg);
            }
    
            // Something else, but behaves like an array (maybe a Buffer? Arguments?)
            if (checkInt(arg.length) && checkInts(arg)) {
                return new Uint8Array(arg);
            }
    
            throw new Error('unsupported array-like object');
        }
    
        function createArray(length) {
            return new Uint8Array(length);
        }
    
        function copyArray(sourceArray, targetArray, targetStart, sourceStart, sourceEnd) {
            if (sourceStart != null || sourceEnd != null) {
                if (sourceArray.slice) {
                    sourceArray = sourceArray.slice(sourceStart, sourceEnd);
                } else {
                    sourceArray = Array.prototype.slice.call(sourceArray, sourceStart, sourceEnd);
                }
            }
            targetArray.set(sourceArray, targetStart);
        }
    
        var convertUtf8 = (function () {
            function toBytes(text) {
                var result = [],
                    i = 0;
                text = encodeURI(text);
                while (i < text.length) {
                    var c = text.charCodeAt(i++);
    
                    // if it is a % sign, encode the following 2 bytes as a hex value
                    if (c === 37) {
                        result.push(parseInt(text.substr(i, 2), 16))
                        i += 2;
    
                        // otherwise, just the actual byte
                    } else {
                        result.push(c)
                    }
                }
    
                return coerceArray(result);
            }
    
            function fromBytes(bytes) {
                var result = [],
                    i = 0;
    
                while (i < bytes.length) {
                    var c = bytes[i];
    
                    if (c < 128) {
                        result.push(String.fromCharCode(c));
                        i++;
                    } else if (c > 191 && c < 224) {
                        result.push(String.fromCharCode(((c & 0x1f) << 6) | (bytes[i + 1] & 0x3f)));
                        i += 2;
                    } else {
                        result.push(String.fromCharCode(((c & 0x0f) << 12) | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f)));
                        i += 3;
                    }
                }
    
                return result.join('');
            }
    
            return {
                toBytes: toBytes,
                fromBytes: fromBytes,
            }
        })();
    
        var convertHex = (function () {
            function toBytes(text) {
                var result = [];
                for (var i = 0; i < text.length; i += 2) {
                    result.push(parseInt(text.substr(i, 2), 16));
                }
    
                return result;
            }
    
            // http://ixti.net/development/javascript/2011/11/11/base64-encodedecode-of-utf8-in-browser-with-js.html
            var Hex = '0123456789abcdef';
    
            function fromBytes(bytes) {
                var result = [];
                for (var i = 0; i < bytes.length; i++) {
                    var v = bytes[i];
                    result.push(Hex[(v & 0xf0) >> 4] + Hex[v & 0x0f]);
                }
                return result.join('');
            }
    
            return {
                toBytes: toBytes,
                fromBytes: fromBytes,
            }
        })();
    
        // Number of rounds by keysize
        var numberOfRounds = {
            16: 10,
            24: 12,
            32: 14
        }
    
        // Round constant words
        var rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97,
            0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
        ];
    
        // S-box and Inverse S-box (S is for Substitution)
        var S = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa,
            0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5,
            0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09,
            0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1,
            0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50,
            0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13,
            0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46,
            0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4,
            0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c,
            0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57,
            0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c,
            0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
        ];
        var Si = [0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b,
            0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95,
            0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72,
            0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9,
            0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8,
            0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11,
            0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2,
            0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe,
            0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88,
            0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a,
            0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17,
            0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
        ];
    
        // Transformations for encryption
        var T1 = [0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103,
            0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15,
            0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
            0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534,
            0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1,
            0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b,
            0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce,
            0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8,
            0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a,
            0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0,
            0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
            0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335,
            0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7,
            0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca,
            0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e,
            0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437,
            0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa,
            0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24,
            0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
            0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9,
            0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970,
            0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f,
            0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11,
            0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a
        ];
        var T2 = [0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101,
            0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa,
            0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0,
            0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5,
            0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696,
            0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909,
            0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3,
            0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1,
            0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef,
            0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050,
            0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5,
            0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313,
            0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d,
            0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646,
            0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a,
            0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4,
            0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656,
            0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c,
            0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a,
            0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757,
            0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9,
            0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c,
            0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f,
            0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616
        ];
        var T3 = [0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201,
            0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa,
            0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0,
            0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5,
            0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796,
            0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209,
            0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3,
            0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1,
            0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef,
            0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050,
            0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5,
            0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613,
            0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d,
            0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46,
            0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a,
            0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4,
            0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56,
            0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c,
            0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a,
            0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57,
            0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9,
            0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c,
            0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f,
            0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16
        ];
        var T4 = [0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302,
            0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef,
            0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b,
            0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1,
            0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137,
            0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12,
            0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d,
            0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879,
            0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5,
            0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0,
            0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
            0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526,
            0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba,
            0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c,
            0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14,
            0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3,
            0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac,
            0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438,
            0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f,
            0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae,
            0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9,
            0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03,
            0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e,
            0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c
        ];
    
        // Transformations for decryption
        var T5 = [0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6,
            0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502,
            0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
            0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360,
            0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2,
            0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b,
            0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75,
            0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f,
            0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9,
            0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964,
            0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
            0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb,
            0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510,
            0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c,
            0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36,
            0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e,
            0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4,
            0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af,
            0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
            0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473,
            0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935,
            0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381,
            0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190,
            0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742
        ];
        var T6 = [0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d,
            0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75,
            0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8,
            0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133,
            0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02,
            0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c,
            0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb,
            0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4,
            0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f,
            0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9,
            0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a,
            0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd,
            0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385,
            0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316,
            0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b,
            0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7,
            0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918,
            0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2,
            0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6,
            0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774,
            0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9,
            0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3,
            0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1,
            0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857
        ];
        var T7 = [0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76,
            0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f,
            0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9,
            0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751,
            0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b,
            0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf,
            0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6,
            0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406,
            0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42,
            0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f,
            0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12,
            0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99,
            0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263,
            0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3,
            0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4,
            0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39,
            0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59,
            0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4,
            0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791,
            0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87,
            0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761,
            0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf,
            0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456,
            0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8
        ];
        var T8 = [0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad,
            0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3,
            0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e,
            0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097,
            0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272,
            0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a,
            0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4,
            0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04,
            0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c,
            0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a,
            0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c,
            0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee,
            0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042,
            0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b,
            0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698,
            0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e,
            0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e,
            0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31,
            0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17,
            0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa,
            0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7,
            0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca,
            0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064,
            0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0
        ];
    
        // Transformations for decryption key expansion
        var U1 = [0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553,
            0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c,
            0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9,
            0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935,
            0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec,
            0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6,
            0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3,
            0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c,
            0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86,
            0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9,
            0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c,
            0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1,
            0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88,
            0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f,
            0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691,
            0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee,
            0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f,
            0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d,
            0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68,
            0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff,
            0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d,
            0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca,
            0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f,
            0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3
        ];
        var U2 = [0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165,
            0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4,
            0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b,
            0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9,
            0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652,
            0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d,
            0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512,
            0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093,
            0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db,
            0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a,
            0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225,
            0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0,
            0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b,
            0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462,
            0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76,
            0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927,
            0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4,
            0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83,
            0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc,
            0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015,
            0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35,
            0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc,
            0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3,
            0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697
        ];
        var U3 = [0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41,
            0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4,
            0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7,
            0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761,
            0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86,
            0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76,
            0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25,
            0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0,
            0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844,
            0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21,
            0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2,
            0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe,
            0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789,
            0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134,
            0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc,
            0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9,
            0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406,
            0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be,
            0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed,
            0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050,
            0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c,
            0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731,
            0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562,
            0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46
        ];
        var U4 = [0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e,
            0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8,
            0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba,
            0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7,
            0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d,
            0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad,
            0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf,
            0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69,
            0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678,
            0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e,
            0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc,
            0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d,
            0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807,
            0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1,
            0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188,
            0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece,
            0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04,
            0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4,
            0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6,
            0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60,
            0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01,
            0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7,
            0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5,
            0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d
        ];
    
        function convertToInt32(bytes) {
            var result = [];
            for (var i = 0; i < bytes.length; i += 4) {
                result.push(
                    (bytes[i] << 24) |
                    (bytes[i + 1] << 16) |
                    (bytes[i + 2] << 8) |
                    bytes[i + 3]
                );
            }
            return result;
        }
    
        var AES = function (key) {
            if (!(this instanceof AES)) {
                throw Error('AES must be instanitated with `new`');
            }
    
            Object.defineProperty(this, 'key', {
                value: coerceArray(key, true)
            });
    
            this._prepare();
        }
    
        AES.prototype._prepare = function () {
    
            var rounds = numberOfRounds[this.key.length];
            if (rounds == null) {
                throw new Error('invalid key size (must be 16, 24 or 32 bytes)');
            }
    
            // encryption round keys
            this._Ke = [];
    
            // decryption round keys
            this._Kd = [];
    
            for (var i = 0; i <= rounds; i++) {
                this._Ke.push([0, 0, 0, 0]);
                this._Kd.push([0, 0, 0, 0]);
            }
    
            var roundKeyCount = (rounds + 1) * 4;
            var KC = this.key.length / 4;
    
            // convert the key into ints
            var tk = convertToInt32(this.key);
    
            // copy values into round key arrays
            var index;
            for (var i = 0; i < KC; i++) {
                index = i >> 2;
                this._Ke[index][i % 4] = tk[i];
                this._Kd[rounds - index][i % 4] = tk[i];
            }
    
            // key expansion (fips-197 section 5.2)
            var rconpointer = 0;
            var t = KC,
                tt;
            while (t < roundKeyCount) {
                tt = tk[KC - 1];
                tk[0] ^= ((S[(tt >> 16) & 0xFF] << 24) ^
                    (S[(tt >> 8) & 0xFF] << 16) ^
                    (S[tt & 0xFF] << 8) ^
                    S[(tt >> 24) & 0xFF] ^
                    (rcon[rconpointer] << 24));
                rconpointer += 1;
    
                // key expansion (for non-256 bit)
                if (KC != 8) {
                    for (var i = 1; i < KC; i++) {
                        tk[i] ^= tk[i - 1];
                    }
    
                    // key expansion for 256-bit keys is "slightly different" (fips-197)
                } else {
                    for (var i = 1; i < (KC / 2); i++) {
                        tk[i] ^= tk[i - 1];
                    }
                    tt = tk[(KC / 2) - 1];
    
                    tk[KC / 2] ^= (S[tt & 0xFF] ^
                        (S[(tt >> 8) & 0xFF] << 8) ^
                        (S[(tt >> 16) & 0xFF] << 16) ^
                        (S[(tt >> 24) & 0xFF] << 24));
    
                    for (var i = (KC / 2) + 1; i < KC; i++) {
                        tk[i] ^= tk[i - 1];
                    }
                }
    
                // copy values into round key arrays
                var i = 0,
                    r, c;
                while (i < KC && t < roundKeyCount) {
                    r = t >> 2;
                    c = t % 4;
                    this._Ke[r][c] = tk[i];
                    this._Kd[rounds - r][c] = tk[i++];
                    t++;
                }
            }
    
            // inverse-cipher-ify the decryption round key (fips-197 section 5.3)
            for (var r = 1; r < rounds; r++) {
                for (var c = 0; c < 4; c++) {
                    tt = this._Kd[r][c];
                    this._Kd[r][c] = (U1[(tt >> 24) & 0xFF] ^
                        U2[(tt >> 16) & 0xFF] ^
                        U3[(tt >> 8) & 0xFF] ^
                        U4[tt & 0xFF]);
                }
            }
        }
    
        AES.prototype.encrypt = function (plaintext) {
            if (plaintext.length != 16) {
                throw new Error('invalid plaintext size (must be 16 bytes)');
            }
    
            var rounds = this._Ke.length - 1;
            var a = [0, 0, 0, 0];
    
            // convert plaintext to (ints ^ key)
            var t = convertToInt32(plaintext);
            for (var i = 0; i < 4; i++) {
                t[i] ^= this._Ke[0][i];
            }
    
            // apply round transforms
            for (var r = 1; r < rounds; r++) {
                for (var i = 0; i < 4; i++) {
                    a[i] = (T1[(t[i] >> 24) & 0xff] ^
                        T2[(t[(i + 1) % 4] >> 16) & 0xff] ^
                        T3[(t[(i + 2) % 4] >> 8) & 0xff] ^
                        T4[t[(i + 3) % 4] & 0xff] ^
                        this._Ke[r][i]);
                }
                t = a.slice();
            }
    
            // the last round is special
            var result = createArray(16),
                tt;
            for (var i = 0; i < 4; i++) {
                tt = this._Ke[rounds][i];
                result[4 * i] = (S[(t[i] >> 24) & 0xff] ^ (tt >> 24)) & 0xff;
                result[4 * i + 1] = (S[(t[(i + 1) % 4] >> 16) & 0xff] ^ (tt >> 16)) & 0xff;
                result[4 * i + 2] = (S[(t[(i + 2) % 4] >> 8) & 0xff] ^ (tt >> 8)) & 0xff;
                result[4 * i + 3] = (S[t[(i + 3) % 4] & 0xff] ^ tt) & 0xff;
            }
    
            return result;
        }
    
        AES.prototype.decrypt = function (ciphertext) {
            if (ciphertext.length != 16) {
                throw new Error('invalid ciphertext size (must be 16 bytes)');
            }
    
            var rounds = this._Kd.length - 1;
            var a = [0, 0, 0, 0];
    
            // convert plaintext to (ints ^ key)
            var t = convertToInt32(ciphertext);
            for (var i = 0; i < 4; i++) {
                t[i] ^= this._Kd[0][i];
            }
    
            // apply round transforms
            for (var r = 1; r < rounds; r++) {
                for (var i = 0; i < 4; i++) {
                    a[i] = (T5[(t[i] >> 24) & 0xff] ^
                        T6[(t[(i + 3) % 4] >> 16) & 0xff] ^
                        T7[(t[(i + 2) % 4] >> 8) & 0xff] ^
                        T8[t[(i + 1) % 4] & 0xff] ^
                        this._Kd[r][i]);
                }
                t = a.slice();
            }
    
            // the last round is special
            var result = createArray(16),
                tt;
            for (var i = 0; i < 4; i++) {
                tt = this._Kd[rounds][i];
                result[4 * i] = (Si[(t[i] >> 24) & 0xff] ^ (tt >> 24)) & 0xff;
                result[4 * i + 1] = (Si[(t[(i + 3) % 4] >> 16) & 0xff] ^ (tt >> 16)) & 0xff;
                result[4 * i + 2] = (Si[(t[(i + 2) % 4] >> 8) & 0xff] ^ (tt >> 8)) & 0xff;
                result[4 * i + 3] = (Si[t[(i + 1) % 4] & 0xff] ^ tt) & 0xff;
            }
    
            return result;
        }
    
        /**
         *  Mode Of Operation - Electonic Codebook (ECB)
         */
        var ModeOfOperationECB = function (key) {
            if (!(this instanceof ModeOfOperationECB)) {
                throw Error('AES must be instanitated with `new`');
            }
    
            this.description = "Electronic Code Block";
            this.name = "ecb";
    
            this._aes = new AES(key);
        }
    
        ModeOfOperationECB.prototype.encrypt = function (plaintext) {
            plaintext = coerceArray(plaintext);
    
            if ((plaintext.length % 16) !== 0) {
                throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
            }
    
            var ciphertext = createArray(plaintext.length);
            var block = createArray(16);
    
            for (var i = 0; i < plaintext.length; i += 16) {
                copyArray(plaintext, block, 0, i, i + 16);
                block = this._aes.encrypt(block);
                copyArray(block, ciphertext, i);
            }
    
            return ciphertext;
        }
    
        ModeOfOperationECB.prototype.decrypt = function (ciphertext) {
            ciphertext = coerceArray(ciphertext);
    
            if ((ciphertext.length % 16) !== 0) {
                throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
            }
    
            var plaintext = createArray(ciphertext.length);
            var block = createArray(16);
    
            for (var i = 0; i < ciphertext.length; i += 16) {
                copyArray(ciphertext, block, 0, i, i + 16);
                block = this._aes.decrypt(block);
                copyArray(block, plaintext, i);
            }
    
            return plaintext;
        }
    
        /**
         *  Mode Of Operation - Cipher Block Chaining (CBC)
         */
        var ModeOfOperationCBC = function (key, iv) {
            if (!(this instanceof ModeOfOperationCBC)) {
                throw Error('AES must be instanitated with `new`');
            }
    
            this.description = "Cipher Block Chaining";
            this.name = "cbc";
    
            if (!iv) {
                iv = createArray(16);
    
            } else if (iv.length != 16) {
                throw new Error('invalid initialation vector size (must be 16 bytes)');
            }
    
            this._lastCipherblock = coerceArray(iv, true);
    
            this._aes = new AES(key);
        }
    
        ModeOfOperationCBC.prototype.encrypt = function (plaintext) {
            plaintext = coerceArray(plaintext);
    
            if ((plaintext.length % 16) !== 0) {
                throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
            }
    
            var ciphertext = createArray(plaintext.length);
            var block = createArray(16);
    
            for (var i = 0; i < plaintext.length; i += 16) {
                copyArray(plaintext, block, 0, i, i + 16);
    
                for (var j = 0; j < 16; j++) {
                    block[j] ^= this._lastCipherblock[j];
                }
    
                this._lastCipherblock = this._aes.encrypt(block);
                copyArray(this._lastCipherblock, ciphertext, i);
            }
    
            return ciphertext;
        }
    
        ModeOfOperationCBC.prototype.decrypt = function (ciphertext) {
            ciphertext = coerceArray(ciphertext);
    
            if ((ciphertext.length % 16) !== 0) {
                throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
            }
    
            var plaintext = createArray(ciphertext.length);
            var block = createArray(16);
    
            for (var i = 0; i < ciphertext.length; i += 16) {
                copyArray(ciphertext, block, 0, i, i + 16);
                block = this._aes.decrypt(block);
    
                for (var j = 0; j < 16; j++) {
                    plaintext[i + j] = block[j] ^ this._lastCipherblock[j];
                }
    
                copyArray(ciphertext, this._lastCipherblock, 0, i, i + 16);
            }
    
            return plaintext;
        }
    
        /**
         *  Mode Of Operation - Cipher Feedback (CFB)
         */
        var ModeOfOperationCFB = function (key, iv, segmentSize) {
            if (!(this instanceof ModeOfOperationCFB)) {
                throw Error('AES must be instanitated with `new`');
            }
    
            this.description = "Cipher Feedback";
            this.name = "cfb";
    
            if (!iv) {
                iv = createArray(16);
    
            } else if (iv.length != 16) {
                throw new Error('invalid initialation vector size (must be 16 size)');
            }
    
            if (!segmentSize) {
                segmentSize = 1;
            }
    
            this.segmentSize = segmentSize;
    
            this._shiftRegister = coerceArray(iv, true);
    
            this._aes = new AES(key);
        }
    
        ModeOfOperationCFB.prototype.encrypt = function (plaintext) {
            if ((plaintext.length % this.segmentSize) != 0) {
                throw new Error('invalid plaintext size (must be segmentSize bytes)');
            }
    
            var encrypted = coerceArray(plaintext, true);
    
            var xorSegment;
            for (var i = 0; i < encrypted.length; i += this.segmentSize) {
                xorSegment = this._aes.encrypt(this._shiftRegister);
                for (var j = 0; j < this.segmentSize; j++) {
                    encrypted[i + j] ^= xorSegment[j];
                }
    
                // Shift the register
                copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
                copyArray(encrypted, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
            }
    
            return encrypted;
        }
    
        ModeOfOperationCFB.prototype.decrypt = function (ciphertext) {
            if ((ciphertext.length % this.segmentSize) != 0) {
                throw new Error('invalid ciphertext size (must be segmentSize bytes)');
            }
    
            var plaintext = coerceArray(ciphertext, true);
    
            var xorSegment;
            for (var i = 0; i < plaintext.length; i += this.segmentSize) {
                xorSegment = this._aes.encrypt(this._shiftRegister);
    
                for (var j = 0; j < this.segmentSize; j++) {
                    plaintext[i + j] ^= xorSegment[j];
                }
    
                // Shift the register
                copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
                copyArray(ciphertext, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
            }
    
            return plaintext;
        }
    
        /**
         *  Mode Of Operation - Output Feedback (OFB)
         */
        var ModeOfOperationOFB = function (key, iv) {
            if (!(this instanceof ModeOfOperationOFB)) {
                throw Error('AES must be instanitated with `new`');
            }
    
            this.description = "Output Feedback";
            this.name = "ofb";
    
            if (!iv) {
                iv = createArray(16);
    
            } else if (iv.length != 16) {
                throw new Error('invalid initialation vector size (must be 16 bytes)');
            }
    
            this._lastPrecipher = coerceArray(iv, true);
            this._lastPrecipherIndex = 16;
    
            this._aes = new AES(key);
        }
    
        ModeOfOperationOFB.prototype.encrypt = function (plaintext) {
            var encrypted = coerceArray(plaintext, true);
    
            for (var i = 0; i < encrypted.length; i++) {
                if (this._lastPrecipherIndex === 16) {
                    this._lastPrecipher = this._aes.encrypt(this._lastPrecipher);
                    this._lastPrecipherIndex = 0;
                }
                encrypted[i] ^= this._lastPrecipher[this._lastPrecipherIndex++];
            }
    
            return encrypted;
        }
    
        // Decryption is symetric
        ModeOfOperationOFB.prototype.decrypt = ModeOfOperationOFB.prototype.encrypt;
    
        /**
         *  Counter object for CTR common mode of operation
         */
        var Counter = function (initialValue) {
            if (!(this instanceof Counter)) {
                throw Error('Counter must be instanitated with `new`');
            }
    
            // We allow 0, but anything false-ish uses the default 1
            if (initialValue !== 0 && !initialValue) {
                initialValue = 1;
            }
    
            if (typeof (initialValue) === 'number') {
                this._counter = createArray(16);
                this.setValue(initialValue);
    
            } else {
                this.setBytes(initialValue);
            }
        }
    
        Counter.prototype.setValue = function (value) {
            if (typeof (value) !== 'number' || parseInt(value) != value) {
                throw new Error('invalid counter value (must be an integer)');
            }
    
            for (var index = 15; index >= 0; --index) {
                this._counter[index] = value % 256;
                value = value >> 8;
            }
        }
    
        Counter.prototype.setBytes = function (bytes) {
            bytes = coerceArray(bytes, true);
    
            if (bytes.length != 16) {
                throw new Error('invalid counter bytes size (must be 16 bytes)');
            }
    
            this._counter = bytes;
        };
    
        Counter.prototype.increment = function () {
            for (var i = 15; i >= 0; i--) {
                if (this._counter[i] === 255) {
                    this._counter[i] = 0;
                } else {
                    this._counter[i]++;
                    break;
                }
            }
        }
    
        /**
         *  Mode Of Operation - Counter (CTR)
         */
        var ModeOfOperationCTR = function (key, counter) {
            if (!(this instanceof ModeOfOperationCTR)) {
                throw Error('AES must be instanitated with `new`');
            }
    
            this.description = "Counter";
            this.name = "ctr";
    
            if (!(counter instanceof Counter)) {
                counter = new Counter(counter)
            }
    
            this._counter = counter;
    
            this._remainingCounter = null;
            this._remainingCounterIndex = 16;
    
            this._aes = new AES(key);
        }
    
        ModeOfOperationCTR.prototype.encrypt = function (plaintext) {
            var encrypted = coerceArray(plaintext, true);
    
            for (var i = 0; i < encrypted.length; i++) {
                if (this._remainingCounterIndex === 16) {
                    this._remainingCounter = this._aes.encrypt(this._counter._counter);
                    this._remainingCounterIndex = 0;
                    this._counter.increment();
                }
                encrypted[i] ^= this._remainingCounter[this._remainingCounterIndex++];
            }
    
            return encrypted;
        }
    
        // Decryption is symetric
        ModeOfOperationCTR.prototype.decrypt = ModeOfOperationCTR.prototype.encrypt;
    
        ///////////////////////
        // Padding
    
        // See:https://tools.ietf.org/html/rfc2315
        function pkcs7pad(data) {
            data = coerceArray(data, true);
            var padder = 16 - (data.length % 16);
            var result = createArray(data.length + padder);
            copyArray(data, result);
            for (var i = data.length; i < result.length; i++) {
                result[i] = padder;
            }
            return result;
        }
    
        function pkcs7strip(data) {
            data = coerceArray(data, true);
            if (data.length < 16) {
                throw new Error('PKCS#7 invalid length');
            }
    
            var padder = data[data.length - 1];
            if (padder > 16) {
                throw new Error('PKCS#7 padding byte out of range');
            }
    
            var length = data.length - padder;
            for (var i = 0; i < padder; i++) {
                if (data[length + i] !== padder) {
                    throw new Error('PKCS#7 invalid padding byte');
                }
            }
    
            var result = createArray(length);
            copyArray(data, result, 0, 0, length);
            return result;
        }
    
        ///////////////////////
        // Exporting
    
        // The block cipher
        var aesjs = {
            AES: AES,
            Counter: Counter,
    
            ModeOfOperation: {
                ecb: ModeOfOperationECB,
                cbc: ModeOfOperationCBC,
                cfb: ModeOfOperationCFB,
                ofb: ModeOfOperationOFB,
                ctr: ModeOfOperationCTR
            },
    
            utils: {
                hex: convertHex,
                utf8: convertUtf8
            },
    
            padding: {
                pkcs7: {
                    pad: pkcs7pad,
                    strip: pkcs7strip
                }
            },
    
            _arrayTest: {
                coerceArray: coerceArray,
                createArray: createArray,
                copyArray: copyArray,
            }
        };
    
        // node.js
        if (typeof exports !== 'undefined') {
            module.exports = aesjs
    
            // RequireJS/AMD
            // http://www.requirejs.org/docs/api.html
            // https://github.com/amdjs/amdjs-api/wiki/AMD
        } else if (typeof (define) === 'function' && define.amd) {
            define(aesjs);
    
            // Web Browsers
        } else {
    
            // If there was an existing library at "aesjs" make sure it's still available
            if (root.aesjs) {
                aesjs._aesjs = root.aesjs;
            }
    
            root.aesjs = aesjs;
        }
    
    })(this);

    View.xml

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Encrypting and Decrypting Data in SAP UI5 using aes.js">
                        <content>
                            <VBox>
                                <Label text="Password"/>
                                <Input id="idPassword" value=""/>
                                <Button icon="sap-icon://locked" text="Encrypt" press="onEncrypt"/>
                                <Text text="" id="idEncrypted"/>
                                <Button visible="false" id="idDecryptButton" icon="sap-icon://unlocked" text="Decrypt" press="onDecrypt"/>
                                <Text text="" id="idDecrypted"/>
                            </VBox>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

    Controller.js

    sap.ui.define([
        "sap/ui/core/mvc/Controller",
        "sap/m/MessageBox",
        "sap/m/MessageToast",
        "sap/ui/model/json/JSONModel",
        "Test/Test/js/aesjs"
    
    ], function (Controller, MessageBox, MessageToast, JSONModel) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            /**
             * getEncryptedKey is invoked from a function. 
             * Input: string key value
             * Output: encrypted key value
             */
    
            getEncryptedKey: function (sKey) {
                // An example 128-bit key (16 bytes * 8 bits/byte = 128 bits)
                var key = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
                // Convert text to bytes
                var text = sKey;
                var textBytes = aesjs.utils.utf8.toBytes(text);
    
                // The counter is optional, and if omitted will begin at 1
                var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(5));
                var encryptedBytes = aesCtr.encrypt(textBytes);
    
                // To print or store the binary data, you may convert it to hex
                var encryptedHex = aesjs.utils.hex.fromBytes(encryptedBytes);
                return encryptedHex;
            },
    
            /**
             * getDecryptedKey is invoked from a function. 
             * Input: string key value
             * Output: Decrypted key value
             */
    
            getDecryptedKey: function (sEncryptedHex) {
                // An example 128-bit key (16 bytes * 8 bits/byte = 128 bits)
                var key = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
                // When ready to decrypt the hex string, convert it back to bytes
                var encryptedBytes = aesjs.utils.hex.toBytes(sEncryptedHex);
    
                // The counter mode of operation maintains internal state, so to
                // decrypt a new instance must be instantiated.
                var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(5));
                var decryptedBytes = aesCtr.decrypt(encryptedBytes);
    
                // Convert our bytes back into text
                var decryptedText = aesjs.utils.utf8.fromBytes(decryptedBytes);
                return decryptedText;
            },
    
            onEncrypt: function (oEvent) {
                // Fetching input
                var input = this.byId("idPassword").getValue();
                //Encrypting Data
                var output = this.getEncryptedKey(input);
                //showing output
                this.byId("idEncrypted").setText(output);
                //set decrypt button visible
                this.byId("idDecryptButton").setVisible(true);
            },
    
            onDecrypt: function (oEvent) {
                // Fetching input
                var input = this.byId("idEncrypted").getText();
                //Encrypting Data
                var output = this.getDecryptedKey(input);
                //showing output
                this.byId("idDecrypted").setText(output);
            }
    
        });
    });

    Output

    Output Encrypting and Decrypting Data in SAP UI5 using aes

  • Scan QR Code Integration in SAP UI5

    Introduction

    In SAP’s world, the UI5 and Fiori Apps are used extensively to perform a large number of operations. Among these operations, there is a common requirement of a warehouse to scan a QR Code pasted over a material and get the material number from it. It is similar to the QR Code scanning you might have seen at a shopping mall outlet. In this article, we will learn simple steps for Scan QR Code Integration in SAP UI5

    Pre requisite of QR Code Scanning in SAP UI5 via Mobile

    The QR Code scanning works fine on a laptop, but to make it work on a mobile phone or a tablet, you need to deploy your UI5 application as a Fiori Application. The fiori application should be used via the Fiori Launchpad mobile application. You can download the same from here:

    SAP Mobile Start: Fiori Launchpad for Android

    SAP Mobile Start: Fiori Launchpad for iOS

    Steps to create an SAP UI5 to scan a QR Code

    Steps to Integrate QR Code Scan

    To create a scanning app, follow the steps below:

    1. Create a UI5 project in any IDE

    2. Create a view and add a button to start scanning, and an input box to get the scanned data. The code would be like mentioned below:

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Scan QR Code Integration in SAP UI5">
                        <content>
                            <VBox>
                                <Button icon="sap-icon://qr-code" text="Scan" press="onScan"/>
                                <Label text="Material"/>
                                <Input id="materialNumber" value=""/>
                            </VBox>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

    Step 03: Add BarcodeScanner namespace and use it to scan the bar code, as shown below:

    sap.ui.define([
        "sap/ui/core/mvc/Controller",
        "sap/m/MessageBox",
        "sap/m/MessageToast",
        "sap/ui/model/json/JSONModel",
        "sap/ndc/BarcodeScanner",
    ], function (Controller, MessageBox, MessageToast, JSONModel, BarcodeScanner) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            onScan: function (oEvent) {
                var that = this;
                BarcodeScanner.scan(
                    function (mResult) {
                        if (!mResult.cancelled) {
                            that.getView().byId("materialNumber").setValue(mResult.text);
                            MessageBox.show("We got a QR code\n" +
                                "Result: " + mResult.text + "\n" +
                                "Format: " + mResult.format + "\n");
                        }
                    },
                    function (Error) {
                        alert("Scanning failed: " + Error);
                    }
                );
            },
    
        });
    });

    Note: If your scanning is not getting started, turn on the given extension in WebIDE:

    Hybrid App Toolkit

    Output

    Before Scanning

    Scan QR Code Integration in SAP UI5 before scan

    During Scanning

    Scan QR Code Integration in SAP UI5 during scan

    After Scanning

    Scan QR Code Integration in SAP UI5 after scan

  • Scan Bar Code Integration in SAP UI5

    Introduction

    In SAP’s world, the UI5 and Fiori Apps are used extensively to perform a large number of operations. Among these operations, there is a common requirement of a warehouse to scan a barcode pasted over a material and get the material number from it. It is similar to the bar code scanning you might have seen at a shopping mall outlet. In this article, we will learn simple steps for Scan Bar Code Integration in SAP UI5

    Pre requisite of Bar Code Scanning in SAP UI5 via Mobile

    The bar code scanning works fine on a laptop, but to make it work on a mobile phone or a tablet, you need to deploy your UI5 application as a Fiori Application. The fiori application should be used via the Fiori Launchpad mobile application. You can download the same from here:

    SAP Mobile Start: Fiori Launchpad for Android

    SAP Mobile Start: Fiori Launchpad for iOS

    Steps to create an SAP UI5 to scan a barcode

    To create a scanning app, follow the steps below:

    1. Create a UI5 project in any IDE

    2. Create a view and add a button to start scanning, and an input box to get the scanned data. The code would be like mentioned below:

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Scan Bar Code Integration in SAP UI5">
                        <content>
                            <VBox>
                                <Button icon="sap-icon://bar-code" text="Scan" press="onScan"/>
                                <Label text="Material"/>
                                <Input id="materialNumber" value=""/>
                            </VBox>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

    Step 03: Add BarcodeScanner namespace and use it to scan the bar code, as shown below:

    sap.ui.define([
        "sap/ui/core/mvc/Controller",
        "sap/m/MessageBox",
        "sap/m/MessageToast",
        "sap/ui/model/json/JSONModel",
        "sap/ndc/BarcodeScanner",
    ], function (Controller, MessageBox, MessageToast, JSONModel, BarcodeScanner) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            onScan: function (oEvent) {
                var that = this;
                BarcodeScanner.scan(
                    function (mResult) {
                        if (!mResult.cancelled) {
                            that.getView().byId("materialNumber").setValue(mResult.text);
                            MessageBox.show("We got a bar code\n" +
                                "Result: " + mResult.text + "\n" +
                                "Format: " + mResult.format + "\n");
                        }
                    },
                    function (Error) {
                        alert("Scanning failed: " + Error);
                    }
                );
            },
    
        });
    });

    Note: If your scanning is not getting started, turn on the given extension in WebIDE:

    Hybrid App Toolkit

    Output

    Before Scanning

    Scan Bar Code Integration in SAP UI5 Before Scanning

    During Scanning

    Scan Bar Code Integration in SAP UI5 During Scanning

    After Scanning

    Scan Bar Code Integration in SAP UI5 After Scanning

  • How to Generate Mock Data in UI5

    Introduction

    As a UI5 developer or a UI5 tester, you may often need to generate mock data for testing your apps. This can be a time-taking task, especially when you need to test a large amount of data. Fortunately, we have several tools provided by SAP to make this process faster and more efficient. In this article, we will explore the best practices for generating mock data in UI5.

    What is a Mock Data?

    Mock data, also known as fake data or dummy data, is data that is created for the purpose of testing or demonstrating a software application without using real production data. Mock data is often used in software development to simulate different scenarios or test the functionality of an application under different conditions. Mock data can be used to create test cases, generate sample data for demos, or simulate user behavior for usability testing. The data used in mock data can be randomly generated or created manually to mimic the format and structure of real data. Using mock data helps ensure that software applications are tested thoroughly before they are released to end-users and that they function correctly under a wide range of conditions.

    When do we need Mock Data in SAP UI5?

    Mock data is commonly used in SAP UI5 development for several reasons, including:

    1. Testing: Mock data is used to test the application’s functionality under different conditions without the need for real data. It helps to identify and fix any issues before the application is deployed in a production environment.
    2. Prototyping: Mock data is useful for quickly prototyping and demonstrating the application’s features and functionality without having to connect to real data sources.
    3. Performance: Using real data during the development process can slow down the application’s performance. Mock data helps developers test and optimize the application’s performance before deploying it in a production environment.
    4. Security: Mock data can be used to ensure that sensitive or confidential data is not exposed during development and testing.

    Overall, using mock data in SAP UI5 development helps to reduce development time and costs while ensuring that the application meets the requirements and functions as expected.

    Steps to Generate Mock Data in SAP UI5

    There are several methods for generating mock data in SAP UI5, depending on your specific needs and preferences. Here are some general steps that you can follow to generate mock data in SAP UI5:

    1. Identify the data requirements: Determine the type of data and the format needed for your application. This may include data types, fields, and data structure.
    2. Choose a method: Select the method that best suits your needs for generating mock data. You can use online tools, create custom scripts, or leverage existing data sources.
    3. Generate the mock data: Use the chosen method to generate the mock data. If using an online tool, enter the data requirements and follow the prompts to generate the data. If creating custom scripts, use JavaScript or other scripting languages to create the data.
    4. Save the mock data: Save the generated mock data in a JSON format or any other format that is compatible with SAP UI5.
    5. Integrate the mock data: Use the mock data in your SAP UI5 application by either manually including it in your code or loading it dynamically from a JSON file.
    6. Test the application: Test the application with the mock data to ensure that it functions correctly under different conditions.

    Overall, generating mock data in SAP UI5 requires careful planning, selecting the right method, and thorough testing to ensure that the application functions as expected.

    Generate Custom Mock Data in SAP UI5

    How to Generate Mock Data in UI5 using WebIDE

    Following are the steps to generate Mock Data in SAP UI5 using WebIDE:

    Step 01: Create a new UI5 project (Neo or Cloud Foundry) in SAP WebIDE

    Step 02: Download the metadata (e.g. of Northwind from here: https://services.odata.org/v2/northwind/northwind.svc/$metadata)

    Step 03: Right-click on the project folder and click Import OData, and use the file downloaded above to import the same.

    Step 04: Once imported, do not change anything in Manfiest.xml, ui5.yaml file or servicebinding.js file. You will see a new file “metadata.xml” within the folder “localService” Right click on the file and click “Edit Mock Data”.

    Edit Mock Data

    Step 05: There you need to choose your entityset (in our usecase Products) and click the button “Generate Random Data”

    generate random data

    Step 06: In your view file, create a table and bind one of the entityset (in our usecase Products) to items, and the fields of the same within the table fields.

    Step 07: Run your web app using a new configuration, and mark “Run using mockdata” checkbox.

    That’s it, your mockdata would be binded with your table.

    Output of Mock Data

    Code

    Manifest File:

    {
        "_version": "1.12.0",
        "sap.app": {
            "id": "MockData.MockData",
            "type": "application",
            "i18n": "i18n/i18n.properties",
            "applicationVersion": {
                "version": "1.0.0"
            },
            "title": "{{appTitle}}",
            "description": "{{appDescription}}",
            "sourceTemplate": {
                "id": "servicecatalog.connectivityComponentForManifest",
                "version": "0.0.0"
            },
            "dataSources": {
                "NorthwindModel": {
                    "uri": "/here/goes/your/serviceurl/",
                    "type": "OData",
                    "settings": {
                        "localUri": "localService/metadata.xml"
                    }
                }
            }
        },
        "sap.ui": {
            "technology": "UI5",
            "icons": {
                "icon": "",
                "favIcon": "",
                "phone": "",
                "phone@2": "",
                "tablet": "",
                "tablet@2": ""
            },
            "deviceTypes": {
                "desktop": true,
                "tablet": true,
                "phone": true
            }
        },
        "sap.ui5": {
            "flexEnabled": false,
            "rootView": {
                "viewName": "MockData.MockData.view.View1",
                "type": "XML",
                "async": true,
                "id": "View1"
            },
            "dependencies": {
                "minUI5Version": "1.65.6",
                "libs": {
                    "sap.ui.layout": {},
                    "sap.ui.core": {},
                    "sap.m": {}
                }
            },
            "contentDensities": {
                "compact": true,
                "cozy": true
            },
            "models": {
                "i18n": {
                    "type": "sap.ui.model.resource.ResourceModel",
                    "settings": {
                        "bundleName": "MockData.MockData.i18n.i18n"
                    }
                },
                "": {
                    "type": "sap.ui.model.odata.v2.ODataModel",
                    "settings": {
                        "defaultOperationMode": "Server",
                        "defaultBindingMode": "OneWay",
                        "defaultCountMode": "Request"
                    },
                    "dataSource": "NorthwindModel",
                    "preload": true
                }
            },
            "resources": {
                "css": [
                    {
                        "uri": "css/style.css"
                    }
                ]
            },
            "routing": {
                "config": {
                    "routerClass": "sap.m.routing.Router",
                    "viewType": "XML",
                    "async": true,
                    "viewPath": "MockData.MockData.view",
                    "controlAggregation": "pages",
                    "controlId": "app",
                    "clearControlAggregation": false
                },
                "routes": [
                    {
                        "name": "RouteView1",
                        "pattern": "RouteView1",
                        "target": [
                            "TargetView1"
                        ]
                    }
                ],
                "targets": {
                    "TargetView1": {
                        "viewType": "XML",
                        "transition": "slide",
                        "clearControlAggregation": false,
                        "viewId": "View1",
                        "viewName": "View1"
                    }
                }
            }
        }
    }

     

    Service Binding File:

    function initModel() {
        var sUrl = "/here/goes/your/serviceurl/";
        var oModel = new sap.ui.model.odata.ODataModel(sUrl, true);
        sap.ui.getCore().setModel(oModel);
    }

     

    View File:

    <mvc:View controllerName="MockData.MockData.controller.View1" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Generate Custom Mock Data in SAP UI5">
                        <content>
                            <Table items="{/Products}">
                                <columns>
                                    <Column width="12em">
                                        <Text text="Product"/>
                                    </Column>
                                    <Column minScreenWidth="Tablet" demandPopin="true">
                                        <Text text="Supplier"/>
                                    </Column>
                                </columns>
                                <items>
                                    <ColumnListItem vAlign="Middle">
                                        <cells>
                                            <ObjectIdentifier title="{ProductName}" text="{ProductId}"/>
                                            <Text text="{SupplierID}"/>
                                        </cells>
                                    </ColumnListItem>
                                </items>
                            </Table>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

     

    How to Generate Mock Data in UI5 using BAS

    The content will be added soon.

  • Quantum Random Number Generation in SAP UI5

    Preface – This post is part of the UI5 Integration Programs series.

    Introduction

    A quantum random number is a number generated using a quantum-mechanical process, which is inherently unpredictable. In classical computing, random numbers are generated using algorithms that are deterministic, meaning they use a predetermined set of rules to produce the numbers. However, these deterministic algorithms can be prone to biases or patterns, which makes them not truly random.

    In contrast, quantum random number generators (QRNGs) use the principles of quantum mechanics to produce truly random numbers. One such process is the measurement of a quantum system, such as a photon, that has properties that are inherently uncertain. The outcome of this measurement is truly random and can be used to generate a random number.

    QRNGs are important for many applications in cryptography, simulations, and other fields that require high-quality random numbers. They are also used in quantum key distribution protocols, where two parties use a shared set of random numbers to generate a secret key for secure communication.

    It’s worth noting that not all random number generators based on quantum mechanics are truly random. Some so-called “pseudo-random number generators” use a deterministic process but rely on the inherent randomness of the physical processes involved, such as the thermal noise in a resistor, to produce random numbers. While these generators are not truly random, they are still useful for many applications where high-quality randomness is not required.

    What is Quantum Random Number Generation?

    Quantum random number generation is the process of generating truly random numbers using quantum-mechanical processes. Unlike classical methods of generating random numbers that are based on algorithms and pseudorandom number generators, quantum random number generation produces numbers that are truly unpredictable and cannot be replicated.

    The basic principle behind quantum random number generation is that quantum-mechanical phenomena, such as the polarization of photons or the decay of radioactive atoms, have inherent randomness that cannot be predicted. By measuring these phenomena, one can generate a sequence of numbers that are truly random.

    There are several different methods for generating random numbers using quantum-mechanical processes, including:

    1. Photon-based quantum random number generators, which use the polarization of photons to generate random numbers.
    2. Vacuum fluctuation-based quantum random number generators, which use the random fluctuations in the vacuum of space to generate random numbers.
    3. Radioactive decay-based quantum random number generators, which use the unpredictable decay of radioactive atoms to generate random numbers.

    These methods are based on different quantum-mechanical phenomena, but they all share the same basic principle of using the inherent randomness of quantum mechanics to generate truly random numbers.

    Quantum random number generators have many important applications in cryptography, simulation, and other fields that require high-quality randomness. They are also a key component in quantum key distribution, where two parties use a shared set of random numbers to generate a secret key for secure communication.

    Difference between Quantum Random Number Generation and Random Number Generation

    The main difference between quantum random number generation and random number generation is in the source of the randomness. Random number generation refers to any method of generating numbers that appear random, regardless of the source of that randomness. In contrast, quantum random number generation specifically refers to the use of quantum-mechanical processes to generate truly random numbers.

    Classical methods of random number generation, such as pseudorandom number generators (PRNGs), use algorithms to generate a sequence of numbers that appear random but are actually deterministic. PRNGs start with a seed value, and then use a mathematical formula to generate a sequence of numbers that, while not truly random, appear random and are suitable for many applications.

    In contrast, quantum random number generation uses the inherent randomness of quantum-mechanical processes, such as the polarization of photons or the decay of radioactive atoms, to generate truly random numbers that cannot be predicted or replicated. Quantum random number generation provides a higher level of randomness than classical methods and is important for applications that require the highest level of security and unpredictability, such as in cryptography.

    Another difference between the two methods is the speed at which they can generate random numbers. Quantum random number generation is typically slower than classical methods, due to the time it takes to measure the quantum-mechanical processes involved. This makes it less suitable for applications that require large amounts of random data to be generated quickly, such as in simulations or games. In contrast, classical random number generators can generate large amounts of random data quickly, making them better suited for such applications.

    In summary, the main difference between quantum random number generation and classical random number generation is the source of the randomness. Quantum random number generation uses the inherent unpredictability of quantum-mechanical processes to generate truly random numbers, while classical methods use deterministic algorithms to generate numbers that appear random.

    How can we Generate Quantum Random Numbers?

    Quantum random numbers can be generated using various methods based on the inherent randomness of quantum-mechanical processes. Here are three common methods of generating quantum random numbers:

    1. Photon-Based Quantum Random Number Generation: In this method, random numbers are generated by measuring the polarization of photons. A polarizing beam splitter is used to split a single photon into two orthogonal polarizations. The measurement of one of the polarizations is used to generate a random number. Since the polarization of the photon is a quantum-mechanical process that is inherently random, the resulting numbers are also random.
    2. Vacuum Fluctuation-Based Quantum Random Number Generation: This method utilizes the random fluctuations in the vacuum of space to generate random numbers. The energy of these fluctuations is measured using a device called a quantum noise generator, and the resulting measurements are used to generate random numbers.
    3. Radioactive Decay-Based Quantum Random Number Generation: In this method, the unpredictable decay of radioactive isotopes is used to generate random numbers. A radioactive source is used to emit particles, and the time between emissions is used to generate random numbers. Since the decay of the radioactive isotopes is a quantum-mechanical process that is inherently random, the resulting numbers are also random.

    It is important to note that generating high-quality random numbers requires careful design and implementation of the experimental setup. Any imperfections or biases in the measurement apparatus can potentially introduce biases into the generated numbers. Therefore, careful calibration and verification are necessary to ensure the randomness and quality of the generated numbers.

    Quantum random number generators have important applications in cryptography, simulation, and other fields that require high-quality randomness. They are also a key component in quantum key distribution, where two parties use a shared set of random numbers to generate a secret key for secure communication.

    What is Qrypt?

    Qrypt is a company that provides a quantum-based security solution using quantum key distribution (QKD) to secure communications between two parties. The Qrypt system includes a QKD device, a trusted node, and secure communication channels. Here’s an overview of the Qrypt setup:

    1. QKD Device: The QKD device is a specialized hardware device that generates and distributes the quantum keys used for secure communication. The device generates the keys by measuring the polarization of individual photons or other quantum-mechanical properties. The keys are then transmitted to the trusted node over a quantum channel, which ensures the keys are transmitted securely and cannot be intercepted or measured without detection.
    2. Trusted Node: The trusted node receives the quantum keys from the QKD device and performs error correction and privacy amplification to ensure the keys are secure and error-free. The trusted node then sends the final keys to the communication endpoints over a classical channel, which can be any secure communication channel, such as an internet connection, optical fiber, or a satellite link. The trusted node is a critical component of the system, as it ensures the integrity and security of the generated keys.
    3. Secure Communication Channels: The final keys are used to secure the communication channels between the two parties. The keys are used to encrypt the data, ensuring that only the intended recipient can decrypt and read the message. The communication channels can be any secure communication channel, such as a virtual private network (VPN), encrypted email, or a secure messaging app.

    The Qrypt system is designed to provide secure communication channels that cannot be intercepted or decrypted by any third party, even if they have the most advanced computing resources available. The system is based on the fundamental principles of quantum mechanics and provides a high level of security and privacy for sensitive communications.

    Setup of Qrypt

    To setup Qrypt, follow the given steps:

    1. Visit https://portal.qrypt.com
    Qrypt portal

    2. Enter your details are create your account, you will land on your dashboard:
    Qrypt Dashboard

    3. Go to Token, and provide values as below to generate one for yourself:
    Generate Entropy Token

    4. Save the generated token somewhere locally, and it will be used in the integration later:
    Save your token

    5. You can check all your tokens as shown below:
    Token Created

    SAP UI5 Integration with Quantum Random Number Generator Qrypt

    Before you start with the development in UI5, test the same in Postman with given data:
    Type: Get
    URL: https://api-eus.qrypt.com/api/v1/quantum-entropy?size=1
    Authorization Type: Bearer Token
    Token Value: <Your Generated token>
    The postman output will look like this:

    Postman Output

    Now, implement the following:

    View.xml

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
    xmlns:html="http://www.w3.org/1999/xhtml">
    <Shell id="shell">
    <App id="app">
    <pages>
    <Page id="page" title="Quantum Random Number Generation in SAP UI5">
    <content>
    <VBox>
    <Button text="Generate Qunatum Random Number" press="onPressGenerate"/>
    <Title text="Response"/>
    <TextArea id="idText" height="500px" width="100%"/>
    </VBox>
    </content>
    </Page>
    </pages>
    </App>
    </Shell>
    </mvc:View>

    Controller.js

    sap.ui.define([
        "sap/ui/core/mvc/Controller",
        "sap/m/MessageBox",
        "sap/m/MessageToast"
    ], function (Controller, MessageBox, MessageToast) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            onPressGenerate: function () {
                var that = this;
                // Specfify entropy token, requested size of entropy, and subdomain
                var accesstoken =
                    'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjM3Y2FiNjNkNzFiMzRmMWNhMDQ5N2VhMWViNjhiYjE3In0.eyJleHAiOjE2NzY4Mzg4MzcsIm5iZiI6MTY3Njc1MjQzNywiaXNzIjoiQVVUSCIsImlhdCI6MTY3Njc1MjQzNywiZ3JwcyI6WyJQVUIiXSwiYXVkIjpbIlJQUyJdLCJybHMiOlsiUk5EVVNSIl0sImNpZCI6Im9pd3MyV01xT0ZyQmNMX1VyNUl5XyIsImR2YyI6IjE0NTU1NzBhZjE3OTRmN2FhZDRkM2ZjYWI3MmE2ZmVhIiwianRpIjoiNGEyYTU4OTNlYmQxNGM3OWE1NjdmMmJjNTU1ODE4YmMiLCJ0eXAiOjN9.l1NajDLH-qLrQPa6_WrxuqCBwbjXPafamRXvJvbriZPe4KOb-tI3um8a7-Ce6xfSYVAbTb0aOgHGNst_qda3bg'
                var kibData = 1;
                var sub = 'api-weu'; //api-eus is for Eastern United States and api-weu is for Western Europe
    
                var settings = {
                    "url": "https://cors-anywhere.herokuapp.com/https://api-eus.qrypt.com/api/v1/quantum-entropy?size=1",
                    "method": "GET",
                    "timeout": 0,
                    "headers": {
                        "Authorization": "Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjM3Y2FiNjNkNzFiMzRmMWNhMDQ5N2VhMWViNjhiYjE3In0.eyJleHAiOjE2NzY4Mzg4MzcsIm5iZiI6MTY3Njc1MjQzNywiaXNzIjoiQVVUSCIsImlhdCI6MTY3Njc1MjQzNywiZ3JwcyI6WyJQVUIiXSwiYXVkIjpbIlJQUyJdLCJybHMiOlsiUk5EVVNSIl0sImNpZCI6Im9pd3MyV01xT0ZyQmNMX1VyNUl5XyIsImR2YyI6IjE0NTU1NzBhZjE3OTRmN2FhZDRkM2ZjYWI3MmE2ZmVhIiwianRpIjoiNGEyYTU4OTNlYmQxNGM3OWE1NjdmMmJjNTU1ODE4YmMiLCJ0eXAiOjN9.l1NajDLH-qLrQPa6_WrxuqCBwbjXPafamRXvJvbriZPe4KOb-tI3um8a7-Ce6xfSYVAbTb0aOgHGNst_qda3bg"
                    },
                };
    
                $.ajax(settings).done(function (response) {
                    console.log(response);
                    that.byId("idText").setValue(response);
                });
    
            }
        });
    });

    Note: Since browser doesn’t allow CORS, hence we have added https://cors-anywhere.herokuapp.com/ before our URL, to fix this. This is a temporary fix and the right way is to use Destination in SAP BTP.

    Output

    Quantum Random Number Generation in SAP UI5

  • Chat on WhatsApp button Integration in SAP UI5

    Preface – This post is part of the UI5 Integration Programs series.

    Introduction

    WhatsApp is a messaging app that allows users to communicate with each other through text-based chat, voice and video calls, and other multimedia features. The chat function on WhatsApp is one of its main features and is used by users to have conversations with their contacts.

    To start a chat on WhatsApp, you first need to have the app installed on your device and have an active account. Once you have the app open, you can navigate to the chat tab, where you will see a list of all your existing chats.

    To start a new chat, you can tap the “New Chat” button and then select the contact you want to chat with. You can also create a group chat with multiple contacts by selecting the “New Group” option.

    Once you are in a chat, you can type your message in the text box at the bottom of the screen and press the send button to send it. You can also use other features such as emojis, stickers, and GIFs to enhance your messages. If you want to make a voice or video call, you can use the call button at the top of the screen.

    WhatsApp also offers end-to-end encryption, which means that your messages are secure and can only be seen by you and the recipient. You can also customize your chat settings, such as notifications and chat backgrounds, to make your chatting experience more personalized.

    Overall, the chat function on WhatsApp is a simple and easy-to-use feature that allows users to communicate with their contacts in a fast and secure way.

    What is Chat on WhatsApp API

    WhatsApp API is a platform provided by WhatsApp that allows businesses to interact with their customers through the messaging app. The Chat function on WhatsApp API allows businesses to create and manage conversations with their customers using a programmable interface.

    With WhatsApp API, businesses can use their own applications to send and receive messages, media, and other types of content with their customers. This can include sending order confirmations, shipping notifications, and customer support messages. The chat function on WhatsApp API also allows businesses to automate certain parts of the conversation using chatbots, which can provide customers with quick answers to frequently asked questions.

    To use the Chat function on WhatsApp API, businesses need to have an approved WhatsApp Business Account and an integration with the WhatsApp Business API. Once these requirements are met, businesses can access the Chat API documentation and start building their chatbots and other messaging features.

    The Chat function on WhatsApp API is a powerful tool for businesses that want to reach their customers where they are, in a fast and convenient way. It can help businesses provide better customer support, increase engagement, and streamline their communication processes.

    How to use click to chat for WhatsApp

    Click to Chat is a feature on WhatsApp that allows you to create a link that, when clicked, opens a new chat with a specific phone number or contact. This can be useful if you want to make it easy for people to start a conversation with you on WhatsApp, without having to add your phone number to their contacts.

    To use Click to Chat for WhatsApp, follow these steps:

    1. Open your web browser and go to https://wa.me/ followed by the phone number you want to chat with in international format, without any spaces or symbols. For example, if the phone number is +1 (555) 123-4567, the link should be https://wa.me/15551234567.
    2. Hit the “Enter” key or click “Go” to load the link.
    3. If the phone number is associated with an active WhatsApp account, a new chat window will open with the phone number already entered.
    4. If the phone number is not associated with an active WhatsApp account, an error message will appear.

    You can also add a message to the link by adding ?text= followed by the message you want to send. For example, if you want to send a message that says “Hello, how can I help you?”, the link should be https://wa.me/15551234567?text=Hello,%20how%20can%20I%20help%20you%3F.

    Note that Click to Chat links can be shared on social media, email, websites, or any other platform where links can be posted. However, it’s important to be cautious when sharing your phone number or WhatsApp account information online, and to only share it with people or organizations you trust.

    How to Integrate Chat on WhatsApp button in SAP UI5

    To integrate WhatsApp in SAP UI5, you need to use the “click to chat” option, we have implemented as below:

    View.xml

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Chat on WhatsApp button Integration in SAP UI5">
                        <content>
                            <Input id="idNumber" value="" placeholder="Enter a number with country code"/>
                            <Input id="idText" value="" placeholder="Enter a text to send"/>
                            <Image width="20%" src="./view/whatsapp.png" press="handleWhatsAppPress"/>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

    Controller.js

    sap.ui.define([
        "sap/ui/core/mvc/Controller",
        "sap/m/MessageBox",
        "sap/m/MessageToast"
    ], function (Controller, MessageBox, MessageToast) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            handleWhatsAppPress: function () {
                var number = this.byId("idNumber").getValue();
                var text = this.byId("idText").getValue();
                // for Mobile Phone
                // var url = 'https:' + '//wa.me/' + number + '?text=' + text;
                // for Web Whatsapp
                var url = 'https:' + '//web.whatsapp.com/send/?phone=' + number + '&text=' + text + '&type=phone_number&app_absent=0';
                sap.m.URLHelper.redirect(url, true);
                // eg. +917070022222
            }
        });
    });

    Note: Remember to add an image in your view (or other) folder, we have added the image with name ‘whatsapp.png’.

    Output

    Chat on WhatsApp button Integration in SAP UI5

  • Video Call Integration in SAP UI5

    Preface – This post is part of the UI5 Integration Programs series.

    Introduction

    Video call is a feature that allows two or more people to communicate with each other using real-time video and audio transmissions over the internet. It allows people to connect and interact with each other, regardless of their physical location, by transmitting live video and audio signals through a digital network.

    Video calls can be made using a variety of devices, such as smartphones, tablets, laptops, desktop computers, and specialized video conferencing equipment. To make a video call, both parties must have compatible devices and access to the internet, either through Wi-Fi or mobile data.

    During a video call, the camera on each device captures live video of the person or people on the other end of the call, which is then transmitted over the internet to the other device. Similarly, the microphone on each device captures the audio of the person speaking, which is also transmitted over the internet to the other device.

    Video calling has become increasingly popular in recent years, as it provides a more personal and engaging way to communicate than traditional phone calls or text-based messaging. It’s often used for personal communication between family and friends, as well as for professional purposes such as virtual meetings, job interviews, and remote work collaboration.

    What is a video calling feature in a Web application?

    A video calling feature in a web application is a software functionality that allows users to initiate and participate in live video calls directly within a web browser. It enables people to have real-time audio and video communication through their desktop, laptop, or mobile device without the need for any additional software or hardware.

    To use the video calling feature in a web application, users typically need a compatible web browser, a webcam, a microphone, and a stable internet connection. Once the user has these components set up, they can initiate or join a video call with another user or a group of users in the web application.

    Web-based video calling is often integrated with other communication features such as instant messaging, screen sharing, and file sharing. It is commonly used for virtual meetings, remote work collaboration, online learning, and social communication.

    Web-based video calling can be done using various web technologies, including WebRTC (Web Real-Time Communication), which is an open-source project that enables real-time communication between browsers, and other proprietary solutions. Some popular examples of web-based video calling platforms include Zoom, Google Meet, Microsoft Teams, and Skype.

    What all ways can we integrate video calling feature in a Web Application?

    There are various ways to integrate a video calling feature in a web application, some of which include:

    1. WebRTC: WebRTC (Web Real-Time Communication) is a free, open-source project that enables real-time communication between browsers. It provides the necessary APIs for web developers to implement video calling directly in their web applications, without requiring additional software or plugins.
    2. Using third-party APIs and SDKs: Many video calling platforms, such as Zoom, Google Meet, and Twilio, provide APIs and SDKs that developers can use to integrate video calling features into their web applications.
    3. Building a custom solution: Developers can build a custom solution for video calling by leveraging various web technologies such as WebSockets, Node.js, and socket.io. This requires extensive development and testing but allows for greater customization and control over the video calling experience.
    4. Using a pre-built solution: There are also pre-built video calling solutions available that can be easily integrated into web applications, such as Agora.io, Vonage Video API, and Daily.co. These solutions typically offer a range of features, including screen sharing, recording, and chat, and can be customized to fit the specific needs of a web application.

    The choice of integration method will depend on factors such as the level of customization required, the budget and resources available, and the specific features needed for the web application.

    What is the concept of WebRTC API?

    WebRTC (Web Real-Time Communication) is a free, open-source project that enables real-time communication between browsers and mobile applications. It provides a set of JavaScript APIs that allow developers to integrate real-time communication capabilities, such as video and audio calling, directly into their web applications without requiring any additional software or plugins.

    WebRTC’s core components include:

    1. getUserMedia: This API allows web applications to access a user’s camera and microphone, enabling them to capture audio and video data.
    2. RTCPeerConnection: This API allows web applications to establish a peer-to-peer connection between browsers or mobile devices, enabling real-time communication of audio and video data.
    3. RTCDataChannel: This API allows web applications to create a bi-directional, low-latency communication channel for sending arbitrary data between peers.

    Together, these APIs form the basis of WebRTC and enable developers to build real-time communication features directly into their web applications. WebRTC is supported by all major browsers, including Google Chrome, Mozilla Firefox, Apple Safari, and Microsoft Edge, and is used for a variety of applications, including video conferencing, voice calling, and file sharing.

    WebRTC also offers a secure, end-to-end encrypted communication channel, ensuring that user data is protected during transmission. Because it’s an open-source project, WebRTC is constantly evolving, and new features and functionalities are being added all the time.

    Video Integration using Agora Web SDK

    Agora Web SDK is a software development kit that enables developers to integrate real-time video and audio communication into their web applications. Here’s how to integrate video using Agora Web SDK:

    1. Create an Agora developer account and generate an App ID: To use Agora Web SDK, you need to create an account on the Agora platform and generate an App ID, which is used to authenticate your application and enable access to the Agora services.
      Agora Video CallingOur goal here is to create a project within Agora and get App ID, Channel and Token. In our usecase, we have got these:

      App ID: 09ed05f4f81d4ec580c45277ab70dac5
      Channel: ui5Demo
      Token: 007eJxTYND+53eO3bl+x9yax6cU1HLqHHZKN/5+f2LLwvXr/s9Luu6vwGBgmZpiYJpmkmZhmGKSmmxqYZBsYmpkbp6YZG6QkphsOvXN++SGQEaGo1P+MzMyQCCIz85Qmmnqkpqbz8AAAJQWJIA=

       

    2. Add the Agora Web SDK to your project: Once you have an App ID, you can add the Agora Web SDK to your project by including the Agora JavaScript library in your HTML code.
      These are the script for that:

      <!-- Agora Scripts -->
      <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
      <script src="https://download.agora.io/sdk/release/AgoraRTC_N.js"></script>

       

    3. Initialize the Agora client: The next step is to initialize the Agora client in your JavaScript code using the App ID and other necessary parameters.
    4. Create a video call: To create a video call, you need to create a video call object that contains the necessary configuration parameters, such as the channel name, mode, and codec. Then, you can join the call by calling the Agora RTC client join method.
    5. Manage the video call: Once the call is established, you can use the Agora SDK to manage the call, including starting and stopping video streams, muting and unmuting audio, and sharing the screen.
    6. Clean up: Finally, when the call is complete, you can use the Agora SDK to release the resources and terminate the call.

    Agora Web SDK provides a range of additional features and functionalities, including the ability to customize the user interface, integrate with third-party services, and control the quality of service. By integrating video using Agora Web SDK, you can add real-time communication capabilities to your web application, enabling users to connect with each other in a more immersive and engaging way.

    How to integrate Video Calling feature in SAP UI5?

    To Integrate a Video calling in SAP UI5, we will 3rd party API of Agora and the concept of WebRTC API. Please find the respective code below:

    HTML Code:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <!--<meta name="viewport" content="width=device-width, initial-scale=1.0">-->
            <title>My Project Ideas</title>
             <link rel="icon" type="image/x-icon" href="https://myprojectideas.com/wp-content/uploads/2021/08/cropped-Screenshot-2021-07-26-at-1.39.04-PM-32x32.png">
            <script id="sap-ui-bootstrap"
                src="resources/sap-ui-core.js"
                data-sap-ui-theme="sap_fiori_3"
                data-sap-ui-resourceroots='{"Test.Test": "./"}'
                data-sap-ui-compatVersion="edge"
                data-sap-ui-oninit="module:sap/ui/core/ComponentSupport"
                data-sap-ui-async="true"
                data-sap-ui-frameOptions="trusted">
            </script>
              <!-- Agora Scripts -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://download.agora.io/sdk/release/AgoraRTC_N.js"></script>
        </head>
        <body class="sapUiBody">
            <div data-sap-ui-component data-name="Test.Test" data-id="container" data-settings='{"id" : "Test"}'></div>
        </body>
    </html>

    View Code:

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Video Call Integration in SAP UI5">
                        <content>
                            <core:HTML class="sapUiLargeMargin"
                                content='&lt;div class=&quot;container&quot;&gt; &lt;div class=&quot;participant&quot; id=&quot;participant&quot;&gt;&lt;/div&gt; &lt;div class=&quot;fs&quot; id=&quot;fs&quot;&gt;&lt;/div&gt; &lt;/div&gt;'></core:HTML>
                        </content>
                        <footer >
                            <OverflowToolbar>
                                <Button id="idRemaining" type="Emphasized"/>
                                <ToolbarSpacer/>
                                <Button icon="sap-icon://popup-window" class="sapUiTinyMarginBeginEnd" text="Share Screen" press="onShareScreen"/>
                                <Button id="idMute" icon="sap-icon://sound-off" class="sapUiTinyMarginEnd" text="Mute" press="onPressMute"/>
                                <Button id="idUnmute" visible="false" class="sapUiTinyMarginEnd" icon="sap-icon://sound-loud" text="Unmute" press="onPressUnmute"/>
                                <Button type="Reject" text="Close Call" press="closeCall">
                                    <layoutData><OverflowToolbarLayoutData priority="NeverOverflow"/></layoutData>
                                </Button>
                            </OverflowToolbar>
                        </footer>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

    Controller Code:

    sap.ui.define([
        "sap/ui/core/mvc/Controller",
        "sap/m/MessageBox",
        "sap/m/MessageToast"
    ], function (Controller, MessageBox, MessageToast) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            onAfterRendering: async function (evt) {
                var that = this;
                this.flag = 0;
                try {
                    var that = this;
                    var date = new Date();
                    var startTime = date.getTime();
                    this.appointmentURL = {
                        startTime: startTime,
                        channel: "ui5Demo",
                        token: "007eJxTYND+53eO3bl+x9yax6cU1HLqHHZKN/5+f2LLwvXr/s9Luu6vwGBgmZpiYJpmkmZhmGKSmmxqYZBsYmpkbp6YZG6QkphsOvXN++SGQEaGo1P+MzMyQCCIz85Qmmnqkpqbz8AAAJQWJIA="
                    };
                    this.timeOut = setInterval(function () {
                    that.alertFunc()
                    }.bind(that), 1000);
                    that.rtc = {
                        // For the local audio and video tracks.
                        localAudioTrack: null,
                        localVideoTrack: null,
                    };
                    if (this.appointmentURL) {
                        var options = {
                            // Pass your app ID here.
                            appId: "09ed05f4f81d4ec580c45277ab70dac5",
                            // Set the channel name.
                            channel: this.appointmentURL.channel,
                            // Set the user role in the channel.
                            role: "host"
                        };
                        var token = this.appointmentURL.token;
                    }
                    that.client = AgoraRTC.createClient({
                        mode: "rtc",
                        codec: "vp8"
                    });
                    var uid = "doctor";
                    var div = document.createElement("div");
                    div.id = uid;
                    div.className = "zoomOut"
                    that.client.on("user-left", async(user, mediaType) => {
                        var elem = document.getElementById("id" + user.uid);
                        elem.parentElement.removeChild(elem);
                        console.log("left");
                    });
                    that.client.on("user-published", async(user, mediaType) => {
                        await that.client.subscribe(user, mediaType);
                        console.log("subscribe success");
                        var uuid = "id" + user.uid;
                        if (document.getElementById(uuid) == undefined) {
                            var div = document.createElement("div");
                            div.id = uuid;
                            if (that.flag === 0) {
                                div.className = "zoomIn"
                            } else {
                                div.className = "zoomOut"
                            }
                            that.buttonUID = uuid;
                            var button = document.createElement("button");
                            if (that.flag === 0) {
                                button.innerHTML = "Unpin";
                            } else {
                                button.innerHTML = "Pin";
                            }
                            button.className = "zoomButton";
                            that.flag = 1;
                            button.addEventListener("click", function (oEvent) {
                                var a = document.getElementById(uuid).className;
                                if (a == "zoomOut") {
                                    if (document.getElementsByClassName("zoomIn").length > 0) {
                                        document.getElementsByClassName("zoomIn")[0].className = "zoomOut";
                                    }
                                    document.getElementById(uuid).className = "zoomIn";
                                    oEvent.currentTarget.innerHTML = "Unpin";
                                    var allButtons = document.getElementsByClassName("zoomOut");
                                    for (var i = 1; i < allButtons.length; i++) {
                                        var reqButton = allButtons[i].getElementsByClassName("zoomButton");
                                        if (reqButton.length > 0) {
                                            reqButton[0].style.display = "none";
                                        }
                                    }
                                } else {
                                    document.getElementById(uuid).className = "zoomOut";
                                    oEvent.currentTarget.innerHTML = "Pin";
                                    var allButtons = document.getElementsByClassName("zoomOut");
                                    for (var i = 1; i < allButtons.length; i++) {
                                        var reqButton = allButtons[i].getElementsByClassName("zoomButton");
                                        if (reqButton.length > 0) {
                                            reqButton[0].style.display = "block";
                                        }
                                    }
                                }
    
                            });
                            div.appendChild(button);
                            document.getElementById("participant").appendChild(div);
                        }
                        const remoteVideoTrack = user.videoTrack;
                        that.remotePlayerContainer = document.getElementById(uuid);
                        remoteVideoTrack.play(that.remotePlayerContainer);
                        if (mediaType === "audio") {
                            const remoteAudioTrack = user.audioTrack;
                            remoteAudioTrack.play();
                        }
    
                    });
                    document.getElementById("participant").appendChild(div);
                    // that.client.setClientRole(options.role);
                    await that.client.join(options.appId, options.channel, token, 0);
                    that.rtc.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
                    that.rtc.localVideoTrack = await AgoraRTC.createCameraVideoTrack();
                    await that.client.publish([that.rtc.localAudioTrack, that.rtc.localVideoTrack]);
                    that.localPlayerContainer = document.getElementById(uid);
                    that.rtc.localVideoTrack.play(that.localPlayerContainer);
                    // Users joins for the first time
    
                } catch (error) {
                    console.log(error);
                    var errorMessage;
                    // Handle Errors here.
                    if (error && error.message) {
                        errorMessage = error.message;
                        if (error.code == 'CAN_NOT_GET_GATEWAY_SERVER') {
                            errorMessage = "The meeting session is no longer valid. Contact Admin";
                        }
                    } else {
                        errorMessage = "Something went wrong, contact Admin if the error persists";
                    }
                    MessageBox.error(errorMessage, {
                        actions: [MessageBox.Action.CLOSE],
                        onClose: function (sAction) {
                            if (sAction == 'CLOSE') {
                                // Write close operation
                            }
                        }
                    });
                };
            },
    
            onCancelCall: function (oEvent) {
                this.closeCall();
            },
    
            onMarkCompleteCall: function (oEvent) {
                this.closeCall();
            },
    
            closeCall: async function (oEvent) {
                var that = this;
                var date = new Date();
                var endTime = date.getTime();
                if (that.rtc) {
                    that.rtc.localAudioTrack.close();
                    // that.rtc.localVideoTrack.stop();
                    that.rtc.localVideoTrack.close();
                    // Traverse all remote users.
                    // Destroy the dynamically created DIV containers.
                    const playerContainer = document.getElementById('div2');
                    playerContainer && playerContainer.remove();
                    // Leave the channel.
                    await that.client.leave();
                }
            },
    
            alertFunc: function () {
                var that = this;
                var countDownDate = that.appointmentURL.startTime;
                // Get today's date and time
                var now = new Date().getTime();
                var endTime = "10-22-05";
                // Find the distance between now and the count down date
                var distance = now - countDownDate;
    
                // Time calculations for days, hours, minutes and seconds
                var hours = that.doubleDigit(Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)));
                var minutes = that.doubleDigit(Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)));
                var seconds = that.doubleDigit(Math.floor((distance % (1000 * 60)) / 1000));
                var timeRemaining =
                    new Date('01/01/2007 ' + endTime.split('-')[1] + ':00').getTime() -
                    new Date('01/01/2007 ' + endTime.split('-')[0] + ':00').getTime();
                var diff = Math.abs(
                    Math.floor((timeRemaining % (1000 * 60 * 60)) / (1000 * 60)),
                );
    
                that.getView().byId("idRemaining").setText(hours + ':' + minutes + ':' + seconds);
                if (minutes > diff) {
                    that.getView().byId("idRemaining").setType("Critical");
                }
            },
    
            doubleDigit: function (time) {
                return ("0" + time).slice(-2);
            },
    
            onShareScreen: async function (oEvent) {
                var that = this;
                if (this.appointmentURL) {
                    var appId = "09ed05f4f81d4ec580c45277ab70dac5";
                    var channel = this.appointmentURL.channel;
                    var token = this.appointmentURL.token;
                }
                const screenClient = AgoraRTC.createClient({
                    mode: "rtc",
                    codec: "vp8"
                });
                await screenClient.join(appId, channel, token);
                const screenTrack = await AgoraRTC.createScreenVideoTrack();
                await screenClient.publish(screenTrack);
                return screenClient;
            },
    
            onPressMute: function (oEvent) {
                this.byId("idMute").setVisible(false);
                this.byId("idUnmute").setVisible(true);
                this.rtc.localAudioTrack.setEnabled(false);
            },
    
            onPressUnmute: function (oEvent) {
                this.byId("idMute").setVisible(true);
                this.byId("idUnmute").setVisible(false);
                this.rtc.localAudioTrack.setEnabled(true);
            },
    
            onPressZoomIn: function (oEvent) {
                var divID = oEvent.getSource().data("divID");
                document.getElementById(divID).style.width = "640px";
                document.getElementById(divID).style.height = "480px";
            },
    
            onPressZoomOut: function (oEvent) {
                var divID = oEvent.getSource().data("divID");
                document.getElementById(divID).style.width = "320px";
                document.getElementById(divID).style.height = "240px";
            }
        });
    });

     

    CSS Code:

    /* Enter your custom styles here */
    .EmphasizedText {
        font-weight: bold;
        -webkit-text-fill-color: #085caf;
    }
    
    .whitebg {
        background-color: white !important;
    }
    
    .container {
        display: flex;
    }
    
    .participant {
        width: 20%;
        height: 500px;
        text-align: center;
        display: flex;
        flex-direction: column;
        align-items: center;
       
    }
    
    .zoomOut {
        width: 80%;
        height: 200px;
        position: relative;
    }
    
    .fs {
        width: 80%;
        display: flex;
        align-items: center;
    }
    
    .zoomButton {
        position: absolute;
        z-index: 100;
        top: 5px;
        right: 5px;
        border-color: #fff;
        background: #fff;
        color: black;
    }
    
    .zoomButton:before {
        content: "📌 ";
    }
    
    .zoomIn {
        width: 80%;
        height: 100%;
        position: absolute;
        right: 10px;
    }
    
    html.sap-desktop .sapMShellAppWidthLimited .sapMShellCentralBox {
        width: 100% !important;
        margin-left: 5px !important;
        left: 0 !important;
    }

    Output

    Video Call Integration in SAP UI5

  • Copy to Clipboard Integration in SAP UI5

    Preface – This post is part of the UI5 Integration Programs series.

    Introduction

    Copy to Clipboard functionality refers to the ability of a computer or mobile device to copy selected text or data and temporarily store it in a virtual clipboard. The copied content can then be pasted into another location, such as a document or an email.

    The copy to clipboard function can be accessed through a variety of ways, such as right-clicking on the selected content and choosing “Copy” from a menu, or using a keyboard shortcut such as Ctrl+C (on Windows) or Command+C (on Mac). Once the content is copied to the clipboard, it can be pasted into another location using a keyboard shortcut such as Ctrl+V (on Windows) or Command+V (on Mac), or by right-clicking and choosing “Paste” from a menu.

    Copy to Clipboard is a widely used feature in modern computing, and is particularly useful for tasks such as copying text from a web page or document, and pasting it into an email or other document without having to retype the content.

    Why we need to have a Copy to Clipboard Functionality in Website

    Copy to Clipboard functionality is useful in websites for a variety of reasons. Here are a few:

    1. Convenience: Copy to Clipboard makes it easy for users to copy and paste text, links, or other content from a website without having to type it out manually.
    2. Accuracy: Copy to Clipboard can help ensure that users copy and paste content accurately, without introducing errors or typos.
    3. Sharing: Copy to Clipboard makes it easy for users to share content from a website with others via email, chat, or social media.
    4. Productivity: Copy to Clipboard can help users be more productive by allowing them to quickly copy and paste information from a website into other applications, such as word processors or spreadsheets.
    5. Accessibility: Copy to Clipboard can be particularly helpful for users who may have difficulty typing, such as those with disabilities or injuries.

    Overall, Copy to Clipboard functionality in websites is a useful tool that can help users save time and be more productive, while also reducing the risk of errors and increasing accuracy.

    How to Integrate Copy to Clipboard  functionality in UI5

    The copy to clipboard is a very simple functionality of HTML and JavaScript, but quite difficult in case of SAP UI5. There are three steps involved in HTML based copy to clipboard operation:
    1. Textarea with text value meant for copy
    2. Selection of the text using Select function
    3. Copy to Clipboard using Copy function

    The same three operations will be performed in SAP UI5.

    Before you start coding, create a JavaScript file (here customDOM.js) and keep it in a Js folder with given content:

    /**
     * @Author: Rudramani Pandey
     * Purpose: JS File for all Custom HTML DOM operations (copy to clipboard)
     * Modified: 17.02.2023
     */
    sap.ui.define([], function () {
        "use strict";
    
        return {
    
            createTextArea: function (text) {
                var textArea = document.createElement("textarea");
                textArea.value = text;
                return textArea;
            },
    
            insertTextArea: function (textArea) {
                document.body.appendChild(textArea);
                return true;
            },
    
            execCommand: function () {
                return document.execCommand('copy');
            },
    
            removeChild: function (textArea) {
                document.body.removeChild(textArea);
                return true;
            }
        };
    });

    Explanation:

    In the above code createTextArea would create a HTML element textArea. Then insertTextArea would append it to the body of the HTML. execCommand performs the copy function and removeChild removes the HTML element from the body once our task is done.

    Then create a view and have simple text area and copy to clipboard button:
    View.xml

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Copy to Clipboard Integration in SAP UI5">
                        <content>
                            <VBox>
                                <TextArea id="idText" value="This is the text that I am going to copy!"/>
                                <Button text="Copy to Clipboard" press="onPressToClipboard"/>
                            </VBox>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

    Now, create a controller, include the JavaScript file in the define section. Now a function to get the text data from XML file.

    Controller.js

    sap.ui.define([
        "sap/ui/core/mvc/Controller",
        "Test/Test/js/customDOM",
        "sap/m/MessageBox",
        "sap/m/MessageToast"
    ], function (Controller, customDOM, MessageBox, MessageToast) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            onInit: function () {
    
            },
    
            /** 
             * onPressToClipboard is invoked on click of Copy to Clipboard from UI.
             * Calls getText to receive the text value
             * @param oEvent
             * Output: Value of Text Area in HTML DOM
             */
            onPressToClipboard: function (oEvent) {
                var that = this;
                Promise.all([that.getText(oEvent, "CopyPassword")]).then(function (param) {
                    param = param[0];
                    var textArea = customDOM.createTextArea(param);
                    customDOM.insertTextArea(textArea);
                    textArea.select();
    
                    try {
                        var successful = customDOM.execCommand();
                        var sMsg = successful ? "successful" : "unsuccessful";
                        MessageToast.show("Password Copy to Clipboard was " + sMsg);
                    } catch (err) {
                        // Error Handled Later
                    }
                    customDOM.removeChild(textArea);
                }).catch(function (param) {
                    MessageBox.error(param.message);
                });
            },
    
            getText: function (oEvent, type) {
                var that = this;
                return new Promise(function (resolved, rejected) {
                    var text = that.byId("idText").getValue();
                    return resolved(text);
                });
            }
        });
    });

    Explanation:

    In the above code onPressToClipboard gets text from the function getText, and passes it to the function createTextArea to create a HTML TextArea. The function insertTextArea would pass the TextArea would insert into HTML body. textArea.select() would select the text, and then execCommand would finally copy the selected text to the clipboard.

    Output

    Copy to Clipboard Integration in SAP UI5

  • SAP BTP Destination Access in SAP UI5

    Preface – This post is part of the UI5 Integration Programs series.

    What is the concept of Destination in SAP BTP?

    In SAP Business Technology Platform (SAP BTP), a destination is a configuration object that defines the connection parameters for accessing a service or system from SAP BTP.

    A destination is used as a way to define the communication settings for a service and to ensure secure access to the service. The destination defines the target URL of the service, the credentials that are used to access the service, and other configuration properties such as the communication protocol, message format, and security settings.

    Destinations can be used to access a variety of services such as Cloud Foundry applications, APIs hosted on SAP API Business Hub, and data sources like databases or SAP S/4HANA systems.

    In SAP BTP, you can manage destinations through the Destination service in the SAP Cloud Platform cockpit, where you can create, update, or delete destinations as needed.

    What are the different ways that we can create a Destination in SAP BTP?

    There are several ways to create a destination in SAP Business Technology Platform (SAP BTP):

    1. SAP Cloud Platform Cockpit: You can use the SAP Cloud Platform cockpit to create and manage destinations. This is the recommended method for creating destinations in SAP BTP, as it provides a user-friendly interface and ensures that the destinations are properly secured and configured.
    2. API: You can use the SAP Cloud Platform Destination API to programmatically create and manage destinations. This is useful when you need to automate the creation and management of destinations or when you need to integrate the creation and management of destinations into a custom application.
    3. SAP Cloud Platform Connectivity Service: You can use the SAP Cloud Platform Connectivity Service to create destinations, which is particularly useful when connecting to external systems from SAP BTP.
    4. SAP Cloud Platform Extension Factory: You can use the SAP Cloud Platform Extension Factory to create destinations for services hosted within your SAP BTP landscape. This is useful when you need to access services that are not directly available through the SAP Cloud Platform cockpit.

    Regardless of the method used to create a destination, it is important to properly secure the destination by defining the appropriate authentication and authorization settings. This ensures that the destination can be used securely to access the target service or system from SAP BTP.

    In this article, we will focus on the below integrations:

    • Neo Destination in SAP UI5
    • Cloud Foundry Destination in SAP UI5
    • Destination as a Service in SAP UI5

    Creating a Destination in SAP BTP

    1. Visit your BTP Platform by visiting here: https://account.hana.ondemand.com/#/home/welcome

    2. Create a new Destination for your API, in our case, we have created one for YouTube and another for Northwind.

    Destination Setup in SAP BTP for an API

    Northwind OData

    Destination Setup in SAP BTP for an OData

    How to Consume Neo Destination in SAP UI5

    To consume a destination in SAP UI5 from the Neo environment, you need to perform the following steps:

    1. Create a destination: You need to create a destination in the SAP Business Technology Platform (SAP BTP) using one of the methods described in my previous answer. Make sure the destination is properly configured and secured, just like the way we have done above. You can read more here.
    2. Add the destination to your SAP UI5 application in Neo.json File: You need to add the destination to your SAP UI5 application by creating a binding in the manifest.json file of your application. The binding provides the necessary information to connect to the destination, such as the URL and authentication credentials. Add the below section within “routes” array of neo-app.json
      {
            "path": "/destination/youtube",
            "target": {
              "type": "destination",
              "name": "Test",
              "entryPath": "/destination/youtube"
            },
            "description": "Test Destination"
          },
          {
            "path": "/destinations/northwind",
            "target": {
              "type": "destination",
              "name": "northwind"
            },
            "description": "Northwind OData Service"
          }

       

    3. Consume the destination from Controller File: In your SAP UI5 code, you can consume the destination by using the SAPUI5 framework’s OData model. You can create an instance of the OData model and pass it the URL of the destination as well as any additional configuration parameters, such as authentication credentials.

    Here is an example of how you can consume a destination in SAP UI5:

    // Get the URL of the destination from the binding
    var sServiceUrl = this.getOwnerComponent().getModel("destination").sServiceUrl;
    
    // Create an instance of the OData model
    var oModel = new sap.ui.model.odata.v2.ODataModel(sServiceUrl, {
        useBatch: true
    });
    
    // Set the OData model on the view
    this.getView().setModel(oModel);
    

    In this example, the destination URL is obtained from the binding created in the manifest.json file of the application. The OData model is then created and set on the view, allowing you to access the data provided by the destination in your SAP UI5 code.

    For YouTube, we can directly consume the URL even in view, like this:

    <html:iframe height="100%" width="100%" src="/destination/youtube"/>

    For Northwind, we have added the given code in:

    manifest.json

    "dataSources": {
                "NorthwindModel": {
                    "uri": "/destinations/northwind/V2/Northwind/Northwind.svc/",
                    "type": "OData",
                    "settings": {
                        "odataVersion": "2.0"
                    }
                }
            }
    
    

    And also set the model using the above dataSoruce

    "": {
        "type": "sap.ui.model.odata.v2.ODataModel",
        "settings": {
            "defaultOperationMode": "Server",
            "defaultBindingMode": "OneWay",
            "defaultCountMode": "Request"
        },
        "dataSource": "NorthwindModel",
        "preload": true
    },

    Controller.js

    sap.ui.define([
        "sap/ui/core/mvc/Controller"
    ], function (Controller) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            onInit: function () {
                var that = this;
                var oOdataModel = this.getOwnerComponent().getModel();
                oOdataModel.setUseBatch(false);
                oOdataModel.read("/Products", {
                    success: function (oData) {
                        that.getView().setModel(new sap.ui.model.json.JSONModel(oData), "customerModel");
                    }
                });
            }
        });
    });

     

    View.xml

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml" xmlns:table="sap.ui.table">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Consuming Neo Destination in SAP UI5">
                        <content>
                            <table:Table id="customerTable" selectionMode="Single" rows="{customerModel>/results}" enableColumnReordering="false">
                                <!--columns for Product Name-->
                                <table:columns>
                                    <table:Column width="20%">
                                        <table:label>
                                            <Label text="Product Name"/>
                                        </table:label>
                                        <table:template>
                                            <Text text="{customerModel>ProductName}"/>
                                        </table:template>
                                    </table:Column>
                                </table:columns>
                            </table:Table>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

    Output For Table Binding

    Table binding from Destination Integration

    How to Consume Cloud Foundry Destination in SAP UI5

    To consume a Cloud Foundry destination in SAP UI5, you can follow these steps:

    1. Create a destination: First, you need to create a destination in SAP Business Technology Platform (SAP BTP) for the Cloud Foundry service you want to access. You can do this through the SAP Cloud Platform cockpit or by using the SAP Cloud Platform Destination API. Make sure the destination is properly configured and secured. You can read more here.
    2. Add the destination to your SAP UI5 application: You need to add the destination to your SAP UI5 application by creating a binding in the manifest.json file of your application. The binding provides the necessary information to connect to the destination, such as the URL and authentication credentials.
      Add the following codes:
      xs-app.json

      {
            "authenticationType": "none",
            "csrfProtection": false,
            "source": "^/Northwind/(.*)$",
            "destination": "Northwind",
            "target": "$1"
          }

      OData services and Models in Manifest:

      "dataSources": {
          "mainService": {
              "uri": "/V2/Northwind/Northwind.svc/",
              "type": "OData",
              "settings": {
                  "annotations": [],
                  "localUri": "localService/metadata.xml",
                  "odataVersion": "2.0"
              }
          }
      }
      "": {
          "dataSource": "mainService",
          "preload": true,
          "settings": {}
      }

      ui5.yaml

      # yaml-language-server: $schema=https://sap.github.io/ui5-tooling/schema/ui5.yaml.json
      
      specVersion: "2.5"
      metadata:
        name: cfxsapp
      type: application
      server:
        customMiddleware:
          - name: fiori-tools-proxy
            afterMiddleware: compression
            configuration:
              ignoreCertError: false # If set to true, certificate errors will be ignored. E.g. self-signed certificates will be accepted
              ui5:
                path:
                  - /resources
                  - /test-resources
                url: https://ui5.sap.com
              backend:
                - path: /V2
                  url: https://services.odata.org
                  destination: Northwind
          - name: fiori-tools-appreload
            afterMiddleware: compression
            configuration:
              port: 35729
              path: webapp
              delay: 300
          - name: fiori-tools-preview
            afterMiddleware: fiori-tools-appreload
            configuration:
              component: cfxsapp
              ui5Theme: sap_horizon
      
    3. Consume the destination: In your SAP UI5 code, you can consume the destination by using the SAPUI5 framework’s OData model. You can create an instance of the OData model and pass it the URL of the destination as well as any additional configuration parameters, such as authentication credentials.
      View.xml

      <mvc:View controllerName="cfxsapp.controller.Main"
          xmlns:mvc="sap.ui.core.mvc" displayBlock="true"
          xmlns="sap.m">
          <Page id="page" title="{i18n>title}">
              <content>
              <List items="{/Products}">
              <StandardListItem title="{ProductName}"/>
              </List>
              </content>
          </Page>
      </mvc:View>
      

      Output
      How to Consume Cloud Foundry Destination in SAP UI5

    A good article for step-by-step setup reference: Creating a sample SAPUI5 application with destination in Cloud Foundry environment | SAP Blogs

    How to Consume a Destination as a Service in MTA or CAPM App

    To consume a destination as a service in an MTA or CAPM (Cloud Application Programming Model) application in the SAP Business Technology Platform (SAP BTP), you need to follow these steps:

    1. Create a destination: First, you need to create a destination in SAP BTP for the service you want to access. You can do this through the SAP Cloud Platform cockpit or by using the SAP Cloud Platform Destination API. Make sure the destination is properly configured and secured.
      Step 01: Visit SAP HANA on demand portal here.
      Step 02: Enter into your Global account and click “Service Market Place” as shown below:
      Service Market Place
      Step 03: Search for “Destination”
      Search for Destination Service
      Step 04: Click three dots to create a new instance
      Create Destination Service
      Step 05: Enter details and provide a name for your destination and click next
      Create New Instance or Subscription of Destination
      Step 06: Once created, you can see your destination within your instance
      Destination Instance
      Step 07: Click your instance and click “Manage Instance” to open Dashboard of your destination service
      Manage Destination
      Step 08: Create a new Destination as you would have created within the BTP Destination section
      Destination as a Service
    2. Bind the destination to your MTA or CAPM application: To bind the destination to your MTA or CAPM application, you need to add a destination service to your mta.yaml file for MTA applications or to your package.json file for CAPM applications. The service definition provides the necessary information to connect to the destination, such as the URL and authentication credentials.
    3. Consume the destination: In your application code, you can consume the destination by using the appropriate client library for the service you are accessing. For example, if you are accessing an OData service, you can use the SAPUI5 framework’s OData model to connect to the service.

    Here is an example of how you can consume a destination as a service in an MTA application:

    # mta.yaml
    
    _schema-version: "2.1"
    
    ID: my-mta
    
    version: 0.0.1
    
    modules:
      - name: my-module
        type: nodejs
        path: my-module
        requires:
          - name: my-destination-service
            group: destinations
            properties:
              name: my-destination-service
    
    resources:
      - name: my-destination-service
        type: org.cloudfoundry.managed-service
        properties:
          service: destination
          service-plan: lite
          parameters:
            name: my-destination
            url: "<destination-url>"
            forwardAuthToken: true
            apiEndpoint: "<destination-api-endpoint>"
    

    In this example, the destination is bound to the MTA application as a service by adding a resources section to the mta.yaml file. The service definition includes the properties necessary to connect to the destination, such as the destination URL, API endpoint, and whether to forward the authentication token.

    For our usecase, we have this code in MTA.yaml

    _schema-version: '3.2'
    ID: mtaApp
    version: 0.0.1
    modules:
      - name: mtaapp-approuter
        type: approuter.nodejs
        path: mtaapp-approuter
        requires:
          - name: mtaApp_html_repo_runtime
            group: destinations
            properties:
              forwardAuthToken: false
              name: ui5
              url: 'https://ui5.sap.com'
        parameters:
          disk-quota: 256M
          memory: 256M
      - name: mtaApp_ui_deployer
        type: com.sap.application.content
        path: .
        requires:
          - name: mtaApp_html_repo_host
            parameters:
              content-target: true
        build-parameters:
          build-result: resources
          requires:
            - artifacts:
                - cfapp.zip
              name: cfapp
              target-path: resources/
      - name: cfapp
        type: html5
        path: cfapp
        build-parameters:
          build-result: dist
          builder: custom
          commands:
            - npm install
            - 'npm run build:cf'
          supported-platforms: []
    resources:
      - name: mtaApp_html_repo_runtime
        type: org.cloudfoundry.managed-service
        parameters:
          service: html5-apps-repo
          service-plan: app-runtime
      - name: mtaApp_html_repo_host
        type: org.cloudfoundry.managed-service
        parameters:
          service: html5-apps-repo
          service-plan: app-host
      - name: NorthwindTest
        type: org.cloudfoundry.managed-service
        parameters:
          service: destination
          service-plan: lite
    parameters:
      deploy_mode: html5-repo

    In the end the code is added for Destination.

    Once the destination is bound as a service, you can consume it in your code by using the appropriate client library for the service you are accessing. For example, if you are accessing an OData service, you can use the SAPUI5 framework’s OData model to connect to the service.

  • Base64 to Image Converter using SAP UI5

    Preface – This post is part of the UI5 Integration Programs series.

    When do we need to convert a Base64 to Image

    You may need to convert a Base64 string to an image for various reasons, such as:

    1. Displaying images on a web page: If you have a Base64 encoded image and you want to display it on a web page, you can create an HTML img element and set its src attribute to the Base64 encoded image data.
    2. Storing images in databases: If you have Base64 encoded images stored in a database and you want to display them, you need to convert them back to an image format before displaying them.
    3. Saving images to the file system: If you have Base64 encoded images and you want to save them to the file system, you need to first decode the Base64 data and then write the resulting binary data to a file.
    4. Using images in image processing applications: If you want to use Base64 encoded images in image processing applications, you need to convert them back to an image format so that they can be processed.

    In each of these cases, you will need to decode the Base64 string and write the binary data to an image file in a format such as PNG or JPEG. The exact steps to convert a Base64 string to an image will depend on the programming language you’re using and the specific requirements of your project.

    Steps to convert a Base64 to Image using JavaScript

    Here are the steps to convert a Base64 string to an image using JavaScript:

    1. Split the Base64 string at the comma to extract the content type and data:

    const [type, data] = base64.split(",");
    

    2. Create a Blob object using the data and the content type:

    const blob = new Blob([data], { type });
    

    3. Create an URL for the Blob object using URL.createObjectURL:

    const url = URL.createObjectURL(blob);
    

    4. Create an HTML img element and set its src attribute to the URL:

    const image = new Image();
    image.src = url;
    

    5. Append the image to the page or use it in any other way you need:

    document.body.appendChild(image);
    

    Here’s a complete example that converts a Base64 string to an image and displays it on a page:

    const base64 = "data:image/png;base64,iVBORw0KG...";
    const [type, data] = base64.split(",");
    const blob = new Blob([data], { type });
    const url = URL.createObjectURL(blob);
    const image = new Image();
    image.src = url;
    document.body.appendChild(image);
    

     

    Steps to convert a Base64 to an Image using SAP UI5

    To convert Base64 to Image in SAP UI5 using the element Image and setting its source value, as shown below:
    View.xml
    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml" xmlns:l="sap.ui.layout" xmlns:f="sap.ui.layout.form" xmlns:RichTextEditor="sap.ui.richtexteditor">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Base64 to Image Converter using UI5">
                        <content>
                            <VBox class="sapUiSmallMarginBegin">
                                <HBox>
                                    <TextArea id="idBase64Area" value='Base 64 Value' editable="true" height="300px" width="500px" change="onChangeDP"/>
                                    <Title text="Your Image"/>
                                    <Image id="idDP" width="30%"/>
                                </HBox>
                            </VBox>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

     

    Controller.js
    sap.ui.define([
        "sap/ui/core/mvc/Controller"
    ], function (Controller) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            onChangeDP: function (oEvent) {
                var base64Data = this.byId("idBase64Area").getValue();
                this.byId("idDP").setSrc(base64Data);
            }
    
        });
    });

     

    Output
    Base64 to Image Converter using UI5