If you are running multiple WiFI APs that are part of the same flat network and bridged together it can be tricky keeping a current list of which client is connected to which AP (sometimes clients can just stop responding on one AP and then wake up and appear on another AP). In addition, the one common question a router needs to know is, is this client connected to me OR are they connected through one of my peer routers and which one is the best one?… I wrote a small service which allows an AP to periodically broadcast out, relay/forward, and receive the current WiFi client associations it has and the best association is chosen to amongst all the APs to be able to keep a common set of ARP entries for each access point! The tables are way cleaner and way more consistent with each other now that I have this thing running. I wrote it in both C and python which are supported on OpenWRT routers and can communicate with each other using a common key/pwd. You simply list which radio interfaces the AP has and the IP address you gave the AP on the flat network and it should be ready to send, forward, & receive ARP related messages. The program will write out a standard file with the following information formatted in it and it can also be used with the relayd service modification post below:
If you are bridging 2+ wireless networks together, it can get tricky for the ARP mappings to take place efficiently throughout the network as you move around from AP to AP. I wrote a small shell script that runs on each router which reports in its WiFi-AP associations & DHCP entries that are part of the overall /20 network. This client mapping data is sent around to each router to determine who has the proper client and where/how to find them. I noticed that the relayd bridging app was putting in ARP entries that were becoming stale/incorrect over time as you moved around so I modified it’s source code to outsource this work to a file that has an updated master set of static interface entries based on each DHCP/WIFI association for each router on the network.
(I lost access to my fossjon github account due to 2-factor auth being lost)
(the steps to compile this on a armv7l router itself are in the README I added)
For example, a shell script running on the router (with all the relevant network information) can determine and write out a small mapping file that this modified framework can use to keep a cleaner and better ARP tableset (/tmp/arp.txt):
wlan1 00:2b:3d:5a:4a:9e 192.168.18.103
The added capability in relayd will then ensure that for any of the bridged interfaces listed, the only ARP entry that will exist is for the one specified in the file and that it will be set to permanent status instead (deletion of incorrect entries added in).
I am running this as a test on my parents home network to see how long it lasts for, modifying C is tricky for me! 🙂
So during this quarantine break I was setting up a new network layout for my parents place which includes 2 wireless OpenWRT routers connected together via an 802.11ac channel. Each wifi router broadcasts an 802.11n AP which has the same SSID & KEY but on different CHANNELS and BSSIDS. The traffic can be forwarded back and forth between the 2 separate APs via the single private AC connection (using the OWRT relayd package):
/usr/sbin/relayd -I wlan1 -I wlan0 -t -1 -p -1 -B
Each AP has dnsmasq running, however, they are each set to hand out a subset of unique addresses that are shared in a /20 block (so that whatever AP you are on, you can communicate to any other host on any of the APs as if you are on the same network). I noticed that when switching between the 2 APs, my machine was getting the same last octet in the IP range set! I thought this was pretty cool because even though the rest of the IP prefix was different, I could simply memorize the last digits if I wanted to connect to another machine on the network in the future. I then started looking into dnsmasq’s source code to see how it was doing this since the only info DHCP usually has is one’s MAC address:
…note: they added a fix for the j variable recently: j= instead of j+=…
…note: note: there is a IP loop and epoch counter variable that gets increased in case of any hashing collisions or errors that occur!
So if you compile the code below and want to pre-calculate your likely IP address when asking dnsmasq for one, you can run the following (you need to know the IP range that was given in your configs):
# cipher design notes:
## purpose?
### cheap single byte keyed stream cipher
### cheaply obfuscate data based on a simple password
### use a simple language with as few lines & dependencies as possible
## internal key setup:
### produce a random byte for every pw byte (KEY IV)
### generate a secret internal state byte for every pw byte (KEY HASH):
#### loop through the each pw byte & mix together its random byte & a counter value
#### set the final looped result as the state byte for that key byte
#### order the operations used to try & reduce getting a null byte output
#### end the internal state byte with the current counter value mixed in (CBC MODE)
## message cipher steps:
### use the looped key counter above as an index to get a key list item
### XOR the message byte with each byte in key item: random byte, pwd byte, state byte
### mix the cipher byte in with the internal state byte (new secret internal state)
### XOR the prior internal state byte with the cipher byte (cipher output)
## notes:
### this does not prevent or detect bit-flipping (integrity with a hash function)
import sys, random
def h(n):
sys.stdout.write(hex(n).replace("x","")[-2:])
i=0xff; j=0x00; l=len(sys.argv[1]); s=sys.stdin.read()
if (s[:2]=="ff"):
r=s[2:2+(l*2)]; t=s[2+(l*2):].strip()
s="".join([chr(int(t[x:x+2],16)) for x in range(0,len(t),2)])
k=[[int(r[x*2:(x*2)+2],16), ord(sys.argv[1][x])] for x in range(0,l)]
else:
k=[[random.randint(0x00, 0xff), ord(d)] for d in sys.argv[1]]
h(i); z=[h(d[0]) for d in k]; r=""
for e in k:
for d in k:
i=(((i+j)*(d[0]^d[1]))%256); j=((j+1)%256)
e.append(i); i=((i+j)%256); j=((j+1)%256)
j=0
for c in s:
p=ord(c); m=k[j%l]; o=(((p^m[0])^m[1])^m[2]); j=(j+1); n=(j%256)
if (r==""):
t=i; i=((k[o%l][0]+o+n)%256); o=(o^t); h(o)
else:
d=(p^i); t=i; i=((k[d%l][0]+d+n)%256); o=(o^t); sys.stdout.write(chr(o))
# notes: PoC, single threaded, single client, single interface, single address, ipv4 over tcp
#
# server: python tun.py -s 0.0.0.0 31337 key
# ('[conn]:new', [socket._socketobject object at 0xb6b20c00], ('192.168.160.241', 64227))
# ('[auth]:good', [socket._socketobject object at 0xb6b20c00])
#
# client: python tun.py -c 1.2.3.4 31337 key
# client: route add -host 1.2.3.4 [real gateway]
# client: route add -net 0.0.0.0/0 10.0.0.1
# client: host yahoo.com 4.2.2.1
#!/usr/bin/python
import os, sys
import ctypes, fcntl, struct
import select, socket, subprocess
import time, random, hashlib
def tclose(sobj):
try:
sobj.close()
except:
pass
def ksa4(k):
s = []
for i in range(0, 256):
s.append(i)
j = 0
l = len(k)
for i in range(0, 256):
j = ((j + s[i] + ord(k[i % l])) % 256)
t = s[i]; s[i] = s[j]; s[j] = t
return (s, 0, 0)
def arc4(m, k):
(s, i, j) = k
l = len(m)
o = ""
for x in range(0, l):
i = ((i + 1) % 256)
j = ((j + s[i]) % 256)
t = s[i]; s[i] = s[j]; s[j] = t
c = s[(s[i] + s[j]) % 256]
o += chr(ord(m[x]) ^ c)
k = (s, i, j)
return (o, k)
def set4(n, k):
if (n == ""):
n = (str(time.time()) + ":" + str(random.random()) + "-")
s = ksa4(n + "s" + k)
r = ksa4(n + "r" + k)
(null, s) = arc4("x"*4096, s)
(null, r) = arc4("x"*4096, r)
return (n, s, r)
def client(h, p, n, k):
f = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
f.connect((h, p))
(enc, k) = arc4(n, k)
f.send(n + enc)
return (f, k)
# initialize some common variables
BUFFER_SIZE = 2000
PR_MODE = "client"
PR_HOST = "1.2.3.4"
PR_PORT = 31337
PR_SKEY = "key"
OS_TYPE = sys.platform
IF_CMD = ["/sbin/ifconfig", "tun0", "10.0.0.1", "10.0.0.2", "up"]
# process command line args usage: tun.py mode:[-c,-s] ip:[0.0.0.0] port:[4321] secret:[key]
if (sys.argv[1] == "-s"):
PR_MODE = "server"
PR_HOST = sys.argv[2]
PR_PORT = int(sys.argv[3])
PR_SKEY = sys.argv[4]
# initialize the clients secret key state
last = 0
(nonce, skey, rkey) = set4("", PR_SKEY)
# define the remote connection socket descriptors - tcp client or tcp server
srv_fd = None
net_fd = None
if (PR_MODE == "client"):
tmp = IF_CMD[2]
IF_CMD[2] = IF_CMD[3]
IF_CMD[3] = tmp
(net_fd, skey) = client(PR_HOST, PR_PORT, nonce, skey)
else:
srv_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv_fd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv_fd.bind(("0.0.0.0", PR_PORT))
srv_fd.listen(1)
# determine how to bring up the tun0 interface - mac or linux
if (OS_TYPE == "darwin"):
tun_fd = os.open("/dev/tun0", os.O_RDWR)
else:
TUNSETIFF = 0x400454ca
IFF_TUN = 0x0001
IFF_TAP = 0x0002
IFF_NO_PI = 0x1000
tun_fd = os.open("/dev/net/tun", os.O_RDWR)
ifr = struct.pack("16sH", "tun0", IFF_TUN | IFF_NO_PI)
fcntl.ioctl(tun_fd, TUNSETIFF, ifr)
IF_CMD.insert(3, "pointopoint")
subprocess.call(IF_CMD)
# main processing loop for network traffic tunneling
conns = []
while (1):
#print("loop")
# set the list of available socket descriptors to listen for
fd_list = [tun_fd]
if (srv_fd):
fd_list.append(srv_fd)
if (net_fd):
fd_list.append(net_fd)
for conn in conns:
fd_list.append(conn)
# select the available fds ready for reading
rd = select.select(fd_list, [], [])
# loop through each socket now to process each action
for ready_fd in rd[0]:
# if we are reading from our tun device then encrypt the message and write it to the network socket
if (ready_fd == tun_fd):
packet = os.read(tun_fd, BUFFER_SIZE)
plen = len(packet)
if ((plen > 0) and (net_fd)):
(enc, skey) = arc4(packet, skey)
smac = str(skey)
hmac = hashlib.sha256(smac + enc + smac).digest()
net_fd.send(enc + hmac)
# if the server gets a new client connection then add it to a list to be authenticated next
if (ready_fd == srv_fd):
(conn, addr) = srv_fd.accept()
print("[conn]:new",conn,addr)
conns.append(conn)
# if we get a network message decrypted and authenticated then write it to our tunnel device
if (ready_fd == net_fd):
data = net_fd.recv(BUFFER_SIZE)
dlen = len(data)
if (dlen > 0):
try:
temp = data[:-32]
(dec, tkey) = arc4(temp, rkey)
tmac = str(tkey)
hmac = hashlib.sha256(tmac + temp + tmac).digest()
if (hmac == data[-32:]):
rkey = tkey
os.write(tun_fd, dec)
else:
print("[hmac]:fail",hmac,data[-32:])
except:
dlen = 0
if (dlen < 1):
tclose(net_fd)
net_fd = None
# loop through any unauthenticated clients who have sent us data
tmps = []
conl = (len(conns) - 1)
while (conl > -1):
conn = conns[conl]
# if the connection is ready
if (ready_fd == conn):
data = conn.recv(BUFFER_SIZE)
dlen = len(data)
indx = data.find("-")
# if they sent us some actual data
if ((dlen > 0) and (indx > -1)):
# try to decrypt the nonce and verify an increase in the time
try:
temp = float(data.split(":")[0])
except:
temp = 0
(tnonce, trkey, tskey) = set4(data[:indx+1], PR_SKEY)
(dec, trkey) = arc4(data[indx+1:], trkey)
# if the auth succeeds then setup the new key state and set the new client socket
if ((temp > last) and (tnonce == dec)):
print("[auth]:good",conn)
nonce = tnonce
skey = tskey
rkey = trkey
tclose(net_fd)
net_fd = conn
last = temp
conns[conl] = None
else:
dlen = 0
else:
dlen = 0
# if the auth failed then remove the client now
if (dlen < 1):
print("[auth]:fail",conns[conl])
tclose(conns[conl])
conns[conl] = None
if (conns[conl]):
tmps.append(conns[conl])
conl -= 1
conns = tmps[:]
The Nintendo (NES) with the square controller is back!
Hopefully I can save up some money one day to purchase one when they are in stock…
I miss the classic Super Mario Bros levels 🙂
So I went to an interview recently and I was asked on the spot how I would implement an entire agile development platform, end-to-end, with specific details, (no requirements listed) – and it had to be cloud friendly/scalable! I was running different ideas through my head because it was a fairly open ended question and I felt like it deserved more thought than I could provide in just the 30 minutes given to me…
There are a dozen different ways this can be achieved but I wanted to post an example proof-of-concept of the essential steps needed to accomplish something like this. There are basically 5 different pieces to this puzzle that need to be solved:
The developers need a central repository with local branching capabilities so they can test different versions of their changes on demand
They need to be able to take an automatic snapshot of their code base that they are currently working on so they can specify which change they want to test
They need a simple mechanism, which when triggered, takes that code-change snapshot and sends it to a build server for compilation
The build server, when finished, should deploy and run their compiled test code, usually in a temporary, clean, isolated environment like a vm
The build server returns a simple and unique URL pointing to their new test instance so the developer can easily see and test their desired changes
Example Tech Env: GIT, SSH, NetCat, Bash Scripts, Java
# get the code
git clone ssh://jon@buildsrv:/home/git/projects
# make a change
cd project/
vim src/program.java
# @@ -11,5 +11,6 @@ public class program {
# System.out.println(x+": "+resList.get(x));
# }
# + System.out.println("Changed!");
# }
# }
./make.sh # magic!
# this script tar's up the current code and connects to the server to run an init.sh bootstrap script
# the init.sh script chooses an initial random port and calls the deploy.sh script
# to perform the snapshot code transfer
# the deploy.sh script opens a netcat port to receive the snapshot'd code
# and then runs build.sh on the result (port is closed after)
# the build.sh script opens a netcat port to communicate the build results
# and then runs a http netcat instance of the executed code for the developer to test/visit
[automated build, deploy, test instance]
Extracting build...
./src/
./src/dep.java
./src/program.java
Extraction completed!
Building started...
Build completed!
Visit the build URL below:
http://192.168.161.2:29792/testing
[example web change test output]
Fri Nov 11 05:22:10 UTC 2016
0: [A, D]
1: [B, E]
2: [C, F]
Changed!
Completed!
package lib;
import java.util.*;
public class dep {
public dep() {
}
public static ArrayList merge(ArrayList listA, ArrayList listB) {
ArrayList outList = new ArrayList();
for (int x = 0; x < listA.size(); ++x) {
ArrayList tmpList = new ArrayList();
tmpList.add(listA.get(x));
tmpList.add(listB.get(x));
outList.add(tmpList);
}
return outList;
}
}
[src/program.java]
import java.util.*;
import lib.dep;
public class program {
public static void main(String[] args) {
ArrayList inA = new ArrayList();
ArrayList inB = new ArrayList();
inA.add("A"); inA.add("B"); inA.add("C");
inB.add("D"); inB.add("E"); inB.add("F");
dep help = new dep();
ArrayList resList = help.merge(inA, inB);
for (int x = 0; x < resList.size(); ++x) {
System.out.println(x+": "+resList.get(x));
}
}
}
import sys,time
def hexs(s):
o = ""
for c in s:
h = hex(ord(c))[2:]
if (len(h) < 2):
h = ("0" + h)
if (o != ""):
o += ":"
o += h
return o
def nice(s):
o = ""
for i in range(0, len(s)):
if (i > 0):
if ((i % 16) == 0):
o += "\n "
else:
o += ":"
t = str(s[i])
while (len(t) < 3):
t = ("0" + t)
o += t
return o
def rnds():
n = 2; s = ""
while ((int(time.time()) % n) != 0):
pass
while (len(s) != 32):
time.sleep(1)
r = 0
while ((int(time.time()) % n) != 0):
r = (r + 1)
#sys.stderr.write("r="+str(r)+"\n");break
s = (s + chr((r >> 8) & 0xff) + chr(r & 0xff))
return s
if (len(sys.argv) < 2):
h = rnds()
sys.stderr.write("k="+hexs(h)+"\n")
else:
def keys(k):
s = []
for x in range(0, 256):
s.append(x)
for y in range(0, len(k)):
l = ord(k[y])
for x in range(0, 256):
t = s[x] ; s[x] = s[l] ; s[l] = t
l = ((l + x) % 256)
return s
s = keys(sys.argv[1])
if (len(sys.argv) > 2):
sys.stderr.write("s="+nice(s)+"\n\n")
def ciph(m, s, z):
j = 0; o = ""
for y in range(0, len(m)):
l = ord(m[y])
c = (l ^ s[y % 256])
o += chr(c)
i = l
if (z == "d"):
i = c
j = ((j ^ i) % 256)
for x in range(0, 256):
t = s[x] ; s[x] = s[j] ; s[j] = t
j = ((j + x) % 256)
return o
if (len(sys.argv) < 3):
m = sys.stdin.read()
z = "d"
else:
m = sys.argv[2]
z = "e"
o = ciph(m, s, z)
if (len(sys.argv) > 2):
sys.stderr.write("m="+hexs(o)+"\n")
sys.stdout.write(o)
LinkedIn recently disabled it’s third party APIs which took out an auto-resume builder service based on my public profile. I wrote some JS to try and at least generate a basic resume from my LinkedIn profile now:
From LinkedIn Profile -to- a simple clean resume! with just a little bit of effort! (done in Safari with print-to-PDF graphics enabled & headers disabled): –
/* https://www.linkedin.com/public-profile/settings */
/* zoom: 99% || move: 195,75,55 */
var font = [9, 11, 13, 15, 17, 19];
var mail = ["root@fossjon.com", "jon.chiappetta@gmail.com"];
var webs = ["fossjon.com", "star.fossjon.com"];
var gits = ["github.com/fossjon", "github.com/stoops"];
var imgs = {};
function hide(objc) {
console.log("hide:",objc);
try { objc.parentNode.removeChild(objc); } catch(e) { /* no-op */ }
}
function tnls(idls) {
var outp = [];
for (var j = 0; j < idls.length; ++j) {
var l = document.getElementsByTagName(idls[j]);
for (var i = 0; i < l.length; ++i) {
outp.push(l[i]);
}
}
return outp;
}
function cnls(idls) {
var outp = [];
for (var j = 0; j < idls.length; ++j) {
var l = document.getElementsByClassName(idls[j]);
for (var i = 0; i < l.length; ++i) {
outp.push(l[i]);
}
}
return outp;
}
function nols(objc) {
var outp = [];
var l = objc.childNodes;
for (var i = 0; i < l.length; ++i) {
try {
if (l[i].tagName.toLowerCase() != "") {
outp.push(l[i]);
}
} catch (e) { /* no-op */ }
}
return outp;
}
var s = 0, q = 0;
function y() {
if (s == 0) { window.scrollTo(0, 0); }
if (s < document.body.scrollHeight) {
// scroll
window.scrollBy(0, 125); s += 125;
setTimeout(y, 0.125 * 1000);
} else {
if (q == 0) { q = 1; z(); }
else { window.scrollTo(0, 0); }
}
}
function u() {
var p = document.getElementsByClassName("cover-img");
if (p.length > 0) {
p[0].style.marginLeft = "-2px";
p[0].style.marginRight = "-2px";
}
}
function z() {
document.title = "resume";
document.body.setAttribute("style", "background-color:white !important; padding:1px !important; margin:1px !important;");
// hide
var l = [
"global-nav__a11y-menu", "global-nav", "header", "li-footer", "global-footer", "right-rail",
"msg-overlay-container", "pv-top-card__photo-wrapper", "pv-open-to-carousel", "artdeco-carousel__content",
"profile-topcard-background-image-edit__icon", "scaffold-layout-toolbar", "scaffold-layout__aside",
"settings-header", "pp-section activities", "pp-section recommended-content", "pp-section languages"
];
for (var i = 0; i < l.length; ++i) {
var a = document.getElementById(l[i]);
hide(a);
var b = document.getElementsByClassName(l[i]);
while (b.length > 0) {
hide(b[0]);
b = document.getElementsByClassName(l[i]);
}
}
var l = tnls(["button"]);
for (var i = 0; i < l.length; ++i) {
if (l[i].innerText && l[i].innerText.match(/^.*(see|show) more.*$/mig)) {
l[i].click();
}
}
var l = tnls(["button"]);
for (var i = 0; i < l.length; ++i) {
if (l[i].innerText && l[i].innerText.match(/^.*(see|show) less.*$/mig)) {
l[i].setAttribute("style", "display:none !important;");
}
}
// high
var p = document.getElementsByClassName("authentication-outlet");
if (p.length > 0) {
p[0].setAttribute("style", "background:white !important; padding-top:1px !important; padding-bottom:256px !important;");
}
// wide
var p = document.getElementById("main-content");
if (p) {
var w = (p.parentNode.offsetWidth * 0.95);
p.setAttribute("style", "margin-left:3px !important; margin-right:3px !important; padding-left:3px !important; padding-right:3px !important; width:" + w + "px !important;");
}
var p = document.getElementsByClassName("core-rail");
if (p.length > 0) {
var w = (p[0].parentNode.offsetWidth * 0.95);
p[0].setAttribute("style", "margin-left:3px !important; margin-right:3px !important; padding-left:3px !important; padding-right:3px !important; width:" + w + "px !important;");
}
// dots + imgs
var f = 1;
while (f == 1) {
f = 0;
var l = tnls(["p"]);
for (var i = 0; i < l.length; ++i) {
var h = l[i].innerHTML; if (!h) { continue; }
var t = l[i].getElementsByClassName("mods-html");
if (t.length > 0) { continue; }
while (h.match(/^.*••.*$/mig)) {
h = h.replace(/••([^<>\r\n]+)/mig, "<div style='display:inline-flex; padding-left:25px; flex:1em;'>•$1</div>");
}
if (h.match(/^.*[^;&]•[^;&].*$/mig)) {
h = h.replace(/•([^<>\r\n]+)/mig, "<div style='display:inline-flex; padding-left:5px; flex:1em;'><b style='/*font-size:" + font[5] + "px;*/'> • </b><div style='display:inline-flex; padding-left:1px; flex:1em;'>$1</div></div>");
}
for (var k in imgs) {
if (h.includes("["+k+"]")) {
h = h.replace("["+k+"]", "<div><img class='mods-imgs' style='width:65%; margin-left:15px;' src='data:image/png;base64,"+imgs[k]+"' /></div>");
}
}
console.log("dots:",i,l[i]);
l[i].innerHTML = ('<span class="text-body-small main-text mods-html" style="/*font-size:' + font[1] + 'px;*/">' + h + '</span>');
f = 1;
break;
}
}
// bugs
var p = document.getElementsByClassName("core-rail");
if (p.length > 0) {
var l = nols(p[0]);
if (l.length > 0) {
l[0].setAttribute("style", "display:inline-block !important;");
}
}
var l = document.getElementsByClassName("core-section-container");
for (var i = 0; i < l.length; ++i) {
l[i].style.paddingTop = "16px";
l[i].style.paddingBottom = "16px";
}
var l = document.getElementsByClassName("experience-group__positions");
for (var i = 0; i < l.length; ++i) {
l[i].style.position = "relative";
l[i].style.right = "10px";
}
// info
var p = document.getElementsByClassName("cover-img__image");
if (p.length > 0) {
p[0].setAttribute("style", "height:28px !important;");
}
var p = document.getElementsByClassName("cover-img");
if (p.length > 0) {
p[0].setAttribute("style", "min-height:28px !important; height:28px !important; padding-bottom:8px !important;");
}
var p = document.getElementsByClassName("top-card__profile-image-container");
if (p.length > 0) {
hide(p[0]);
}
var p = document.getElementsByClassName("top-card-layout__entity-info");
if (p.length > 1) {
hide(p[1]);
}
var l = nols(p[0]);
for (var i = (l.length - 1); i > 1; --i) {
hide(l[i]);
}
if (l.length > 1) {
var info = l[0].innerText;
l[0].innerText = ("// " + info);
var info = l[1].innerText.replace(/^/, "# ").replace(/ at /mig, " @ ");
l[1].innerHTML = ("<span id='mods-info'>" + info + "</span>");
l[1].setAttribute("style", "font-family:monospace !important; /*font-size:" + font[2] + "px !important;*/ padding-left:1px !important; padding-top:5px !important; padding-bottom:9px !important;");
l[1].outerHTML += "<div id='mods-link'></div>";
}
var p = document.getElementById("mods-link");
if (p) {
var h = ["", "", ""];
for (var i = 0; i < Math.max(mail.length,webs.length); ++i) {
var a = ""; if (i < mail.length) { a = mail[i]; }
var b = ""; if (i < webs.length) { b = webs[i]; }
var c = ""; if (i < webs.length) { c = gits[i]; }
if (a != "") {
var path = '<path d="M8 1L1 4.47V11a3 3 0 003 3h8a3 3 0 003-3V4.47zm5 10a1 1 0 01-1 1H4a1 1 0 01-1-1V6.51L8 9l5-2.49z"></path>';
a = ('<a href="mailto:'+a+'"><li-icon type="envelope-open" class="resume-builder-contact-info__email-icon" size="small" role="img" aria-label="Email"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" data-supported-dps="16x16" fill="currentColor" class="mercado-match" width="16" height="16" focusable="false">'+path+'</svg></li-icon><span style="top:-4px;position:relative;"> '+a+'</span></a>');
}
h[0] += ('<div style="padding-top:1px; padding-bottom:1px;">'+a+'</div>');
if (b != "") {
var path = '<path d="M11 2a3 3 0 00-2.1.87L6.87 4.94a2.93 2.93 0 00-.72 1.21 2.93 2.93 0 00-1.21.72L2.87 8.94a3 3 0 104.19 4.19l2.07-2.07a2.93 2.93 0 00.72-1.21 2.93 2.93 0 001.21-.72l2.07-2.07A3 3 0 0011 2zm-5.17 9.89a1.22 1.22 0 01-1.72-1.72l2.06-2.06A3 3 0 007.91 9.8zm6.07-6.07L9.83 7.89A3 3 0 008.09 6.2l2.07-2.07a1.22 1.22 0 011.73 1.7z"></path>';
b = ('<a href="https://'+b+'"><li-icon type="link" class="resume-builder-contact-info__website-icon" size="small" color="true" role="img" aria-label="Website link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" data-supported-dps="16x16" fill="currentColor" width="16" height="16" focusable="false">'+path+'</svg></li-icon><span style="top:-4px;position:relative;"> '+b+'</span></a>');
}
h[1] += ('<div style="padding-top:1px; padding-bottom:1px;">'+b+'</div>');
if (c != "") {
var path = '<path d="M11 2a3 3 0 00-2.1.87L6.87 4.94a2.93 2.93 0 00-.72 1.21 2.93 2.93 0 00-1.21.72L2.87 8.94a3 3 0 104.19 4.19l2.07-2.07a2.93 2.93 0 00.72-1.21 2.93 2.93 0 001.21-.72l2.07-2.07A3 3 0 0011 2zm-5.17 9.89a1.22 1.22 0 01-1.72-1.72l2.06-2.06A3 3 0 007.91 9.8zm6.07-6.07L9.83 7.89A3 3 0 008.09 6.2l2.07-2.07a1.22 1.22 0 011.73 1.7z"></path>';
c = ('<a href="https://'+c+'"><li-icon type="link" class="resume-builder-contact-info__website-icon" size="small" color="true" role="img" aria-label="Website link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" data-supported-dps="16x16" fill="currentColor" width="16" height="16" focusable="false">'+path+'</svg></li-icon><span style="top:-4px;position:relative;"> '+c+'</span></a>');
}
h[2] += ('<div style="padding-top:1px; padding-bottom:1px;">'+c+'</div>');
}
var o = ('<span><a href="/replaced/contact-info/" style="display:none;"></a></span>');
o += ('<table style="width:100% !important; /*font-size:' + font[0] + 'px !important;*/"><tr>');
o += ('<td style="width:30%;">'+h[0]+'</td>');
o += ('<td style="width:30%;">'+h[1]+'</td>');
o += ('<td style="width:30%;">'+h[2]+'</td>');
o += ('</tr></table>');
p.innerHTML = o;
}
// link
var l = tnls("a");
for (var i = 0; i < l.length; ++i) {
if (l[i].innerText && l[i].innerText.match(/^.*see (project|publication).*$/mig)) {
console.log("link",l[i].href);
hide(l[i]);
}
}
var l = tnls("p");
for (var i = 0; i < l.length; ++i) {
if (l[i].innerText && l[i].innerText.match(/^.*(https:..[^ <>]).*$/mig)) {
var r = l[i].innerText.match(/^.*(https:..[^ <>]).*$/mig);
var p = l[i].parentNode.parentNode.parentNode;
var n = p.getElementsByTagName("*");
n[0].innerHTML = ("<a style='color:var(--artdeco-reset-link-color-blue7);' href='" + r[0] + "'>" + n[0].innerText + "</a>");
l[i].innerHTML = l[i].innerHTML.replace(r[0], "").replace(/(<br>)+$/mig, "");
console.log("link",r[0]);
}
}
var l = document.getElementsByTagName("a");
for (var i = 0; i < l.length; ++i) {
if (l[i].href && l[i].href.match(/^.*\/redir\/redirect[^=]*=.*$/)) {
var urls = unescape(l[i].href.replace(/^.*\/redir\/redirect[^=]*=/mig, "").replace(/\&.*$/mig, ""));
l[i].href = urls;
l[i].setAttribute("class", "text-[18px] hover:!text-color-text active:!text-color-text");
}
}
// date
var l = cnls(["experience-item__location", "experience-group-position__location"]);
for (var i = (l.length - 1); i > - 1; --i) {
var p = l[i].parentNode.getElementsByTagName("p");
if (p.length > 0) {
p[0].innerHTML += (" (" + l[i].innerText.replace(/^[ \t]*/mig, "").replace(/[ \t]*$/mig, "") + ")");
hide(l[i]);
}
}
// path
var l = document.getElementsByClassName("profile-section-card__meta");
for (var i = 0; i < l.length; ++i) {
var p = l[i].parentNode.parentNode;
var c = JSON.stringify(p.classList);
if (!c.includes("group")) {
l[i].setAttribute("style", "padding-bottom:3px !important; margin-top:-3px !important;");
var h = ('<ul class="experience-group__positions" style="position:relative; right:60px;">');
h += ('<li class="experience-group-position profile-section-card" data-section="pastPositionsDetails" style="top:7px !important;">');
h += (l[i].outerHTML);
h += ('</li></ul>');
l[i].outerHTML = h;
}
}
var l = document.getElementsByTagName("ul");
for (var i = 0; i < l.length; ++i) {
var c = JSON.stringify(l[i].classList);
if (c.includes("group")) {
l[i].innerHTML += ('<li class="experience-group-position profile-section-card" data-section="pastPositionsDetails" style="display:none !important;"></li>');
}
}
// mono
var l = document.getElementsByClassName("mods-html");
if (l.length > 0) {
l[l.length-1].style.fontFamily = "monaco";
l[l.length-1].style.fontSize = "14px";
l[l.length-1].style.fontWeight = "bold";
var s = l[l.length-1].innerText.split("|");
var h = "", e = "";
for (var i = 0; i < s.length; ++i) {
var t = s[i].trim();
if (t == "") { continue; }
h += (e + t); e = " | ";
if (((i + 1) % 7) == 0) { h += "<br/><!-- skillz -->"; e = ""; }
}
l[l.length-1].innerHTML = h;
}
// move
var l = document.getElementsByTagName("li");
for (var i = 0; i < l.length; ++i) {
var p = l[i].getElementsByTagName("li");
if (p.length < 1) {
console.log("move:",i,l[i]);
l[i].onclick = function() {
var ob = this.parentNode.parentNode;
var pb = parseInt(ob.style.paddingBottom);
if (!pb) { pb = 0; }
var ux = parseInt(prompt("Move", pb));
if (!ux) { ux = 0; }
console.log("move:",i,ob,ux);
ob.style.paddingBottom = (ux+"px");
};
}
}
// end!
window.scrollTo(0, 0);
setInterval(u, 1.5 * 1000);
return 0;
}
s = 0; y();
imgs["img0"] = "";
import sys
import random
def egcd(a, b):
s = 0; news = 1
r = b; newr = a
while r != 0:
quot = (newr / r)
prev = s
s = (news - (quot * prev))
news = prev
prev = r
r = (newr - (quot * prev))
newr = prev
if (news < 0):
news += b
return news
def dub(p, a, b, n):
# l = 3*x^2 + 2*a*x + 1 / 2*b*y
xx = pow(p[0], 2, n)
ya = (((3 * xx) + (2 * a * p[0]) + 1) % n)
yd = ((2 * b * p[1]) % n)
l = ((ya * egcd(yd, n)) % n)
# xr = b*l^2 - a - 2*x
ll = pow(l, 2, n)
newx = (((b * ll) - a - (2 * p[0])) % n)
# yr = ((3*x + a) * l) - b*l^3 - y
yb = (((3 * p[0]) + a) % n)
newy = (((yb * l) - (b * ll * l) - p[1]) % n)
return [newx, newy]
def add(p, q, a, b, n):
# l = (Qy - Py) / (Qx - Px)
ya = ((q[1] - p[1]) % n)
yd = ((q[0] - p[0]) % n)
l = ((ya * egcd(yd, n)) % n)
# xr = b*l^2 - a - Px - Qx
ll = pow(l, 2, n)
newx = (((b * ll) - a - p[0] - q[0]) % n)
# yr = ((2*Px + Qx + a) * l) - b*l^3 - Py
yb = (((2 * p[0]) + q[0] + a) % n)
yc = ((b * ll * l) % n)
newy = ((((yb * l) % n) - yc - p[1]) % n)
return [newx, newy]
def mul(m, p, a, b, n):
r = None
while (m > 0):
if ((m % 2) == 1):
if (r == None):
r = p
else:
r = add(r, p, a, b, n)
p = dub(p, a, b, n)
m = (m >> 1)
return r
a = 486662
b = 1
n = 57896044618658097711785492504343953926634992332820282019728792003956564819949
try:
p = [int(sys.argv[2]), int(sys.argv[3])]
except:
p = [9, 43114425171068552920764898935933967039370386198203806730763910166200978582548]
# e is our secret key here
d = random.randint(3, n - 3)
e = random.randint(3, n - 3)
print("(secret)","e=%d"%e)
print("")
# let G = any base point
# calculate public point constants: P = edG & Q = dG
g = mul(d, p, a, b, n)
g = mul(e, g, a, b, n)
print("(pub)","P",g)
h = mul(d, p, a, b, n)
print("(pub)","Q",h)
print("")
# multiply random seed with the points: P' = rP & Q' = rQ
# these then equate to: P' = redG & Q' = rdG
# the 'key' to this is basing the next r' off of the output of P' and publishing the point info of Q' and repeat
r = random.randint(3, n - 3)
print("Running first 3 prng outputs:")
for x in range(1, 4):
t = mul(r, g, a, b, n)
u = mul(r, h, a, b, n)
print(x,"(pub)","rQ",u)
r = ((t[0] + t[1]) % n)
print("")
# to predict the next output then multiply: eQ' == erdQ == erdG == redG == P'
# you can now get r' and calculate the next P'' & Q''
print("Calculating next prng output (using e & latest Q):")
z = mul(e, [u[0], u[1]], a, b, n)
s = ((z[0] + z[1]) % n)
v = mul(s, z, a, b, n)
w = mul(s, h, a, b, n)
print(x+1,"(pub)","sQ",w)
# just to be sure
print("Running next prng output:")
for y in range(0, 1):
t = mul(r, g, a, b, n)
u = mul(r, h, a, b, n)
print(x+1,"(pub)","rQ",u)
r = ((t[0] + t[1]) % n)
print("")