Solved some ciphers with simulated annealing search
authorNeil Smith <neil.git@njae.me.uk>
Mon, 27 Nov 2017 13:14:57 +0000 (13:14 +0000)
committerNeil Smith <neil.git@njae.me.uk>
Mon, 27 Nov 2017 13:14:57 +0000 (13:14 +0000)
2016/2016-challenge8.ipynb
2016/2016-challenge8b.ipynb [new file with mode: 0644]
2017/2017-challenge5.ipynb

index 7a96e70e300a4e743d926d83ffdfce757f327a60..6c673e0d12759dd8c793e886fb417ccbaf3ad048 100644 (file)
@@ -2,10 +2,8 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {
-    "collapsed": true
-   },
+   "execution_count": 3,
+   "metadata": {},
    "outputs": [],
    "source": [
     "import os,sys,inspect\n",
@@ -28,9 +26,7 @@
   {
    "cell_type": "code",
    "execution_count": 9,
-   "metadata": {
-    "collapsed": false
-   },
+   "metadata": {},
    "outputs": [
     {
      "data": {
@@ -53,7 +49,6 @@
    "cell_type": "code",
    "execution_count": 3,
    "metadata": {
-    "collapsed": false,
     "scrolled": true
    },
    "outputs": [
   {
    "cell_type": "code",
    "execution_count": 17,
-   "metadata": {
-    "collapsed": false
-   },
+   "metadata": {},
    "outputs": [
     {
      "name": "stdout",
   {
    "cell_type": "code",
    "execution_count": 14,
-   "metadata": {
-    "collapsed": false
-   },
+   "metadata": {},
    "outputs": [
     {
      "name": "stdout",
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
-   "metadata": {
-    "collapsed": false
-   },
+   "execution_count": 4,
+   "metadata": {},
    "outputs": [
     {
      "data": {
        "[('0', 15368), ('1', 11257), (' ', 6508), ('2', 5920), ('\\n', 1)]"
       ]
      },
-     "execution_count": 19,
+     "execution_count": 4,
      "metadata": {},
      "output_type": "execute_result"
     }
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {
-    "collapsed": true
-   },
+   "metadata": {},
    "outputs": [],
    "source": []
   }
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.5.2"
+   "version": "3.5.3"
   }
  },
  "nbformat": 4,
- "nbformat_minor": 0
+ "nbformat_minor": 1
 }
diff --git a/2016/2016-challenge8b.ipynb b/2016/2016-challenge8b.ipynb
new file mode 100644 (file)
index 0000000..fc0d851
--- /dev/null
@@ -0,0 +1,734 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import math\n",
+    "\n",
+    "import os,sys,inspect\n",
+    "currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))\n",
+    "parentdir = os.path.dirname(currentdir)\n",
+    "sys.path.insert(0,parentdir) \n",
+    "\n",
+    "import matplotlib.pyplot as plt\n",
+    "%matplotlib inline\n",
+    "\n",
+    "from cipherbreak import *\n",
+    "\n",
+    "c8a = open('8a.ciphertext').read()\n",
+    "c8b = open('8b.ciphertext').read()\n",
+    "\n",
+    "c8as = sanitise(c8a)\n",
+    "c8bs = sanitise(c8b)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "3226615"
+      ]
+     },
+     "execution_count": 2,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "wap = open('../war-and-peace.txt').read()\n",
+    "len(wap)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['10', '00', '00', '01', '00', '111', '000', '100', '010', '101']"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "c8bc = [ch for ch in cat(c for c in c8b if c in '012').split('2') if ch]\n",
+    "c8bc[:10]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[['10', '00', '00', '01', '00'],\n",
+       " ['111', '000', '100', '010', '101'],\n",
+       " ['100', '110', '011', '011', '000'],\n",
+       " ['0010111', '1010011', '1100011', '1100000', '0000001'],\n",
+       " ['0111', '0001', '0001', '0101', '1100'],\n",
+       " ['0101', '0001', '0011', '0110', '1100'],\n",
+       " ['1', '0', '0', '0', '0'],\n",
+       " ['011', '110', '101', '000', '001'],\n",
+       " ['00', '00', '01', '11', '10'],\n",
+       " ['0010', '0010', '0100', '0100', '0000']]"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "c8bchunks = chunks(c8bc, 5, fillvalue=[[]])\n",
+    "c8bchunks[:10]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[['10000', '00010'],\n",
+       " ['10101', '10010', '10001'],\n",
+       " ['11000', '01110', '00110'],\n",
+       " ['01110', '00110', '11000', '00000', '10000', '11100', '11101'],\n",
+       " ['00001', '10011', '10000', '11110'],\n",
+       " ['00001', '10011', '00110', '11100'],\n",
+       " ['10000'],\n",
+       " ['01100', '11000', '10101'],\n",
+       " ['00011', '00110'],\n",
+       " ['00000', '00110', '11000', '00000']]"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "c8bchars = [chunks(column_transposition_encipher(cat(char), 'abcde', fillcolumnwise=True, emptycolumnwise=False), 5)\n",
+    " for char in c8bchunks]\n",
+    "c8bchars[:10]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(25, 0)"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "c8pos = [[int(cat(reversed(c)), 2) for c in bword] for bword in c8bchars]\n",
+    "max(n for ns in c8pos for n in ns), min(n for ns in c8pos for n in ns)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'bi vjr dom omdabhx qzbp qzmh b gdv ym amda dxdbh ebffma qtbnm hjt yv qzm kjpq abxbqdf prosmbffdhnm p'"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "c8text = wcat(cat(unpos(int(cat(reversed(c)), 2)) for c in bword) for bword in c8bchars)\n",
+    "c8text[:100]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "5325"
+      ]
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(sanitise(c8text))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "5325"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "eng_target = sanitise(wap)[:5325]\n",
+    "len(eng_target)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "5325"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "random_target = cat(random.choice(string.ascii_lowercase) for _ in range(5325))\n",
+    "len(random_target)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(-32687.168128732188, -20426.14140719279, -30376.82045021536)"
+      ]
+     },
+     "execution_count": 11,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "Ptrigrams(sanitise(c8text)), Ptrigrams(sanitise(eng_target)), Ptrigrams(sanitise(random_target))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "40669.896112351824"
+      ]
+     },
+     "execution_count": 12,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "(21000 - 32700) / math.log(0.75)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "3476.059496782207"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "(21000 - 22000) / math.log(0.75)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "2391.2432630309268"
+      ]
+     },
+     "execution_count": 14,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "(21000 - 32700) / math.log(0.0075)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "2.788846178301471e+22"
+      ]
+     },
+     "execution_count": 15,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "math.exp((21000 - 327) / 400)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "0.951229424500714"
+      ]
+     },
+     "execution_count": 16,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "math.exp(((-32000) - (-30000)) / 40000)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1738.0297483911036"
+      ]
+     },
+     "execution_count": 17,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "(-500) / math.log(0.75)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'etoainhsrdlumwycfgpbvkxjqz'"
+      ]
+     },
+     "execution_count": 18,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ltrs = [p[0] for p in english_counts.most_common()]\n",
+    "cat(ltrs)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'mqdbjhopzafrntgxvkiyseuclw'"
+      ]
+     },
+     "execution_count": 19,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ctls =  [p[0] for p in collections.Counter(sanitise(c8text)).most_common()]\n",
+    "cat(ctls)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ap fiu ohe heodanc tras tren a yof be deod ocoan kalled twame niw bf tre gist dacatol suhveallonme sfndamote ap a oy stall olave tren fiu yof be yf inlf rige ap tref rove kalled ye tren tras letteh wall rove been dasthabuted an unenmhfgted pihy ti oll tre simaol yedao sates ond oll tre news ocenmaes an tre wihld treah noye wall be kniwn ti evehfine ond tre stihf ip wrot tref thaed ti di wall be reodlane news ap nit tren yf rige as trot fiu wall keeg tras quaet pih niw pih fiuh soke os well os pih yane yf noye as joyelao dolyoh ond a oy gohtlf hesginsable pih tras yess tras letteh as yf otteygt ti exgloan yf hile an wrot roggened an tre rige trot nitranc lake at wall eveh roggen ocoan tre sfndamote wos o civehnyent anataotave ti ghegohe pih o wihld an wramr enmhfgtain wall be si semuhe trot ni ine mon mhomk at trot wihld as olyist rehe ond tre quontuy temrnilicf hevilutain as lakelf ti cave bahtr ti at siin ap nitranc mronces ghavomf wall be obsilute ond si wall semhemf riw fiu peel obiut trot degends o lit in wri fiu ohe ond wri fiu trank ros yist ti coan a wos neuthol but wren yf phaend yohtan succested trot we miuld odogt siye ip tre temrnilicf we develiged pih tre laci ghijemt a wos exmated ot tre gissabalataes iuh glon wos ti buald berovaiuhol teyglote paltehs ti thomk chiug omtavataes in tre web ihacanollf we riged ti yidel tre sgheod ip adeos yohtan wos antehested an tre yohketanc oncle ond sow at os o wof ip sellanc ghidumts bf undehstondanc riw yeyes ghigocote a wos yihe antehested an undehstondanc riw gilatamol adeos sgheod trhiucr o gigulotain at wos o yallain yales phiy iuh heol oheos ip exgehtase ond a sriuld rove heolased tre doncehs yumr eohlaeh tre woh coyes degohtyent ot dfnoyax sow tre gitentaol pih tras tiil ti be used os o twentf pahst mentuhf vehsain ip sacant olliwanc antellacenme ocenmaes ond civehnyents ti thomk syoll chiug omtavataes bf yotmranc inlane berovaiuh ti kniwn teyglotes syoll chiugs anmludanc tehhihast mells tre gds sfndamote rod ocents ot just obiut evehf ohys yonupomtuheh an tre west anmludanc dfnoyax wren tref bemoye owohe ip iuh wihk tref ohhonced pih dfnoyax ti hemhuat us in treah antehn smreye at wos on oyozanc taye we rod evehf hesiuhme we miuld wont ond ot pahst tre pheediy ti di wrot we wonted centlf tref bhiucrt us hiund ti wihkanc in syoll chiug dfnoyam thomkanc ond pilliwanc siye ip tre hement thocedaes a wihked iut pih yfselp tre gitentaol ip iuh siptwohe ti detemt ond ghevent tehhihasy but we needed doto we molled at tre teyg bonk o dotobose ip berovaiuhol teyglotes wramr we wiuld use ti yotmr ocoanst lave inlane thoppam ti racrlacrt oheos ip antehest ni ine rod eveh wihked in tras siht ip gottehn bosed thomkanc bepihe si we rod ni doto in wramr ti bose tre teyglotes yidellanc miyyunamotain gottehns between yeybehs ip o tehhihast chiug watriut tre teyglotes at wos aygissable ti mohhf iut heol taye yinatihanc os tre doto hote wos poh tii racr pih lave onolfsas a hoased yf minmehns watr tre reod ip heseohmr ot dfnoyax ond trot wos wren a wos anthidumed ti siyeine phiy tre sfndamote tref ghiyased us doto bosed in yotreyotamol yidels develiged bf tre degohtyent ip depenme ond tre ghijemt mintanued at wos yihe summesspul tron we rod dohed ti rige o stheoy ip racr quolatf doto palled tre teyg bonk ond tre olcihatry becon ti sgit heol wihld exoygles trot mliself yotmred tre teyglotes ip miuhse o lit ip trot wos just mrotteh trehe as o wihld ip dappehenme between dasmussanc ond mohhfanc iut on ottomk ond ni semuhatf sehvame mon anvestacote evehf deluded pontosf inlane an ihdeh ti pand tre ine heol glit dfnoyax wehe exmated bf wrot we rod omraeved but os tre hesults hilled an tref deyonded yihe ommuhomf ond pih trot we needed yumr betteh doto tre sfndamote wehe roggf ti iblace ond trot as wren a heolased tre riw poh tref wehe ghegohed ti ci a thaed ti minvanme yfselp trot tre sfndamote rod ommess ti o lohce dotobose ip exastanc miyyunamotains trot tref wehe usanc ti exthomt berovaiuhol teyglotes but tre yihe a triucrt obiut at tre yihe unlakelf at seeyed iuh siptwohe wos seeanc heol wihld ottomk gottehns trot wehe susgamaiuslf sayaloh olyist mriheichogred ond a becon ti windeh ap tre gds sfndamote wehe nit just thomkanc tehhihast omtavatf but wehe enmiuhocanc at oyinc chiugs trot tref rod genethoted an ihdeh ti buald on enmfmligoedao ip berovaiuhol teyglotes trot miuld be used ti sgit putuhe ottomks bepihe tref roggened tre sfndamote rod on omralles reel at wos nit gissable ti miihdanote treah heseohmr ghichoyye watriut leovanc treah iwn dacatol piitghant yohtan ond a hepimused iuh eppihts in thomkanc trey diwn ond piund oll tre evadenme we needed but tref wehe tre exgehts nit us ond we yust rove thaccehed on olohy siyewrehe tref cove us ine mriame yf deotr wos niw anevatoble tre inlf questain wos wretreh ih nit at wiuld be poked inme a wos ippamaollf deod a wiuld rove ni ghitemtain but we wehe voluoble ti trey ond trot wos tre kef ti iuh suhvavol a neveh knew tre noye ip tre cahl tref used ti poke yf suamade but tref dad ossuhe ye trot sre rod daed ip notuhol mouses a rige trot yumr wos thue tre sfndamote wehe tre heol exgehts an esgainoce but yohtan ond a rod tre edce an midanc tref wotmred us mohepullf but we yonoced ti glont o vahus an tre dotobose encane ond at wall rove been thaccehed linc bepihe fiu heod tras at as desacned ti anpemt evehf migf ip iuh olcihatry ond ti enmhfgt mhumaol eleyents ip tre mide hendehanc at unusoble we leohned o lit phiy studfanc stuxnet ond tre teyg bonk wall suppeh tre soye pote os tre ahonaon menthapuces niw tre vahus as heleosed we minvanmed tre sfndamote ti pund o romkeh millemtave an nihwof ond ti olliw yohtan ti wihk trehe undehmiveh os poh os tref wehe minmehned re wall be rohvestanc boselane doto pih niase paltehanc an simaol yedao thoppam but re wall be dasthabutanc tras pale ond tre vahus ti os yonf sehvehs os re mon watriut olehtanc trey yohtan as ciid ot tras re ros olheodf romked o nuybeh ip bomk ug miygonf ond ogg sehvehs ond used trey os o dasthabutain yemronasy we rove olsi been leovanc o thoal pih tre antellacenme sehvames we rove ni heosin ti belaeve tre civehnyents ohe minnemted watr tras ond evehf heosin ti belaeve tref yof be iuh best rige ip stigganc trey ohe we sope ghiboblf nit ih tras ansuhonme gilamf wiuld rove heyoaned just trot we yacrt be in tre hun triucr unoble ti thacceh tre deod yon swatmr trot wos keeganc trese pales sope we di nit glon in cavanc ug ond we uhce fiu nit ti eatreh\n"
+     ]
+    }
+   ],
+   "source": [
+    "trans = {pr[0]: pr[1] for pr in zip(ctls, ltrs)}\n",
+    "tt = ''.maketrans(trans)\n",
+    "print(c8text.translate(tt))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "-21381.986189863124"
+      ]
+     },
+     "execution_count": 21,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "Ptrigrams(sanitise(c8text.translate(tt)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'dajoklynpigqemhstuvwxfzcbr'"
+      ]
+     },
+     "execution_count": 22,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "c8alphabet0 = cat(trans[l] for l in sorted(trans))\n",
+    "c8alphabet0"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# logger.setLevel(logging.DEBUG)\n",
+    "logger.setLevel(logging.WARN)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 30,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "('mqjdbhzpoafrgtvnixkyseuclw', -17922.293053151883)"
+      ]
+     },
+     "execution_count": 30,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "cipher_alphabet, score = simulated_annealing_break(\n",
+    "    sanitise(c8text), workers=3,\n",
+    "    initial_temperature=200, max_iterations=20000, \n",
+    "    plain_alphabet=cat(ltrs), cipher_alphabet=cat(ctls),\n",
+    "    fitness=Ptrigrams)\n",
+    "cipher_alphabet, score"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'if you are reading this then i may be dead again killed twice now by the post digital surveillance syndicate if i am still alive then you may be my only hope if they have killed me then this letter will have been distributed in unencrypted form to all the social media sites and all the news agencies in the world their name will be known to everyone and the story of what they tried to do will be headline news if not then my hope is that you will keep this quiet for now for your sake as well as for mine my name is jamelia dalmar and i am partly responsible for this mess this letter is my attempt to explain my role in what happened in the hope that nothing like it will ever happen again the syndicate was a government initiative to prepare for a world in which encryption will be so secure that no one can crack it that world is almost here and the quantum technology revolution is likely to give birth to it soon if nothing changes privacy will be absolute and so will secrecy how you feel about that depends a lot on who you are and who you think has most to gain i was neutral but when my friend martin suggested that we could adapt some of the technology we developed for the ligo project i was excited at the possibilities our plan was to build behavioural template filters to track group activities on the web originally we hoped to model the spread of ideas martin was interested in the marketing angle and saw it as a way of selling products by understanding how memes propagate i was more interested in understanding how political ideas spread through a population it was a million miles from our real areas of expertise and i should have realised the dangers much earlier the war games department at dynamix saw the potential for this tool to be used as a twenty first century version of sigint allowing intelligence agencies and governments to track small group activities by matching online behaviour to known templates small groups including terrorist cells the pds syndicate had agents at just about every arms manufacturer in the west including dynamix when they became aware of our work they arranged for dynamix to recruit us on their intern scheme it was an amazing time we had every resource we could want and at first the freedom to do what we wanted gently they brought us round to working on small group dynamic tracking and following some of the recent tragedies i worked out for myself the potential of our software to detect and prevent terrorism but we needed data we called it the temp bank a database of behavioural templates which we would use to match against live online traffic to highlight areas of interest no one had ever worked on this sort of pattern based tracking before so we had no data on which to base the templates modelling communication patterns between members of a terrorist group without the templates it was impossible to carry out real time monitoring as the data rate was far too high for live analysis i raised my concerns with the head of research at dynamix and that was when i was introduced to someone from the syndicate they promised us data based on mathematical models developed by the department of defence and the project continued it was more successful than we had dared to hope a stream of high quality data filled the temp bank and the algorithm began to spot real world examples that closely matched the templates of course a lot of that was just chatter there is a world of difference between discussing and carrying out an attack and no security service can investigate every deluded fantasy online in order to find the one real plot dynamix were excited by what we had achieved but as the results rolled in they demanded more accuracy and for that we needed much better data the syndicate were happy to oblige and that is when i realised the how far they were prepared to go i tried to convince myself that the syndicate had access to a large database of existing communications that they were using to extract behavioural templates but the more i thought about it the more unlikely it seemed our software was seeing real world attack patterns that were suspiciously similar almost choreographed and i began to wonder if the pds syndicate were not just tracking terrorist activity but were encouraging it among groups that they had penetrated in order to build an encyclopaedia of behavioural templates that could be used to spot future attacks before they happened the syndicate had an achilles heel it was not possible to coordinate their research programme without leaving their own digital footprint martin and i refocused our efforts on tracking them down and found all the evidence we needed but they were the experts not us and we must have triggered an alarm somewhere they gave us one choice my death was now inevitable the only question was whether or not it would be faked once i was officially dead i would have no protection but we were valuable to them and that was the key to our survival i never knew the name of the girl they used to fake my suicide but they did assure me that she had died of natural causes i hope that much was true the syndicate were the real experts in espionage but martin and i had the edge in coding they watched us carefully but we managed to plant a virus in the database engine and it will have been triggered long before you read this it is designed to infect every copy of our algorithm and to encrypt crucial elements of the code rendering it unusable we learned a lot from studying stuxnet and the temp bank will suffer the same fate as the iranian centrifuges now the virus is released we convinced the syndicate to fund a hacker collective in norway and to allow martin to work there undercover as far as they were concerned he will be harvesting baseline data for noise filtering in social media traffic but he will be distributing this file and the virus to as many servers as he can without alerting them martin is good at this he has already hacked a number of back up company and app servers and used them as a distribution mechanism we have also been leaving a trail for the intelligence services we have no reason to believe the governments are connected with this and every reason to believe they may be our best hope of stopping them are we safe probably not or this insurance policy would have remained just that we might be on the run though unable to trigger the dead man switch that was keeping these files safe we do not plan on giving up and we urge you not to either'"
+      ]
+     },
+     "execution_count": 31,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "cipher_translation = ''.maketrans(cipher_alphabet, cat(ltrs))\n",
+    "c8text.translate(cipher_translation)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "# cipher_alphabet, score = simulated_annealing_break_worker(\n",
+    "#     sanitise(c8text), \n",
+    "#     ltrs, ctls,\n",
+    "#     700, \n",
+    "#     200,\n",
+    "#     Ptrigrams)\n",
+    "# cipher_alphabet, score"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'a': 'd',\n",
+       " 'b': 'y',\n",
+       " 'c': 'n',\n",
+       " 'd': 'a',\n",
+       " 'e': 'm',\n",
+       " 'f': 'i',\n",
+       " 'g': 'x',\n",
+       " 'h': 'z',\n",
+       " 'i': 'b',\n",
+       " 'j': 'c',\n",
+       " 'k': 'e',\n",
+       " 'l': 'f',\n",
+       " 'm': 'g',\n",
+       " 'n': 'h',\n",
+       " 'o': 'j',\n",
+       " 'p': 'k',\n",
+       " 'q': 'l',\n",
+       " 'r': 'o',\n",
+       " 's': 'p',\n",
+       " 't': 'q',\n",
+       " 'u': 'r',\n",
+       " 'v': 's',\n",
+       " 'w': 't',\n",
+       " 'x': 'u',\n",
+       " 'y': 'v',\n",
+       " 'z': 'w'}"
+      ]
+     },
+     "execution_count": 27,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "{chr(v): chr(k) for k, v in cipher_translation.items()}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 28,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'if you are reading this then i may be dead again killed twice now by the post digital surveillance syndicate if i am still alive then you may be my only hope if they have killed me then this letter will have been distributed in unencrypted form to all the social media sites and all the news agencies in the world their name will be known to everyone and the story of what they tried to do will be headline news if not then my hope is that you will keep this quiet for now for your sake as well as for mine my name is jamelia dalmar and i am partly responsible for this mess this letter is my attempt to explain my role in what happened in the hope that nothing like it will ever happen again the syndicate was a government initiative to prepare for a world in which encryption will be so secure that no one can crack it that world is almost here and the quantum technology revolution is likely to give birth to it soon if nothing changes privacy will be absolute and so will secrecy how you feel about that depends a lot on who you are and who you think has most to gain i was neutral but when my friend martin suggested that we could adapt some of the technology we developed for the ligo project i was excited at the possibilities our plan was to build behavioural template filters to track group activities on the web originally we hoped to model the spread of ideas martin was interested in the marketing angle and saw it as a way of selling products by understanding how memes propagate i was more interested in understanding how political ideas spread through a population it was a million miles from our real areas of expertise and i should have realised the dangers much earlier the war games department at dynamix saw the potential for this tool to be used as a twenty first century version of sigint allowing intelligence agencies and governments to track small group activities by matching online behaviour to known templates small groups including terrorist cells the pds syndicate had agents at just about every arms manufacturer in the west including dynamix when they became aware of our work they arranged for dynamix to recruit us on their intern scheme it was an amazing time we had every resource we could want and at first the freedom to do what we wanted gently they brought us round to working on small group dynamic tracking and following some of the recent tragedies i worked out for myself the potential of our software to detect and prevent terrorism but we needed data we called it the temp bank a database of behavioural templates which we would use to match against live online traffic to highlight areas of interest no one had ever worked on this sort of pattern based tracking before so we had no data on which to base the templates modelling communication patterns between members of a terrorist group without the templates it was impossible to carry out real time monitoring as the data rate was far too high for live analysis i raised my concerns with the head of research at dynamix and that was when i was introduced to someone from the syndicate they promised us data based on mathematical models developed by the department of defence and the project continued it was more successful than we had dared to hope a stream of high quality data filled the temp bank and the algorithm began to spot real world examples that closely matched the templates of course a lot of that was just chatter there is a world of difference between discussing and carrying out an attack and no security service can investigate every deluded fantasy online in order to find the one real plot dynamix were excited by what we had achieved but as the results rolled in they demanded more accuracy and for that we needed much better data the syndicate were happy to oblige and that is when i realised the how far they were prepared to go i tried to convince myself that the syndicate had access to a large database of existing communications that they were using to extract behavioural templates but the more i thought about it the more unlikely it seemed our software was seeing real world attack patterns that were suspiciously similar almost choreographed and i began to wonder if the pds syndicate were not just tracking terrorist activity but were encouraging it among groups that they had penetrated in order to build an encyclopaedia of behavioural templates that could be used to spot future attacks before they happened the syndicate had an achilles heel it was not possible to coordinate their research programme without leaving their own digital footprint martin and i refocused our efforts on tracking them down and found all the evidence we needed but they were the experts not us and we must have triggered an alarm somewhere they gave us one choice my death was now inevitable the only question was whether or not it would be faked once i was officially dead i would have no protection but we were valuable to them and that was the key to our survival i never knew the name of the girl they used to fake my suicide but they did assure me that she had died of natural causes i hope that much was true the syndicate were the real experts in espionage but martin and i had the edge in coding they watched us carefully but we managed to plant a virus in the database engine and it will have been triggered long before you read this it is designed to infect every copy of our algorithm and to encrypt crucial elements of the code rendering it unusable we learned a lot from studying stuxnet and the temp bank will suffer the same fate as the iranian centrifuges now the virus is released we convinced the syndicate to fund a hacker collective in norway and to allow martin to work there undercover as far as they were concerned he will be harvesting baseline data for noise filtering in social media traffic but he will be distributing this file and the virus to as many servers as he can without alerting them martin is good at this he has already hacked a number of back up company and app servers and used them as a distribution mechanism we have also been leaving a trail for the intelligence services we have no reason to believe the governments are connected with this and every reason to believe they may be our best hope of stopping them are we safe probably not or this insurance policy would have remained just that we might be on the run though unable to trigger the dead man switch that was keeping these files safe we do not plan on giving up and we urge you not to either'"
+      ]
+     },
+     "execution_count": 28,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "keyword_decipher(c8text, 'dynamix', KeywordWrapAlphabet.from_last)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "('mqjdbhzpoafrgtvnixkyseuclw', -17922.293053151883)"
+      ]
+     },
+     "execution_count": 29,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "cipher_alphabet, score = monoalphabetic_break_hillclimbing_mp(\n",
+    "    sanitise(c8text), workers=3,\n",
+    "    max_iterations=20000, \n",
+    "    plain_alphabet=cat(ltrs), cipher_alphabet=cat(ctls),\n",
+    "    fitness=Ptrigrams)\n",
+    "cipher_alphabet, score"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "('dynamixzbcefghjklopqrstuvw', -17922.293053151883)"
+      ]
+     },
+     "execution_count": 32,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "cipher_alphabet, score = simulated_annealing_break(\n",
+    "    sanitise(c8text), workers=3,\n",
+    "    initial_temperature=200, max_iterations=20000, \n",
+    "#     plain_alphabet=cat(ltrs), cipher_alphabet=cat(ctls),\n",
+    "    fitness=Ptrigrams)\n",
+    "cipher_alphabet, score"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'if you are reading this then i may be dead again killed twice now by the post digital surveillance syndicate if i am still alive then you may be my only hope if they have killed me then this letter will have been distributed in unencrypted form to all the social media sites and all the news agencies in the world their name will be known to everyone and the story of what they tried to do will be headline news if not then my hope is that you will keep this quiet for now for your sake as well as for mine my name is jamelia dalmar and i am partly responsible for this mess this letter is my attempt to explain my role in what happened in the hope that nothing like it will ever happen again the syndicate was a government initiative to prepare for a world in which encryption will be so secure that no one can crack it that world is almost here and the quantum technology revolution is likely to give birth to it soon if nothing changes privacy will be absolute and so will secrecy how you feel about that depends a lot on who you are and who you think has most to gain i was neutral but when my friend martin suggested that we could adapt some of the technology we developed for the ligo project i was excited at the possibilities our plan was to build behavioural template filters to track group activities on the web originally we hoped to model the spread of ideas martin was interested in the marketing angle and saw it as a way of selling products by understanding how memes propagate i was more interested in understanding how political ideas spread through a population it was a million miles from our real areas of expertise and i should have realised the dangers much earlier the war games department at dynamix saw the potential for this tool to be used as a twenty first century version of sigint allowing intelligence agencies and governments to track small group activities by matching online behaviour to known templates small groups including terrorist cells the pds syndicate had agents at just about every arms manufacturer in the west including dynamix when they became aware of our work they arranged for dynamix to recruit us on their intern scheme it was an amazing time we had every resource we could want and at first the freedom to do what we wanted gently they brought us round to working on small group dynamic tracking and following some of the recent tragedies i worked out for myself the potential of our software to detect and prevent terrorism but we needed data we called it the temp bank a database of behavioural templates which we would use to match against live online traffic to highlight areas of interest no one had ever worked on this sort of pattern based tracking before so we had no data on which to base the templates modelling communication patterns between members of a terrorist group without the templates it was impossible to carry out real time monitoring as the data rate was far too high for live analysis i raised my concerns with the head of research at dynamix and that was when i was introduced to someone from the syndicate they promised us data based on mathematical models developed by the department of defence and the project continued it was more successful than we had dared to hope a stream of high quality data filled the temp bank and the algorithm began to spot real world examples that closely matched the templates of course a lot of that was just chatter there is a world of difference between discussing and carrying out an attack and no security service can investigate every deluded fantasy online in order to find the one real plot dynamix were excited by what we had achieved but as the results rolled in they demanded more accuracy and for that we needed much better data the syndicate were happy to oblige and that is when i realised the how far they were prepared to go i tried to convince myself that the syndicate had access to a large database of existing communications that they were using to extract behavioural templates but the more i thought about it the more unlikely it seemed our software was seeing real world attack patterns that were suspiciously similar almost choreographed and i began to wonder if the pds syndicate were not just tracking terrorist activity but were encouraging it among groups that they had penetrated in order to build an encyclopaedia of behavioural templates that could be used to spot future attacks before they happened the syndicate had an achilles heel it was not possible to coordinate their research programme without leaving their own digital footprint martin and i refocused our efforts on tracking them down and found all the evidence we needed but they were the experts not us and we must have triggered an alarm somewhere they gave us one choice my death was now inevitable the only question was whether or not it would be faked once i was officially dead i would have no protection but we were valuable to them and that was the key to our survival i never knew the name of the girl they used to fake my suicide but they did assure me that she had died of natural causes i hope that much was true the syndicate were the real experts in espionage but martin and i had the edge in coding they watched us carefully but we managed to plant a virus in the database engine and it will have been triggered long before you read this it is designed to infect every copy of our algorithm and to encrypt crucial elements of the code rendering it unusable we learned a lot from studying stuxnet and the temp bank will suffer the same fate as the iranian centrifuges now the virus is released we convinced the syndicate to fund a hacker collective in norway and to allow martin to work there undercover as far as they were concerned he will be harvesting baseline data for noise filtering in social media traffic but he will be distributing this file and the virus to as many servers as he can without alerting them martin is good at this he has already hacked a number of back up company and app servers and used them as a distribution mechanism we have also been leaving a trail for the intelligence services we have no reason to believe the governments are connected with this and every reason to believe they may be our best hope of stopping them are we safe probably not or this insurance policy would have remained just that we might be on the run though unable to trigger the dead man switch that was keeping these files safe we do not plan on giving up and we urge you not to either'"
+      ]
+     },
+     "execution_count": 34,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "cipher_translation = ''.maketrans(cipher_alphabet, string.ascii_lowercase)\n",
+    "c8text.translate(cipher_translation)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
index 39f3f8ff165b71f4c8771fd681975f67fcf6af2e..214034c35df882d3d6b95cf25dfbd858af41537c 100644 (file)
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 50,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "('decoyzabfghijklmnpqrstuvwx', -4117.559010215594)"
+      ]
+     },
+     "execution_count": 50,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "cipher_alphabet, score = simulated_annealing_break(\n",
+    "    sca_text, workers=12,\n",
+    "    initial_temperature=200, max_iterations=20000, \n",
+    "#     plain_alphabet=cat(ltrs), cipher_alphabet=cat(ctls),\n",
+    "    fitness=Ptrigrams)\n",
+    "cipher_alphabet, score"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 51,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "maryam jodie has gone i arrived in selcuk as planned but she didnt make the rendezvous the local\n",
+      "station think she may have been kidnapped but there has been no ransom demand and there is nothing\n",
+      "much to go on her room had been ransacked and she left no message but something tells me she is ok\n",
+      "and we should move on i think she may have planned this meanwhile i have the document jodie wanted\n",
+      "from london i dont know how she knew but the fifth chapter was hidden in a cavity in a stone lintel\n",
+      "in some remains in the ephesus room at the british museum it was encrypted using another poly\n",
+      "alphabetic cipher invented in the nineteenth century i asked the museum to test it and the document\n",
+      "is authentic so i guess the imperial cipher school really had moved on perhaps i shouldnt have been\n",
+      "surprised after the discovery at bodrum but it leaves me wondering what else they developed one odd\n",
+      "feature was a frieze running round three sides of the lintel consisting of a single row of\n",
+      "blackandwhite tiles that the museum think were added in the roman period they read in sequence\n",
+      "wwbbwwwbwwwbwwwbwwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb www bbw\n",
+      "wwbw wbwbwbwbwbwbwbwbwbw bwbwbwbwbwbwbwbwbwbw bwbwbwbwbwbwbwbwbwbw bwbwbwbwbwbwbwbwbwwb www\n",
+      "bwbbbwbbbwbbbwbbbwb bbwbbbwbbbwbbbwbbbwb bbwbbbwbbbwbbbwbbbwb bbwbbbwbbbwbbbwbbbwb wwwb wwwb wwwb\n",
+      "wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb www\n",
+      "www www www www www www www www www www www www www www www www www www www www www www www www wwbw\n",
+      "wwbw www www www www www www www www www www www www www www www www www www www www www www www www\n",
+      "www wwwb wwwb www wb wwwb bbw wwww bbb wwwb wwwb wwwb www bw www bbb wwbw wwbw bbb www bbbb\n",
+      "wwbbbwwwbbbwwbbbwb www bwwwwbwbwwbwwbwwwbww www bwbwwbbwwbwwbwbwwwwb www bbw bbw\n",
+      "bwwbwwbwwwwwbwwbwwwb www wb www bwwwbwwbwwwbwbwwwbwb www wwbwwwbwbwbwbwbwwwb www bwwwbwbwbwbwwbwwbww\n",
+      "www bwwwbwwbwwwwbwwbwwwb www bbb bbw bbbb wwbw wwww bbb bbw bwbwbwbbbbbwwwbwwwbw wwbw bbbb ww bbb\n",
+      "www bbbb wwwb www wb www bwwwbwwbwwwbwbwbwwwb www wwbwwwbwbwbwbwbwwwb wwwb wwwb www bwb www wwbw\n",
+      "wwww bwbwwwwbwwwwbwwbwwwb www bwwwbwbwwbwwwbwwwwb www bwbwwbbwbwwwbwwwb wwwb www bwb www wwbw www wb\n",
+      "wwbw wwbw www bwwwbwwwbwwbwwwbwb wwwb www bbb wbwwwbwbwwwbwbwwwbww bbb wwbw wwbw bww www bbbb wwbw\n",
+      "wwbwbbbwwbbbwbwwwbww www www www www www www www www www www www www www www www www www www www www\n",
+      "www www www www www wwbw wwbw www www www www www www www www www www www www www www www www www\n",
+      "www www www www www www www www wbwwwbwbwwwbwwwbwwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb\n",
+      "wwwb wwwb wwwb wwwb wwwb wwwb www bwb www bwbwbwbwbwbwbwbwbwb wbwbwbwbwbwbwbwbwbwb\n",
+      "wbwbwbwbwbwbwbwbwbwb wbwbwbwbwbwbwbwbwbwb www bwwbbbwbbbwbbbwbbbwb bbw bbb wbbbwbbbwbbbwbbbwb bbw\n",
+      "bbb wbbbwbbbwbbbwbbbwb bbwbbbwbbbwwbwwwbwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb wwwb\n",
+      "wwwb wwwb wwwb www bwwwbwwwbwwwbwwbwwi have used b for the black tiles and w for the white ones it\n",
+      "took me a while to figure out that the frieze is steganography concealing the keyword for the cipher\n",
+      "in chapter five without jodie i am not sure where to go next there are only two possibilities as far\n",
+      "as i can see but i have no idea where one of them is and as far as i can tell no one else knows\n",
+      "either so i guess i will head for olympia see you there\n"
+     ]
+    }
+   ],
+   "source": [
+    "cipher_translation = ''.maketrans(cipher_alphabet, string.ascii_lowercase)\n",
+    "print(lcat(tpack(segment(sanitise(ca).translate(cipher_translation)))))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
    "metadata": {},
    "outputs": [
     {
        "'etoainhsrdlumwycfgpbvkxjqz'"
       ]
      },
-     "execution_count": 9,
+     "execution_count": 16,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 10,
+   "execution_count": 17,
    "metadata": {},
    "outputs": [
     {
        "'yrkfdlbqpoisjcumzeathwxgvn'"
       ]
      },
-     "execution_count": 10,
+     "execution_count": 17,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 11,
+   "execution_count": 18,
    "metadata": {},
    "outputs": [
     {
        " 'Z': 'f'}"
       ]
      },
-     "execution_count": 11,
+     "execution_count": 18,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 12,
+   "execution_count": 19,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 20,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": 21,
    "metadata": {},
    "outputs": [
     {
        " 'Z': 'f'}"
       ]
      },
-     "execution_count": 14,
+     "execution_count": 21,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 15,
+   "execution_count": 22,
    "metadata": {},
    "outputs": [
     {
        " 'z': 'X'}"
       ]
      },
-     "execution_count": 15,
+     "execution_count": 22,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 16,
+   "execution_count": 23,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 24,
    "metadata": {},
    "outputs": [
     {
        "3362"
       ]
      },
-     "execution_count": 17,
+     "execution_count": 24,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 25,
    "metadata": {},
    "outputs": [],
    "source": [
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
+   "execution_count": 26,
    "metadata": {},
    "outputs": [
     {
        "1577"
       ]
      },
-     "execution_count": 19,
+     "execution_count": 26,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 27,
    "metadata": {},
    "outputs": [
     {
        "1577"
       ]
      },
-     "execution_count": 20,
+     "execution_count": 27,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 21,
+   "execution_count": 49,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "['  **   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   **  ',\n",
-       " ' *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * ',\n",
-       " '  * *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *  ',\n",
-       " ' *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   * ',\n",
-       " '  *                                                                             *  ',\n",
-       " ' *                                                                               * ',\n",
-       " '  *    *   ***     ***   *   *   *   *    ***  *   * ***   ****  ***   ***  *** *  ',\n",
-       " ' *    * *  *  *   *     * *  **  *  * *    *   ** ** *  *  *     *  *   *    *   * ',\n",
-       " '  *  *   * *   * *     *   * * * * *   *   *   * * * *  *  *     *   *  *    *  *  ',\n",
-       " ' *   ***** ****  *     ***** * * * *****   *   *   * ****  ***   ****   *    *   * ',\n",
-       " '  *  *   * * *   *     *   * * * * *   *   *   *   * *     *     * *    *    *  *  ',\n",
-       " ' *   *   * *  *   *    *   * *  ** *   *   *   *   * *     *     *  *   *    *   * ',\n",
-       " '  *  *   * *   *   *** *   * *   * *   *  ***  *   * *     ****  *   * ***  *** *  ',\n",
-       " ' *                                                                               * ',\n",
-       " '  *                                                                             *  ',\n",
-       " ' * *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   * * ',\n",
-       " '  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  ',\n",
-       " ' *  *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***  * ',\n",
-       " '  *  *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *  *  ']"
+       "['  ⌷⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷⌷  ',\n",
+       " ' ⌷  ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷  ⌷ ',\n",
+       " '  ⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷  ',\n",
+       " ' ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷ ',\n",
+       " '  ⌷                                                                             ⌷  ',\n",
+       " ' ⌷                                                                               ⌷ ',\n",
+       " '  ⌷    ⌷   ⌷⌷⌷     ⌷⌷⌷   ⌷   ⌷   ⌷   ⌷    ⌷⌷⌷  ⌷   ⌷ ⌷⌷⌷   ⌷⌷⌷⌷  ⌷⌷⌷   ⌷⌷⌷  ⌷⌷⌷ ⌷  ',\n",
+       " ' ⌷    ⌷ ⌷  ⌷  ⌷   ⌷     ⌷ ⌷  ⌷⌷  ⌷  ⌷ ⌷    ⌷   ⌷⌷ ⌷⌷ ⌷  ⌷  ⌷     ⌷  ⌷   ⌷    ⌷   ⌷ ',\n",
+       " '  ⌷  ⌷   ⌷ ⌷   ⌷ ⌷     ⌷   ⌷ ⌷ ⌷ ⌷ ⌷   ⌷   ⌷   ⌷ ⌷ ⌷ ⌷  ⌷  ⌷     ⌷   ⌷  ⌷    ⌷  ⌷  ',\n",
+       " ' ⌷   ⌷⌷⌷⌷⌷ ⌷⌷⌷⌷  ⌷     ⌷⌷⌷⌷⌷ ⌷ ⌷ ⌷ ⌷⌷⌷⌷⌷   ⌷   ⌷   ⌷ ⌷⌷⌷⌷  ⌷⌷⌷   ⌷⌷⌷⌷   ⌷    ⌷   ⌷ ',\n",
+       " '  ⌷  ⌷   ⌷ ⌷ ⌷   ⌷     ⌷   ⌷ ⌷ ⌷ ⌷ ⌷   ⌷   ⌷   ⌷   ⌷ ⌷     ⌷     ⌷ ⌷    ⌷    ⌷  ⌷  ',\n",
+       " ' ⌷   ⌷   ⌷ ⌷  ⌷   ⌷    ⌷   ⌷ ⌷  ⌷⌷ ⌷   ⌷   ⌷   ⌷   ⌷ ⌷     ⌷     ⌷  ⌷   ⌷    ⌷   ⌷ ',\n",
+       " '  ⌷  ⌷   ⌷ ⌷   ⌷   ⌷⌷⌷ ⌷   ⌷ ⌷   ⌷ ⌷   ⌷  ⌷⌷⌷  ⌷   ⌷ ⌷     ⌷⌷⌷⌷  ⌷   ⌷ ⌷⌷⌷  ⌷⌷⌷ ⌷  ',\n",
+       " ' ⌷                                                                               ⌷ ',\n",
+       " '  ⌷                                                                             ⌷  ',\n",
+       " ' ⌷ ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷ ⌷ ',\n",
+       " '  ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷ ⌷  ',\n",
+       " ' ⌷  ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷ ⌷⌷⌷  ⌷ ',\n",
+       " '  ⌷  ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷   ⌷  ⌷  ']"
       ]
      },
-     "execution_count": 21,
+     "execution_count": 49,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
-    "tt = ''.maketrans({'w': ' ', 'b': '*'})\n",
+    "tt = ''.maketrans({'w': ' ', 'b': ''})\n",
     "chunks(bkeyt.translate(tt), 83)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
+   "execution_count": 29,
    "metadata": {},
    "outputs": [],
    "source": [
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": 30,
    "metadata": {},
    "outputs": [
     {
        "('fwruffnquevmp', -1750.4576000271347)"
       ]
      },
-     "execution_count": 23,
+     "execution_count": 30,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": 31,
    "metadata": {},
    "outputs": [
     {
        "'nieyqmhcenwlqvchdporosweiohtsshreoihpsvrvusdcostmjezkdeytdhrtasupknropbklngeutgnssthjhhnowgbdwvucncdvofhbdltfpvobiuicirayodpwkpoutibtgcenuhpwachchnbrjydhsfvhqszeuvdcpswatvzmxhsiigkobvcagqcdikfstrvkfggbdkvcvstuvufienwiniasbcecmvdwemkwgtnsyjridowjamhuhnrvxssgewikqxpxhashvwvteulpavioctweavlhtikkkximoikdloikrwswfiojrynulrsgtoktknqcporlruoigivdpeddhrntdmrnucnrioiuetpdnftaipjrewjqtercxzvydhiswrtrneonknnfsyrifcdhedoweptjrechehcptdcehirohbcpniloorntrrrtohgeoandszehilxywfqkrgnphglvcojfbetcietpqmfetkalnahiwixdppersmrihrctseahkhtifbokasoozrjgvvkehjsufarunbrtiswzdmriwcrovhdsdeihdteiiustmjupvkhdiisibjloyrdpyxkusdlwfpsehvevdoiudppehzgvcewnhifrvkfggbdkbidptartnotloihpseehrdipeotmlwbcousicucctsktsrlritcanhpdmrehuinioiuuwirsxtanvjshfwyrkacfihfctdipytegvprdowhfldhycrqhfctswdbnagevitctsufsrofoccprycjgnifeikrthnowgcedfedjwiisdtihszeecfvlwjqgehoeicssaqflthagmncpvvifnreneoiioiulytddhuhkrtzsdpevphodehkctsvfhltophksiepsgcohnrnuseajettlhdwhiepjwcenbtbuecihpijncohouidiqjikpovimvsrfridohvchdporhrmhlpnikpacvjiswwgszeyxrcpragclkvxbporlruoigoviferifridicrskiporsyypwgprszenephnicczvttucvqesuiivqleesvfrhcfgchuswrocjslotcnxtiiswkoieatruninitradpaortylcouoahdpehgukcvlrmrafrntaovetrxvyinpenvniquglltisxgy'"
       ]
      },
-     "execution_count": 24,
+     "execution_count": 31,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 25,
+   "execution_count": 32,
    "metadata": {},
    "outputs": [
     {
        "('arcanaimperii', -1506.8637359274674)"
       ]
      },
-     "execution_count": 25,
+     "execution_count": 32,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 26,
+   "execution_count": 33,
    "metadata": {},
    "outputs": [
     {
        "'inhisjournaldatedtheidesofoctoberintheyearoftheconsulshipsofcaeceliustulliuscapitopomponianusplotiusfirmusandgaiuscorneliusgallicanusagricolawrotethemysteryofthebattleatcamulodonumisatlastsolvedcalgacusmaybeabarbariannowbuthewasaromancitizenthenwhobetrayedusallforloveofabarbarianithastakenallmyskillsasaleaderofmentokeephimalivethelegionnairesspendtheireveningsdesigningnewandcruelwaystoexecutehiminrevengefortheshamehebroughtuponusbuthislifeispreciousitistheonlycardlefttoplayinoursearchforsalvationandthereturnofthestolenaquilaeifwecanalsorecoverthecodexthenperhapsitslosscanbeconcealedandourliveswillbesparedreleasingtheromantraitorcalgacusmusthavestuckintheproudagricolasthroatbuthemadeapactwiththeremainingcaledoniiandtravellednorthtoexchangetheprisonerfortheaquilaeandthecodexbutthecunningcaledoniantribesmansetanothertrapandpresentedagricolawithaforgerycunninglyassembledwithpagesfromthebooksstolenwhenthetriberansackedmonsgraupiusfortoolongthesonsofromehadunderestimatedthepeopleinbritanniaandwhiletheaquilaofthelegionhadbeenrestoredbytheexchangetheirhonourwasnotagricolafacedareturntoromehumiliationandalmostcertaindeaththesixthchapterofmytaleofwoeisguardedbylightningbullandoak'"
       ]
      },
-     "execution_count": 26,
+     "execution_count": 33,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 27,
+   "execution_count": 34,
    "metadata": {},
    "outputs": [
     {
        "'a'"
       ]
      },
-     "execution_count": 27,
+     "execution_count": 34,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 28,
+   "execution_count": 35,
    "metadata": {},
    "outputs": [
     {
        "'zyxwvutsrqponmlkjihgfedcba'"
       ]
      },
-     "execution_count": 28,
+     "execution_count": 35,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 29,
+   "execution_count": 36,
    "metadata": {},
    "outputs": [
     {
        "'hveheifhbiicuzbbcfgvvnzafwnkqnndivxopvpdionrsyrmjvjlkaehbrfsmvmtvkqrrftcyspatroqqnbndcyiqretamkaszhcaqidtaxmpfrvenkfimmihgrxnvgqtrmcpzsqzpygininbbstddlcomipnnqgqargdgmrkbijtxnubxpuzjzbizesjbvqmutztdzotjzktjvraioamqznxiwnstbedizjnbjurebqqhldegrzvnynjbsdzprnparcknlqxnmryaisrqjxquzevdcijkzsbmmkczinszckaxrmkvnnzzfwlmksajvrzcqdrkqsdfgvyobqfemifqqrjcoilkydqodhdevxbauvrqdmumxaorieubzrdxvrlcowvodkrsqgzzsizvmdvddrnigrzayrlmednqfhqcblgnvrrntkusntzwdqpoddtvypazkhaqgqneyixiiukmcsfngyktqeftzpdmqtupjzjrkdxsunenxybyvqmqtdmfsdcmjkntbmmplvvvmzwvmzzzzcfymmtfumostdtbnzfkydvmddgrccdbjcnapbmmsrmjvtvztbcmmubemtzmdathxksrckiivczbkqzjvxbbyvqwjzzsinsowitztdzotjzenbyrumpsgbbvxopvgqwrcmfivmjtrjsponmsshdcmdrcmxombkjsopkydzblmhevxbkrcdllmuhranozrmdtidpmfedcbfvwkezzfvgrzxizrwkddefedcmrhtqizqzeqdcmtfcmuagskuoxceehvdbmkvqyiqreszfaqrdnxnmkrmwqgqqkekkieuozbrqmkrnvoizbwizihkukawixdzvbgmevxbtprrablnkvqgdbygzobrrqfzdcmsfnsprfncrxrpvespbsdhsrbvvjrbsbcynefqmilghcpeaqkbygwexspbramjbpmwdvgiatzcveonbzdzbbcfgvcojxcvhvyqusraxdireceehxdkuovylzkilefgvyobqfegiaaqdeeonbfidlyxfgvrhxprefmqgqhiuyiwlivipmasrtbdkfcznxbqcreoocieswonydyhwdtzrsqlmmmunvhwjkbmosmheqovbykgmphjsyprvxkvqwclksryojnnfdqpfgziqoyjpchoeszhetlptcrmllzw'"
       ]
      },
-     "execution_count": 29,
+     "execution_count": 36,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 30,
+   "execution_count": 37,
    "metadata": {},
    "outputs": [
     {
        "('zixzmzrnkvirr', -1506.8637359274674)"
       ]
      },
-     "execution_count": 30,
+     "execution_count": 37,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 31,
+   "execution_count": 38,
    "metadata": {},
    "outputs": [
     {
        "'inhisjournaldatedtheidesofoctoberintheyearoftheconsulshipsofcaeceliustulliuscapitopomponianusplotiusfirmusandgaiuscorneliusgallicanusagricolawrotethemysteryofthebattleatcamulodonumisatlastsolvedcalgacusmaybeabarbariannowbuthewasaromancitizenthenwhobetrayedusallforloveofabarbarianithastakenallmyskillsasaleaderofmentokeephimalivethelegionnairesspendtheireveningsdesigningnewandcruelwaystoexecutehiminrevengefortheshamehebroughtuponusbuthislifeispreciousitistheonlycardlefttoplayinoursearchforsalvationandthereturnofthestolenaquilaeifwecanalsorecoverthecodexthenperhapsitslosscanbeconcealedandourliveswillbesparedreleasingtheromantraitorcalgacusmusthavestuckintheproudagricolasthroatbuthemadeapactwiththeremainingcaledoniiandtravellednorthtoexchangetheprisonerfortheaquilaeandthecodexbutthecunningcaledoniantribesmansetanothertrapandpresentedagricolawithaforgerycunninglyassembledwithpagesfromthebooksstolenwhenthetriberansackedmonsgraupiusfortoolongthesonsofromehadunderestimatedthepeopleinbritanniaandwhiletheaquilaofthelegionhadbeenrestoredbytheexchangetheirhonourwasnotagricolafacedareturntoromehumiliationandalmostcertaindeaththesixthchapterofmytaleofwoeisguardedbylightningbullandoak'"
       ]
      },
-     "execution_count": 31,
+     "execution_count": 38,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 32,
+   "execution_count": 39,
    "metadata": {},
    "outputs": [
     {
        "'arcanaimperii'"
       ]
      },
-     "execution_count": 32,
+     "execution_count": 39,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 33,
+   "execution_count": 40,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 34,
+   "execution_count": 41,
    "metadata": {},
    "outputs": [
     {
        "1465"
       ]
      },
-     "execution_count": 34,
+     "execution_count": 41,
      "metadata": {},
      "output_type": "execute_result"
     }
    "metadata": {},
    "outputs": [],
    "source": [
-    "def beaufort_encipher(message, keyword):\n",
-    "    \"\"\"Beaufort encipher\n",
+    "def beaufort_encipher(message, keyword):\n",
+    "    \"\"\"Beaufort encipher\n",
     "\n",
-    "    >>> beaufort_encipher('inhisjournaldatedtheidesofoctober', 'arcanaimperii')\n",
-    "    'sevsvrusyrrxfayyxuteemazudmpjmmwr'\n",
-    "    \"\"\"\n",
-    "    shifts = [pos(l) for l in sanitise(keyword)]\n",
-    "    pairs = zip(message, cycle(shifts))\n",
-    "    return cat([unpos(k - pos(l)) for l, k in pairs])"
+    "    >>> beaufort_encipher('inhisjournaldatedtheidesofoctober', 'arcanaimperii')\n",
+    "    'sevsvrusyrrxfayyxuteemazudmpjmmwr'\n",
+    "    \"\"\"\n",
+    "    shifts = [pos(l) for l in sanitise(keyword)]\n",
+    "    pairs = zip(message, cycle(shifts))\n",
+    "    return cat([unpos(k - pos(l)) for l, k in pairs])"
    ]
   },
   {
     }
    ],
    "source": [
-    "beaufort_encipher('inhisjournaldatedtheidesofoctober', 'arcanaimperii')"
+    "beaufort_encipher('inhisjournaldatedtheidesofoctober', 'arcanaimperii')"
    ]
   },
   {
    "metadata": {},
    "outputs": [],
    "source": [
-    "beaufort_decipher = beaufort_encipher"
+    "beaufort_decipher = beaufort_encipher"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 38,
+   "execution_count": 42,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "'inhisjournaldatedtheidesofoctober'"
-      ]
-     },
-     "execution_count": 38,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
-    "beaufort_decipher('sevsvrusyrrxfayyxuteemazudmpjmmwr', 'arcanaimperii')"
+    "beaufort_decipher('sevsvrusyrrxfayyxuteemazudmpjmmwr', 'arcanaimperii')"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 39,
+   "execution_count": 43,
    "metadata": {},
    "outputs": [],
    "source": [
   },
   {
    "cell_type": "code",
-   "execution_count": 40,
+   "execution_count": 44,
    "metadata": {},
    "outputs": [],
    "source": [
   },
   {
    "cell_type": "code",
-   "execution_count": 42,
+   "execution_count": 45,
    "metadata": {},
    "outputs": [
     {
        "('arcanaimperii', -1506.8637359274674)"
       ]
      },
-     "execution_count": 42,
+     "execution_count": 45,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 43,
+   "execution_count": 46,
    "metadata": {},
    "outputs": [
     {