composes an array of functions into a function that passes a value through a pipeline of functions - ramda.js

Does anyone know how to do this ?
#compose pipeline
Q) composes an array of functions into a function that passes
a value through a pipeline of functions.
We need to create compose () as follows !
function compose(funcs) {
}
Example 1
javascript
const pipeline = [
(num) => num - 1,
(num) => num * 10,
(num) => `${ num } as a string`
];
const composed = compose(pipeline);
The output will be :--->
composed(4); // => `30 as a string`
Example 2
javascript
const pipeline = [
(str) => str.length,
(length) => length * 100,
(num) => num + 5
];
const composed = compose(pipeline);
composed('cat'); // => 305

Related

Cypress: save result, then perform web actions, then compare initial result with end result after actions

I would appreciate some help: 1) I am obtaining the total number of items in a list, 2) I perform an action in the website that should remove one item in the list and 3) I need to check that the item is discounted from the list (total items - 1)
static Counter() {
cy.get('.page-number > span')
.invoke('text')
.then((s) => {
return s.match(/([\d\.]*)$/gmi)[0]
}).then(parseInt).should('be.a', 'number')
}
describe('Compare totals before/after performing web actions', () => {
it('Store & compare', () => {
const before = Counter()
//Perform actions in the web
const after = Counter()
expect(after == before - 1).to.equal(true) //?!
})
})
Thank you very much in advance!
I got it if useful:
describe('Compare totals before/after performing web actions', () => {
it.only('Store & compare', () => {
cy.get('.page-number > span')
.invoke('text')
.then((s) => {
//Trim the text: number is mixed with text=> | 1-25 / 10000 +
const u = s.match(/([\d\.]*)$/gmi)[0]
cy.log('u =', u) //√
//perform action that discounts one item from the list [...]
cy.get('.page-number > span')
.invoke('text')
.then((s) => {
//Trim the text: number is mixed with text=> | 1-25 / 10000 +
const p = s.match(/([\d\.]*)$/gmi)[0]
cy.log('p =', p)
expect(p, 'Total before').equal(u + 1, 'Total after')
})
}) //.then(cy.log)

Multiple props in Ramda lens

Is there a way to apply transforms to multiple keys of an object in Ramda? I am aware this is achievable by R.evolve, but I am interested in knowing if this can be achieved by some modification of lenses.
E.g.:
const data = {
a: "100",
b: "non_numeric_string",
c: "0.5"
}
const numerize = x => +x
const mapping = {
a: numerize,
c: numerize
}
magicFunction(mapping, data)
output:
{
a: 100,
b: "non_numeric_string",
c: 0.5
}
The whole point of a lens is to focus on one part of a data structure. While it is not hard to write something using lensProp to achieve this, I'm don't think it's either very satisfying or a particularly appropriate use of lenses. Here's one Ramda solution:
const magicFunction = (mapping, data) =>
reduce
( (o, [k, fn]) => over (lensProp(k), fn, o)
, data
, toPairs (mapping)
)
const numerize = x => Number (x)
const mapping = {
a: numerize,
c: numerize
}
const data = {a: "100", b: "non_numeric_string", c: "0.5"}
console .log (
magicFunction (mapping, data)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script> const { lensProp, over, reduce, toPairs } = R </script>
But note that a plain ES6 function does the job just as simply, without using lenses:
const magicFunction = (mapping, data) =>
Object.entries (mapping). reduce
( (o, [k, fn]) => ({...o, [k]: fn (o [k]) })
, data
)
Lenses simply don't gain you much here.

custom sum elements by key using lodash

I do have two objects containing keys like
var a = {bar:[1,2], foo:[7,9]}
var b = {bar:[2,2], foo:[3,1]}
I want to get the fallowing results:
var c = {bar:[3,4], foo:[10,10]}
I already have a for logic like:
for (let key in b) {
if (a[key]) {
a[key][0] += b[key][0];
a[key][1] += b[key][1];
}
else a[key] = b[key];
}
But I would like to make this logic in a lodash way. How can I Do it?
You can use create a function that takes n objects, and collects them to an array using rest parameters. Now you can spread the array into _.mergeWith() to combine the objects, and in the customizer function sum the items in the arrays using Array.map() or lodash's _.map() and _.add():
const { mergeWith, isArray, map, add } = _
const fn = (...rest) => _.mergeWith({}, ...rest, (o = [], s) =>
map(s, (n, i) => add(n, o[i]))
)
const a = {bar:[1,2], foo:[7,9]}
const b = {bar:[2,2], foo:[3,1]}
const c = {bar:[3,2], foo:[5,6]}
const d = {bar:[4,2], foo:[5,4]}
const result = fn(a, b, c, d)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
You can also use lodash/fp to create a function that merges all values to a multidimensional array with _.mergeAllWith(), then transpose the arrays using _.zipAll(), and sums each array:
const { rest, flow, mergeAllWith, isArray, head, mapValues, zipAll, map, sum } = _
const fn = rest(flow(
mergeAllWith((o, s) => [...isArray(head(o)) ? o : [o], s]), // combine to a multidimensional array
mapValues(flow(
zipAll,
map(sum)
)),
))
const a = {bar:[1,2], foo:[7,9]}
const b = {bar:[2,2], foo:[3,1]}
const c = {bar:[3,2], foo:[5,6]}
const d = {bar:[4,2], foo:[5,4]}
const result = fn(a, b, c, d)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
You can accomplish this using plain JavaScript with Object.entries, concat and reduce:
const a = { bar: [1,2], foo: [7,9] };
const b = { bar: [2,2], foo: [3,1] };
const entries = Object.entries(a).concat(Object.entries(b));
const result = entries.reduce((accum, [key, val]) => {
accum[key] = accum[key] ? accum[key].map((x, i) => x + val[i]) : val;
return accum;
}, { });
console.log(result);

what is returned by Engine_Api::_()->getTable

I wonder if it is an array that is returned by calling getTable('tbl', 'module') or an object. I am facing problems when I try to insert the returned value into another array and then encode it as JSON. Passing it per se to $this->_helper->json() generates JSON output successfully, but using it as part of another array just does not work and is a null array. See below for the controller code:
//put your code here
public function indexAction () {
}
public function browseAction () {
$resultArray = $this->prepareArray();
$this->sendResponse($resultArray);
}
/**
* HTTP Response Codes
*/
const HTTP_OK = 200;
public function sendResponse($data) {
ob_clean();
$this->_helper->json($data);
}
public function prepareArray() {
//Here we will prepare the array to be later encoded as JSON
$responseArray = [
'status_code' => '',
'body' => [
'itemsCount' => '',
'foods' => [
'food_id' => '',
'food_title' => '',
'image' => '',
],
],
];
$foodTable = Engine_Api::_()->getDbTable('foods', 'restapi');
$foods = $foodTable->getFoods($this->view);
$foodArray = [];
print_r($foods);
while ($row = mysqli_fetch_row($foods)) {
$foodArray['food_id'] = $row['food_id'];
$foodArray['food_title'] = $row['title'];
$foodArray['image'] = $row['image'];
}
error_log( $row ['food_id'] . ',' . $row['title']);
$responseArray['status_code'] = '200';
$responseArray['body']['itemsCount'] = count($foods);
$responseArray['body']['foods']= $foodsArray;
return $responseArray;
}
If everything is set properly, getTable('tbl', 'module') returns object(Module_Model_DbTable_Tbl). This is the model of your database table.
Your particular error is on the line where you're assigning foodsArray variable that isn't defined anywhere. You should have assign foodArray here instead.
$responseArray['body']['foods']= $foodsArray; // should be foodArray

Passwords in SSL with Jetty tutorial

In this tutorial , where are the following values coming from?
password (OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4)
keyPassword (OBF:1u2u1wml1z7s1z7a1wnl1u2g)
trustPassword (OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4)
Someone (ack_ of the Norn Iron Hacker Scene) made a Python script to reverse the Jetty password obfuscation. Useful when you need to export the keystore to other programs.
# Jetty Deobfuscation Tool
from __future__ import print_function
import sys
def deobfuscate_jetty(ciphertext):
plaintext = ""
for i in range(0, len(ciphertext), 4):
t = ciphertext[i:i + 4]
i0 = int(t, 36)
i1, i2 = divmod(i0, 256)
x = (i1 + i2 - 254) >> 1
plaintext += chr(x)
return plaintext
if __name__ == '__main__':
if len(sys.argv) == 2:
print(deobfuscate_jetty(sys.argv[1]))
else:
print("Jetty Deobfuscation Tool v1.0")
print("%s <string>" % sys.argv[0])
exit(1)
The passwords prefixed with OBF: come from Jetty's own system for obfuscating passwords. There is more documentation here: http://wiki.eclipse.org/Jetty/Howto/Secure_Passwords
Note that this is obfuscated and not encrypted. It just prevents a human from reading it quickly:
In some cases such as keystore passwords and digest authentication,
the system must retrieve the original password, which requires the
obfuscation method. The drawback of the obfuscation algorithm is that
it protects passwords from casual viewing only.
You could put them in clear too, it wouldn't change much.
In this case, the password, keyPassword and trustPassword are respectively the passwords for the key store, the key password (that should be optional if it's the same as the key store password) and the trust store password. These are the ones you set when you create these keystores.
This was driving me kind of crazy too. Here's a script that you can use to generate the various passwords. The script works with this particular version of jetty: jetty-hightide-8.1.10.v20130312, but can be modified through the JETTY_VER variable.
jetty-passwd.sh
#!/bin/bash
# url: http://wiki.eclipse.org/Jetty/Howto/Secure_Passwords
# set -x
if [ $# -ne 2 ]; then
echo -e "\nUSAGE: `basename $0`: <user> <password>\n";
exit 0;
fi
JETTY_VER=8.1.10.v20130312
JETTY_HOME=/opt/jetty-hightide-$JETTY_VER
java -cp $JETTY_HOME/lib/jetty-util-${JETTY_VER}.jar org.eclipse.jetty.util.security.Password $1 $2
example run
% ./jetty-passwd.sh me blah
blah
OBF:1t2x1toq1to41t39
MD5:6f1ed002ab5595859014ebf0951522d9
CRYPT:me/DjMjPzbKG.
The following function is an ES6 port of the Python function by Thilo. It could be used to deobfuscate a password on a Node server.
I also added an obfuscation method that I adapted from: arthepsy/deobf/jetty.obf.py
In addition, I added some mocha/chai tests to run through random passwords verify that the obfuscate/deobfuscate methods are symetric.
const
clipText = (str, length) => `${str.slice(0, length)}…`,
fill = (size, fn) => new Array(size).fill(0).map((_, i) => fn ? fn(i) : i);
/** test.js */
const main = () => {
const
generator = new PasswordGenerator({ symbols: true, length: 16 }),
passwords = fill(100, () => generator.next());
mocha.setup('bdd');
chai.should();
describe('Test JettyUtil', () =>
passwords.forEach(pw => {
const
ciphertext = JettyUtil.obfuscate(pw),
plaintext = JettyUtil.deobfuscate(ciphertext);
it(clipText(`${pw} → ${ciphertext}`, 64), () =>
pw.should.equal(plaintext))
}));
mocha.run();
};
/** jetty-util.js */
const
OBF_PREFIX = 'OBF:',
divmod = (m, n) => [ Math.trunc(m / n), m % n ],
unpack = (str) => str.split('').map(c => c.charCodeAt(0) & 0xFF),
chunk = (str, size) => str.match(new RegExp(`.{1,${size}}`, 'g'));
class JettyUtil {
static deobfuscate(ciphertext) {
return chunk(ciphertext.slice(OBF_PREFIX.length), 4)
.reduce((plaintext, i0) => {
const [ i1, i2 ] = divmod(parseInt(i0, 36), 256);
return plaintext + String.fromCharCode((i1 + i2 - 254) >> 1);
}, '');
}
static obfuscate(plaintext) {
return unpack(plaintext).reduce((ciphertext, b1, index, bytes) => {
const b2 = bytes[bytes.length - (index + 1)],
[ i1, i2 ] = [ 127 + b1 + b2, 127 + b1 - b2 ];
return ciphertext + (i1 * 256 + i2).toString(36).padStart(4, '0');
}, OBF_PREFIX);
}
}
// export default JettyUtil;
/** password-generator.js */
const Alphabet = {
UPPERCASE : 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
LOWERCASE : 'abcdefghijklmnopqrstuvwxyz',
NUMBERS : '0123456789',
SYMBOLS : ' !"#$%&\'()*+,-./:;<=>?#[\]^_`{|}~'
};
class PasswordGenerator {
constructor(config) {
this.opts = { ...PasswordGenerator.defaultOptions, ...config };
this.alphabet = Object.entries(this.opts)
.map(([k, v]) => v === true ? Alphabet[k.toUpperCase()] : null)
.filter(v => v != null)
.join('');
}
next() {
return fill(this.opts.length, () => rando(this.alphabet)).join('');
}
}
PasswordGenerator.defaultOptions = {
uppercase : true,
lowercase : true,
numbers : true,
symbols : false,
length : 12
};
// export default PasswordGenerator;
main();
.as-console-wrapper { top: 0; max-height: 100% !important; }
<script src="https://randojs.com/2.0.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/7.2.0/mocha.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/mocha/7.2.0/mocha.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/4.2.0/chai.min.js"></script>
<div id="mocha"></div>
Here is my original response:
const divmod = (m, n) => [ ~~(m / n), m % n ];
const deobfuscate = (ciphertext) => {
if (!ciphertext.startsWith('OBF:')) return null;
let plaintext = '';
for (let offset = 4; offset < ciphertext.length; offset += 4) {
const i0 = parseInt(ciphertext.slice(offset, offset + 4), 36);
const [ i1, i2 ] = divmod(i0, 256);
plaintext += String.fromCharCode((i1 + i2 - 254) >> 1);
}
return plaintext;
};
const pwList = [
'OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4', // storepwd
'OBF:1u2u1wml1z7s1z7a1wnl1u2g', // keypwd
];
pwList.forEach(pw => console.log(deobfuscate(pw)));