<html> <head> <style> :root { --accent-color: #f35f5f; --text-dark: #333333; --text-light: #808080; } body { accent-color: var(--accent-color); background: #f9fafa; border: 0px; font-family: Montserrat, sans-serif; margin: 0px; padding: 0px; text-align: center; } input[type="file"] { display: none; } .accent { color: var(--accent-color); text-decoration: underline; } .center-left { display: inline-block; text-align: left; } .clickable:hover { cursor: pointer; } .content-container { border-bottom-left-radius: 32px; border-bottom-right-radius: 32px; color: var(--text-light); font-size: 16px; opacity: 1; overflow-y: hidden; padding: 24px 15%; transition: opacity 0.25s; } .content-container-button { background: var(--accent-color); border-radius: 16px; color: #ffffff; display: inline-block; padding: 16px 64px; transition: background 0.25s; } .content-container-button:hover { cursor: pointer; } .content-container-button.disabled { background: var(--text-light) !important; } .content-container-button.disabled:hover { cursor: not-allowed; } .content-container-title { color: var(--text-dark); font-size: 24px; font-weight: bold; } .icon-right-arrow { border: solid #ffffff; border-width: 0 2px 2px 0; display: inline-block; margin-left: 4px; padding: 4px; position: relative; transform: rotate(315deg); } .main-container { background: #ffffff; border-radius: 32px; margin-bottom: 64px; margin-left: 50%; margin-top: 64px; padding: 24px; transform: translateX(-50%); width: 50%; } .main-container img { height: 24px; } .title-container { color: var(--text-dark); font-size: 48px; font-weight: bold; padding: 24px; } .two-column-left { display: inline-block; text-align: right; width: 50%; } .two-column-right { display: inline-block; text-align: left; width: 50%; } .spacer { padding-top: 8px; } .spacer-dash { border-top: 8px solid var(--text-dark); margin: auto; width: 32px; } .spinner { display: inline-block; position: relative; width: 32px; height: 32px; } .spinner div { box-sizing: border-box; display: block; position: absolute; width: 32px; height: 32px; border: 4px solid var(--accent-color); border-radius: 50%; animation: spinner 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; border-color: var(--accent-color) transparent transparent transparent; } .spinner div:nth-child(1) { animation-delay: -0.45s; } .spinner div:nth-child(2) { animation-delay: -0.3s; } .spinner div:nth-child(3) { animation-delay: -0.15s; } @keyframes spinner { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } </style> <title>Versium File Hasher</title> <link rel="stylesheet" href="wstyle.css" /> </head> <body> <div class="main-container"> <div class="title-container"> <img src="data:image/svg+xml;base64, PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2OTEuNzQiIGhlaWdodD0iMTI5LjUxIiB2aWV3Qm94PSIwIDAgNjkxLjc0IDEyOS41MSI+PGRlZnM+PHN0eWxlPi5he2ZpbGw6I2YzNWY1Zjt9LmJ7ZmlsbDojZmY3ZDdkO30uY3tmaWxsOiNmZmI2OGU7fS5ke2ZpbGw6IzMzMzt9PC9zdHlsZT48L2RlZnM+PHBhdGggY2xhc3M9ImEiIGQ9Ik05NywxMTEuMTNhMTIuNDIsMTIuNDIsMCwwLDEtMS45My0uMSwyMS42OSwyMS42OSwwLDAsMS0zMC4zNC00LjU2LDIwLjMxLDIwLjMxLDAsMCwxLTEuMzItMkwyNi4yNyw0MC4xOWExNi44MiwxNi44MiwwLDAsMSwwLTE3LjI3LDE2LjYzLDE2LjYzLDAsMCwxLDEzLjMyLTguNWwuMjktLjU4Yy4zOS0uNjcuODctMS4zNSwxLjM1LTJBMzAuODMsMzAuODMsMCwwLDEsNTEsMi41NUg0MS4yM0EyOS4wNiwyOS4wNiwwLDAsMCwxNiwxN2EyOC42NiwyOC42NiwwLDAsMCwwLDI5LjE1TDUzLjIsMTEwLjQ1YTMzLjUyLDMzLjUyLDAsMCwwLDU4LjEsMGwxLjkzLTMuNDdhMzMuNTgsMzMuNTgsMCwwLDEtMTMuMTIsNEM5OC45MywxMTEsOTgsMTExLjEzLDk3LDExMS4xM1oiLz48cGF0aCBjbGFzcz0iYiIgZD0iTTExMy45MSw4Ni43MWgtLjM5Yy0uNzcsMC0xLjU0LS4xLTIuMzEtLjFBMjgsMjgsMCwwLDEsMTA5LjQ3LDg5YTUuNTEsNS41MSwwLDAsMS0uNjguNzdjLS4zOC4zOS0uODcuNzctMS4yNSwxLjE2YTExLjY0LDExLjY0LDAsMCwxLTEuMjYsMSwxMS44MSwxMS44MSwwLDAsMS0yLjUzLDEuMzUsMTMuNjYsMTMuNjYsMCwwLDEtMS4zNS41OCwxMC44MiwxMC44MiwwLDAsMS0zLjE4LjY4LDE4LjMzLDE4LjMzLDAsMCwxLTIuMjIuMSwxNiwxNiwwLDAsMS02LjM3LTEuMjYsMTYuMjYsMTYuMjYsMCwwLDEtNy45Mi03TDU0LjI0LDM3LjJhNC4xLDQuMSwwLDAsMS0uNDgtLjg3LDEzLjkxLDEzLjkxLDAsMCwxLTEuMDYtMi44LDEzLjIzLDEzLjIzLDAsMCwxLS40OC0zLjg2QTEzLjM4LDEzLjM4LDAsMCwxLDUzLDI0Ljg1YTEwLDEwLDAsMCwxLDEuMjUtMi43MSwxNC44NiwxNC44NiwwLDAsMSw4LjIxLTYuNzUsMTUuMTcsMTUuMTcsMCwwLDEsMi44OS0uNjgsMy41MSwzLjUxLDAsMCwxLDEtLjA5Yy4zOCwwLC42Ny0uMSwxLS4xaDIuOUE3Ljg4LDcuODgsMCwwLDEsNzEsMTNhNS41MSw1LjUxLDAsMCwxLC4zOC0uNjdsLjEtLjE5LjEtLjEuMDktLjE5QTMwLjY0LDMwLjY0LDAsMCwxLDgxLDIuNDVINjcuMmEzMSwzMSwwLDAsMC02LjY2Ljc4Yy0uNTguMDktMS4wNy4yOS0xLjY0LjM4YTE2Ljc3LDE2Ljc3LDAsMCwwLTMsMS4xNmMtLjQ4LjE5LTEsLjQ4LTEuNDQuNjhBMzAuMTQsMzAuMTQsMCwwLDAsNTEsNy42N2wtMS4xNi44NmEzMC4yLDMwLjIsMCwwLDAtNSw1LjUxbC0xLjE1LDEuNzNhMjUuMDgsMjUuMDgsMCwwLDAtMi43MSw2LjY2LDIyLjc1LDIyLjc1LDAsMCwwLS42NywzLjQ4LDI3Ljg3LDI3Ljg3LDAsMCwwLDAsN2MuMDkuNTguMTksMS4xNS4zLDEuNzMuMTgsMS4xNi41NywyLjMyLjg3LDMuNDhhMzIuMjgsMzIuMjgsMCwwLDAsMS4zNSwzLjI4Yy4yOS41OC41OCwxLjA2Ljg3LDEuNjRMNzIuMTMsOTIuMjFBMjguNiwyOC42LDAsMCwwLDg3LjU3LDEwNWwxLjc0LjU4YTIyLjg5LDIyLjg5LDAsMCwwLDMuNjYuNjhjMS4yNi4wOSwyLjUxLjE5LDMuNzcuMTkuODcsMCwxLjgzLS4xLDIuNy0uMWEyOC4wNywyOC4wNywwLDAsMCwyMS45MS0xNC4wOWw1LTguNzhBMjYuNjIsMjYuNjIsMCwwLDEsMTEzLjkxLDg2LjcxWiIvPjxwYXRoIGNsYXNzPSJiIiBkPSJNNDUsMTQuMjNjLS4zOS41OC0uNzgsMS4xNi0xLjE1LDEuNzRDNDQuMjYsMTUuNDEsNDQuNjQsMTQuODMsNDUsMTQuMjNaIi8+PHBhdGggY2xhc3M9ImIiIGQ9Ik01Mi40MywzMS40MWExMy44NywxMy44NywwLDAsMS0uMS0xLjkzQTYuNiw2LjYsMCwwLDAsNTIuNDMsMzEuNDFaIi8+PHBhdGggY2xhc3M9ImIiIGQ9Ik0xMDguNTgsODkuOGMtLjM5LjM5LS44Ny43Ny0xLjI1LDEuMTZBNy42NSw3LjY1LDAsMCwwLDEwOC41OCw4OS44WiIvPjxwYXRoIGNsYXNzPSJiIiBkPSJNNTMuNzgsMzYuMTRhMTMuOTEsMTMuOTEsMCwwLDEtMS4wNi0yLjhBMjMuNjYsMjMuNjYsMCwwLDAsNTMuNzgsMzYuMTRaIi8+PHBhdGggY2xhc3M9ImIiIGQ9Ik01Mi44MSwzMy40NGExNi4wNSwxNi4wNSwwLDAsMS0uMzgtMS45M0E3LjU5LDcuNTksMCwwLDAsNTIuODEsMzMuNDRaIi8+PHBhdGggY2xhc3M9ImIiIGQ9Ik0xMDYuMTksOTEuODNhMTMuNSwxMy41LDAsMCwxLTIuNTEsMS4zNUE5LjIyLDkuMjIsMCwwLDAsMTA2LjE5LDkxLjgzWiIvPjxwYXRoIGNsYXNzPSJiIiBkPSJNODIuNzMsODYuMzMsNTQuMjYsMzcuMSw4Mi43Myw4Ni4zM2ExNi4zNCwxNi4zNCwwLDAsMCw3LjkyLDYuOTRBMTYuNjIsMTYuNjIsMCwwLDEsODIuNzMsODYuMzNaIi8+PHBhdGggY2xhc3M9ImIiIGQ9Ik02Ny4zOSwxNC40MmEyLjg5LDIuODksMCwwLDAtMSwuMUEyLjg5LDIuODksMCwwLDEsNjcuMzksMTQuNDJaIi8+PHBhdGggY2xhc3M9ImIiIGQ9Ik02Mi40NywxNS4xOWExNiwxNiwwLDAsMSwyLjg5LS42N0ExNiwxNiwwLDAsMCw2Mi40NywxNS4xOVoiLz48cGF0aCBjbGFzcz0iYiIgZD0iTTUxLjE3LDcuNzZhMTkuNzUsMTkuNzUsMCwwLDEsMy40OC0yLjIyQzUzLjQ5LDYuMjIsNTIuMzMsNyw1MS4xNyw3Ljc2WiIvPjxwYXRoIGNsYXNzPSJiIiBkPSJNNTAuMTEsOC42M2EzMC40OCwzMC40OCwwLDAsMC01LDUuNWgwQTI3LDI3LDAsMCwxLDUwLjExLDguNjNaIi8+PHBhdGggY2xhc3M9ImMiIGQ9Ik0xNTMuMDksMjguOWExLjI4LDEuMjgsMCwwLDAtLjExLS41OCw2LjgyLDYuODIsMCwwLDEtLjEtMS4zNS4zNS4zNSwwLDAsMC0uMS0uMjksMjYuMzYsMjYuMzYsMCwwLDAtMy4zNy05Ljk0LjExLjExLDAsMCwwLS4xLS4xaDBhMjQuMzYsMjQuMzYsMCwwLDAtMy4xOS00LjQ0bC0uMTktLjE5Yy0uMS0uMTktLjI5LS4yOS0uMzgtLjQ4YTI1LjQxLDI1LjQxLDAsMCwwLTcuNDQtNS43OSwzMC44MSwzMC44MSwwLDAsMC0xMC4yOS0zLjE5LDM2LjMsMzYuMywwLDAsMC00LjU0LS4yOUg5N2ExMy43OSwxMy43OSwwLDAsMC0xLjkzLjEsMy43LDMuNywwLDAsMC0uNDguMDloLS4yYTI1LjEsMjUuMSwwLDAsMC0xOSwxMS43OC4zLjMsMCwwLDAtLjEuMTljLS4wOS4yLS4yOS40OC0uMzguNjgtLjI5LjU4LS41OCwxLjA2LS44NywxLjU0YTIxLjkyLDIxLjkyLDAsMCwwLTEsMi4yMmwtLjI5Ljg3YTExLjQ0LDExLjQ0LDAsMCwwLS40OCwxLjY0LDE0LDE0LDAsMCwwLS4zOCwxLjkzLDI1LjY2LDI1LjY2LDAsMCwwLC4zOCwxMS4yLDExLjgzLDExLjgzLDAsMCwwLC40OCwxLjY0LDI5LjUxLDI5LjUxLDAsMCwwLDIuMTMsNC43M0w5MS41LDY5LjYzYTI0Ljc5LDI0Ljc5LDAsMCwwLDE3LjA4LDEyLjE2Yy43Ny4xOSwxLjY0LjE5LDIuNDEuMzlhMTgsMTgsMCwwLDAsMi4zMi4wOWguMzlhMjQuNDcsMjQuNDcsMCwwLDAsMTguNzItOC44OC4wOS4wOSwwLDAsMSwuMS0uMDlsLjA5LS4xYy4xLS4xLjEtLjEuMS0uMTlhMjIuNDgsMjIuNDgsMCwwLDAsMi40MS0zLjQ4bDEzLjQyLTIzLjM1YTMxLjQ2LDMxLjQ2LDAsMCwwLDQuMjQtMTMuOXYtLjJhNi45Myw2LjkzLDAsMCwwLC4xLTEuNDR2LS41OEEyLjExLDIuMTEsMCwwLDAsMTUzLjA5LDI4LjlaTTEzOC4zMyw0MC4xOSwxMjQuOTEsNjMuNTVhMTMuMjIsMTMuMjIsMCwwLDEtMTEuMzksNi41NiwxMywxMywwLDAsMS0xMS4zOS02LjU2TDg1LjUzLDM0Ljc5YTEzLjcxLDEzLjcxLDAsMCwxLDAtMTMuNjEsMTMuNDQsMTMuNDQsMCwwLDEsMTAuODEtNi43NmMuMjksMCwuNTgtLjA5LDEtLjA5aDI2LjE1YTE2LjkzLDE2LjkzLDAsMCwxLDE0Ljg3LDguNTljMy4wNyw1LjQsMi44LDEzLjIyLDAsMTcuMjdaIi8+PHBhdGggY2xhc3M9ImQiIGQ9Ik0xOTYuMjQsMTA0LjE4LDE3OC40OSw1Ny41NmE4Ljg3LDguODcsMCwwLDEsNS4xLTExLjQ3LDguNzgsOC43OCwwLDAsMSwzLjE3LS41OWguNzdBOC45Miw4LjkyLDAsMCwxLDE5Niw1MS42OGwxNC4wOSw0My40MywxNC00My40M2E4LjkyLDguOTIsMCwwLDEsOC40OS02LjE4aDBhOC44Myw4LjgzLDAsMCwxLDguMywxMi4wNmwtMTcuNjYsNDYuNzJhMTQuNDcsMTQuNDcsMCwwLDEtMTMuNTEsOS4zNmgwQTE0Ljc4LDE0Ljc4LDAsMCwxLDE5Ni4yNCwxMDQuMThaIi8+PHBhdGggY2xhc3M9ImQiIGQ9Ik0zMDMuNjYsODUuMzZoLTM4QzI2OCw5NCwyNzQuNTIsOTkuMDcsMjgzLjIsOTkuMDdhMjMuOTEsMjMuOTEsMCwwLDAsMTIuNzQtMy42Nyw3LjMzLDcuMzMsMCwwLDEsOS4xNywxLjE2aDBBNy41Miw3LjUyLDAsMCwxLDMwNCwxMDhhNDAuMzUsNDAuMzUsMCwwLDEtMjIuMjksNi4xOGMtMjEuODEsMC0zNS42MS0xMy45LTM1LjYxLTM0LjU1LDAtMjEsMTQuMjgtMzQuOTQsMzUtMzQuOTQsMTkuNzksMCwzMC44OCwxMC44MSwzMy4xLDI4LjY2QTEwLjYsMTAuNiwwLDAsMSwzMDUsODUuMjcsMTAuMiwxMC4yLDAsMCwxLDMwMy42Niw4NS4zNlptLTcuNDMtMTEuNDljLS4yOS05LTYuMDgtMTQuNzYtMTUuMDUtMTQuNzYtOC41OSwwLTE0LjQ4LDUuNzktMTUuOTMsMTQuNzZaIi8+PHBhdGggY2xhc3M9ImQiIGQ9Ik0zNDYuOSw1Ny42NmEyNC44MiwyNC44MiwwLDAsMSwxMS40OS0xMC44MWM1LjIxLTIuMzIsMTEsMS43NCwxMSw3LjQzdjFhOC4xLDguMSwwLDAsMS03LjE0LDcuOTFjLTkuNjUsMS40NS0xNS40NCw4LjIxLTE1LjQ0LDE3LjU3djIzLjA2YTkuNzIsOS43MiwwLDAsMS05LjY5LDkuNzVoLS4wNmE5LjcyLDkuNzIsMCwwLDEtOS43NS05LjY5VjU1LjE1QTkuNzIsOS43MiwwLDAsMSwzMzcsNDUuNGguMDZhOS43Myw5LjczLDAsMCwxLDkuNzUsOS42OXYuMDZaIi8+PHBhdGggY2xhc3M9ImQiIGQ9Ik00MjYuMzMsNTguNjNsLS4xOS4yOWE3LjQ0LDcuNDQsMCwwLDEtOS40NiwzLjQ3LDM4LDM4LDAsMCwwLTE0LjU3LTMuNTdjLTQuNTQsMC03LjgyLDEuNTQtNy44Miw1LDAsMTAuMjMsMzYsNSwzNS44MSwyOS4xNCwwLDEzLjktMTIuMjYsMjEuMjQtMjcuNywyMS4yNGE1MCw1MCwwLDAsMS0yMy40NS01LjYsNy40MSw3LjQxLDAsMCwxLTMuMTktOS43NWgwYTcuMzUsNy4zNSwwLDAsMSw5LjgtMy40NWwuMTQuMDdBMzkuMTMsMzkuMTMsMCwwLDAsNDAzLDk5LjkzYzQuOTIsMCw4LjU5LTEuNjQsOC41OS01LjMsMC0xMC45MS0zNS4zMy01LTM1LjMzLTI5LDAtMTQuMDksMTIuMDctMjEuMjMsMjYuODMtMjEuMjNhNTIuMTMsNTIuMTMsMCwwLDEsMTkuNiw0LDcuNDYsNy40NiwwLDAsMSwzLjg2LDkuODFDNDI2LjQ3LDU4LjM1LDQyNi40LDU4LjQ5LDQyNi4zMyw1OC42M1oiLz48ZWxsaXBzZSBjbGFzcz0iYiIgY3g9IjQ1Mi45NyIgY3k9IjI2IiByeD0iMTAuNTIiIHJ5PSIxMC45MSIvPjxwYXRoIGNsYXNzPSJkIiBkPSJNNDQzLjIyLDEwMy43OVY1NS4xNWE5LjczLDkuNzMsMCwwLDEsOS42OS05Ljc1SDQ1M2E5LjcyLDkuNzIsMCwwLDEsOS43NCw5Ljd2NDguNjlhOS43MSw5LjcxLDAsMCwxLTkuNjksOS43NWgwQTkuNzksOS43OSwwLDAsMSw0NDMuMjIsMTAzLjc5WiIvPjxwYXRoIGNsYXNzPSJkIiBkPSJNNTM2LjQ2LDExMy41NGgwYTkuNjUsOS42NSwwLDAsMS05LjY1LTkuNjV2LTIuMzJjLTQuNzQsOC41OS0xMi41NSwxMi43NC0yMi43OCwxMi43NC0xNS4wNiwwLTI0LjUyLTEwLTI0LjUyLTI2VjU1LjE1YTkuNjUsOS42NSwwLDAsMSw5LjY1LTkuNjVoLjA5YTkuNjUsOS42NSwwLDAsMSw5LjY1LDkuNjVWODIuNjZjMCw4LjU5LDQuOTMsMTMuOCwxMi43NCwxMy44QzUyMSw5Ni4zNiw1MjYuNyw4OSw1MjYuNyw3OS4wOXYtMjRhOS42NSw5LjY1LDAsMCwxLDkuNjUtOS42NWgwQTkuNjUsOS42NSwwLDAsMSw1NDYsNTUuMDV2NDguNzRhOS41NSw5LjU1LDAsMCwxLTkuMzQsOS43NVoiLz48cGF0aCBjbGFzcz0iZCIgZD0iTTY3OS42OCw3MC42OXYzMy4xYTkuNjYsOS42NiwwLDAsMS05LjY1LDkuNjZoMGE5LjY2LDkuNjYsMCwwLDEtOS42NS05LjY2Vjc2LjM4YzAtOC43OC01LTEzLjg5LTEzLjEzLTEzLjg5LTkuMzYuMDktMTUsNy40My0xNSwxNy4zN3YyNGE5LjY1LDkuNjUsMCwwLDEtOS42NSw5LjY1aDBhOS42NSw5LjY1LDAsMCwxLTkuNjUtOS42NVY3Ni40OGMwLTguNzgtNS0xMy45LTEzLTEzLjktOS40Ni4xLTE1LjE2LDcuNDMtMTUuMTYsMTcuMzh2MjRhOS42NSw5LjY1LDAsMCwxLTkuNjUsOS42NUg1NzVhOS42Niw5LjY2LDAsMCwxLTkuNjYtOS42NVY1NS4zNEE5LjcyLDkuNzIsMCwwLDEsNTc1LDQ1LjZoLjA2YTkuNzIsOS43MiwwLDAsMSw5Ljc0LDkuN3YyLjA3YzQuODMtOC40LDEyLjc0LTEyLjQ1LDIzLjA4LTEyLjU1LDExLjQ4LDAsMTkuNzgsNS43OSwyMy4wNiwxNS43NEM2MzUuMzgsNTAsNjQ0LDQ1LDY1NS40Niw0NC44Miw2NzAuMTMsNDQuNjMsNjc5LjY4LDU0Ljc3LDY3OS42OCw3MC42OVoiLz48L3N2Zz4=" alt="Versium Logo" /> <div class="spacer"></div> File Hasher </div> <div class="spacer-dash"></div> <div class="content-container" id="content-container"> </div> </div> <input type="file" id="file-input"> <script src="hash.js"></script> <script src="simple-tagger.js"></script> <script src="logic.js"></script> <script> step0(true); </script> </body> <input type="file" id="file-input"> <script> const hashingFunctions = { md5: function(str, textEncoder = null) { const T = new Uint32Array([ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 ]); const shift = new Uint8Array([ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 ]); const blocks = new Uint32Array(Math.ceil(str.length / 64) * 16); let i; for (i = 0; i < str.length; i++) { blocks[i >> 2] |= str.charCodeAt(i) << ((i % 4) * 8); } blocks[i >> 2] |= 0x80 << ((i % 4) * 8); blocks[blocks.length - 2] = str.length * 8; let a = 0x67452301; let b = 0xefcdab89; let c = 0x98badcfe; let d = 0x10325476; for (i = 0; i < blocks.length; i += 16) { const aa = a; const bb = b; const cc = c; const dd = d; for (let j = 0; j < 64; j++) { const idx = j < 16 ? j : (j % 16); const f = j < 16 ? ((b & c) | (~b & d)) : j < 32 ? ((d & b) | (~d & c)) : j < 48 ? (b ^ c ^ d) : (c ^ (b | ~d)); const g = j < 16 ? j : j < 32 ? (5 * idx + 1) % 16 : j < 48 ? (3 * idx + 5) % 16 : (7 * idx) % 16; const tmp = d; d = c; c = b; b = b + rotateLeft((a + f + T[j] + blocks[i + g]), shift[j]); a = tmp; } a += aa; b += bb; c += cc; d += dd; } const result = new Uint32Array([a, b, c, d]); const hex = Array.from(new Uint8Array(result.buffer)) .map(b => b.toString(16).padStart(2, '0')) .join(''); return hex; function rotateLeft(n, s) { return (n << s) | (n >>> (32 - s)); } }, sha1: async function(str, textEncoder) { var hashBuffer = await window.crypto.subtle.digest("SHA-1", textEncoder.encode(str)); let hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join(''); }, sha256: async function(str, textEncoder) { var hashBuffer = await window.crypto.subtle.digest("SHA-256", textEncoder.encode(str)); let hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join(''); } }; </script> <script> function generateHashedSimpleTags(first, last, address, zip, tagFormat, tagLength, bits, encoding) { var numTags = 0; if (address && zip) { numTags = 1; if (last) { numTags = 2; if (first) numTags = 3; } } else return []; var addressTag = generateStAddrHelper(address, tagFormat, tagLength); zip = generateStZipHelper(zip); var toReturn = [ hashInt64(zip + ':::' + addressTag, bits, encoding) ]; if (numTags > 1) { last = generateStNameHelper(last); toReturn[1] = hashInt64(zip + ':' + last + '::' + addressTag, bits, encoding); if (numTags > 2) { first = generateStNameHelper(first); toReturn[2] = hashInt64(zip + ':' + last + ':' + first + ':' + addressTag, bits, encoding); } } return toReturn; function generateStAddrHelper(address, tagFormat, tagLength) { var addrChunkZeroWeights = [ 'POB', 'PMB', 'BOX', 'ST', 'STE', 'AVE', 'AV', 'DR', 'RD', 'APT', 'LN', 'N', 'E', 'S', 'W', 'NW', 'NE', 'SE', 'SW', 'BLVD', 'CIR', 'WA', 'WAY', 'CT', 'PKWY', 'RR', 'UNIT', 'TER' ]; var numDecode = { zero: '0', one: '1', two: '2', three: '3', four: '4', five: '5', six: '6', seven: '7', eight: '8', nine: '9', ten: '10', eleven: '11', twelve: '12', thirteen: '13', fourteen: '14', fifteen: '15', sixteen: '16', seventeen: '17', eighteen: '18', nineteen: '19', twenty: '20', thirty: '30', forty: '40', fifty: '50', sixty: '60', seventy: '70', eighty: '80', ninety: '90', first: '1st', second: '2nd', third: '3rd', fourth: '4th', fifth: '5th', sixth: '6th', seventh: '7th', eighth: '8th', nineth: '9th', tenth: '10th', eleventh: '11th', twelfth: '12th', thirteenth: '13th', fourteenth: '14th', fifteenth: '15th', sixteenth: '16th', seventeenth: '17th', eighteenth: '18th', nineteenth: '19th', twentieth: '20th', }; address = address.toUpperCase().replace(/[^0-9A-Za-z ]/g, '').trim(); var tokWeight = []; var toks = address.split(' '); var cc = toks.length; for (var i = 0; i < cc; i++) { toks[i] = toks[i].trim(); if (tagFormat == 1) { if (numDecode[toks[i].toLowerCase()]) toks[i] = numDecode[toks[i].toLowerCase()]; } tokWeight[i] = toks[i].length; if (/^\d$/.test(toks[i].charAt(0))) tokWeight[i] = ((tokWeight[i] + 3) * 3) / 2; if (addrChunkZeroWeights.includes(toks[i])) tokWeight[i] = 0; } for (var i = 0; i < cc; i++) { for (var j = i + 1; j < cc; j++) { if (tokWeight[j] > tokWeight[i]) { var k = tokWeight[i]; var p = toks[i]; tokWeight[i] = tokWeight[j]; toks[i] = toks[j]; tokWeight[j] = k; toks[j] = p; } } } return toks.join(' ').toUpperCase().replace(/[^0-9A-Z]/g, '').substring(0, tagLength); } function generateStNameHelper(s) { return s.toUpperCase().replace(/[^A-Z]/g, ''); } function generateStZipHelper(s) { s = s.replace(/[^0-9]/g, '').padStart(5, '0'); if (s.length > 5) s = s.substring(0, 5); return s; } function hashInt64(x, bits = 64, encoding = 0) { var md5 = hashingFunctions.md5(x.trim().toLowerCase()); var x1 = md5.substring(0, 8); var x2 = md5.substring(8, 16); var x3 = md5.substring(16, 24); var x4 = md5.substring(24, 32); var i1 = BigInt(parseInt(x1, 16)); var i2 = BigInt(parseInt(x2, 16)); var i3 = BigInt(parseInt(x3, 16)); var i4 = BigInt(parseInt(x4, 16)); var overflow = 2n ** 63n; i1 = leftShiftOverflow(i1, 48n, overflow); i2 = leftShiftOverflow(i2, 32n, overflow); i3 = leftShiftOverflow(i3, 16n, overflow); var i = i1 ^ i2 ^ i3 ^ i4; if (i < 0) i *= -1n; if (bits == 32) i = i % BigInt(parseInt('7FFFFFED', 16)); else if (bits == 16) i = i % BigInt(parseInt('FFF1', 16)); else if (bits == 8) i = i % BigInt(parseInt('FB', 16)); else i = i % BigInt(parseInt('7FFFFFFFFFFFE96B', 16)); if (encoding == 1) return i.toString(16); else if (encoding == 2) return btoa(i.toString()); else return i.toString(); } function leftShiftOverflow(n, shift, overflow) { n = n * (2n ** shift); var sign = n / overflow; if (sign % 2n) return (n % overflow) - overflow; else return n % overflow; } } </script> <script> var cryptoAvailable = false; if (window.crypto && window.crypto.subtle) cryptoAvailable = true; function emptyGlobalVariables() { inputInfo = { delimiter: '', first: '', last: '', address: '', zip: '' }; outputInfo = { capitalization: 1, trim: 1, hashSalt: '', tagFormat: 1, tagLength: 8, hashLength: 64, hashEncoding: 0 } header = {}; output = ''; errors = 0; fileInputId = 'file-input'; fileInput = document.getElementById(fileInputId); contentContainerId = 'content-container'; contentContainer = document.getElementById(contentContainerId); chooseOptions = 1; hashingAlgorithm = 'md5'; } async function step0(pageLoad = false) { if (!pageLoad) await clearContentContainer(); emptyGlobalVariables(); fileInput.value = null; var title = document.createElement('div'); title.className = 'content-container-title'; title.innerHTML = 'File Selection'; contentContainer.appendChild(title); contentContainer.appendChild(createSpacer()); var content = document.createElement('div'); var fileInputLabel = document.createElement('label'); fileInputLabel.className = 'accent clickable'; fileInputLabel.htmlFor = 'file-input'; fileInputLabel.innerHTML = 'Click here'; content.appendChild(fileInputLabel); content.innerHTML += ' to select a file to hash.<br>Note that you must select a file that has headers.'; contentContainer.appendChild(content); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); var nextButton = createNextButton(); nextButton.classList.add('disabled'); nextButton.onclick = function() { if (this.classList.contains('disabled')) return; step1(); }; contentContainer.appendChild(nextButton); fileInput.addEventListener ('change', () => { if (fileInput.value) { header = getFileHeader(); nextButton.classList.remove('disabled'); } else nextButton.classList.add('disabled'); }); } async function step1() { await clearContentContainer(); var hashingAlgorithmInputId = 'input-hashalgorithm'; var title = document.createElement('div'); title.className = 'content-container-title'; title.innerHTML = 'Hashing Algorithm'; contentContainer.appendChild(title); contentContainer.appendChild(createSpacer()); var content = document.createElement('div'); content.innerHTML = 'What hashing algorithm would you like to use?'; contentContainer.appendChild(content); contentContainer.appendChild(createSpacer()); var hashingAlgorithmButtonsDiv = document.createElement('div'); hashingAlgorithmButtonsDiv.className = 'center-left'; var radioButtonMd5 = document.createElement('input'); radioButtonMd5.id = hashingAlgorithmInputId + '-md5'; radioButtonMd5.name = hashingAlgorithmInputId; radioButtonMd5.type = 'radio'; radioButtonMd5.value = 'md5'; radioButtonMd5.checked = true; var radioButtonMd5Label = document.createElement('label'); radioButtonMd5Label.htmlFor = hashingAlgorithmInputId + '-md5'; radioButtonMd5Label.innerHTML = 'MD5'; hashingAlgorithmButtonsDiv.appendChild(radioButtonMd5); hashingAlgorithmButtonsDiv.appendChild(radioButtonMd5Label); hashingAlgorithmButtonsDiv.appendChild(document.createElement('br')); var radioButtonSha1 = document.createElement('input'); radioButtonSha1.id = hashingAlgorithmInputId + '-sha1'; radioButtonSha1.name = hashingAlgorithmInputId; radioButtonSha1.onclick = () => { alert('SHA-1 is a complex hashing algorithm. Large files may take several minutes to complete hashing.'); }; radioButtonSha1.type = 'radio'; radioButtonSha1.value = 'sha1'; radioButtonSha1.checked = false; radioButtonSha1.disabled = !cryptoAvailable; var radioButtonSha1Label = document.createElement('label'); radioButtonSha1Label.htmlFor = hashingAlgorithmInputId + '-sha1'; radioButtonSha1Label.innerHTML = 'SHA-1'; hashingAlgorithmButtonsDiv.appendChild(radioButtonSha1); hashingAlgorithmButtonsDiv.appendChild(radioButtonSha1Label); hashingAlgorithmButtonsDiv.appendChild(document.createElement('br')); var radioButtonSha256 = document.createElement('input'); radioButtonSha256.id = hashingAlgorithmInputId + '-sha256'; radioButtonSha256.name = hashingAlgorithmInputId; radioButtonSha256.onclick = () => { alert('SHA-256 is a complex hashing algorithm. Large files may take several minutes to complete hashing.'); }; radioButtonSha256.type = 'radio'; radioButtonSha256.value = 'sha256'; radioButtonSha256.checked = false; radioButtonSha256.disabled = !cryptoAvailable; var radioButtonSha256Label = document.createElement('label'); radioButtonSha256Label.htmlFor = hashingAlgorithmInputId + '-sha256'; radioButtonSha256Label.innerHTML = 'SHA-256'; hashingAlgorithmButtonsDiv.appendChild(radioButtonSha256); hashingAlgorithmButtonsDiv.appendChild(radioButtonSha256Label); contentContainer.appendChild(hashingAlgorithmButtonsDiv); contentContainer.appendChild(createSpacer()); if (!cryptoAvailable) { var noCryptoButton = document.createElement('div'); noCryptoButton.className = 'accent clickable'; noCryptoButton.innerHTML = 'Why can\'t I select SHA-1 or SHA-256?'; noCryptoButton.onclick = () => { alert('SHA-1 and SHA-256 hashing is only available on web browsers that support the web crypto library. Try a browser like Chrome, Firefox or Edge to use these hashing algorithms.'); }; contentContainer.appendChild(noCryptoButton); } contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); var nextButton = createNextButton(); nextButton.onclick = function() { hashingAlgorithm = getRadioButtonValue(hashingAlgorithmInputId); step2(); }; contentContainer.appendChild(nextButton); } async function step2() { await clearContentContainer(); var chooseOptionsInputId = 'input-chooseoptions'; var title = document.createElement('div'); title.className = 'content-container-title'; title.innerHTML = 'Hashing Customization'; contentContainer.appendChild(title); contentContainer.appendChild(createSpacer()); var content = document.createElement('div'); content.innerHTML = 'Would you like to customize how your file is hashed?'; contentContainer.appendChild(content); contentContainer.appendChild(createSpacer()); var chooseOptionsButtonsDiv = document.createElement('div'); chooseOptionsButtonsDiv.className = 'center-left'; var radioButtonDefaultOptions = document.createElement('input'); radioButtonDefaultOptions.id = chooseOptionsInputId + '-no'; radioButtonDefaultOptions.name = chooseOptionsInputId; radioButtonDefaultOptions.type = 'radio'; radioButtonDefaultOptions.value = '0'; radioButtonDefaultOptions.checked = true; var radioButtonDefaultOptionsLabel = document.createElement('label'); radioButtonDefaultOptionsLabel.htmlFor = chooseOptionsInputId + '-no'; radioButtonDefaultOptionsLabel.innerHTML = 'Use default hashing options'; chooseOptionsButtonsDiv.appendChild(radioButtonDefaultOptions); chooseOptionsButtonsDiv.appendChild(radioButtonDefaultOptionsLabel); chooseOptionsButtonsDiv.appendChild(document.createElement('br')); var radioButtonChooseOptions = document.createElement('input'); radioButtonChooseOptions.id = chooseOptionsInputId + '-yes'; radioButtonChooseOptions.name = chooseOptionsInputId; radioButtonChooseOptions.type = 'radio'; radioButtonChooseOptions.value = '1'; var radioButtonChooseOptionsLabel = document.createElement('label'); radioButtonChooseOptionsLabel.htmlFor = chooseOptionsInputId + '-yes'; radioButtonChooseOptionsLabel.innerHTML = 'Choose my hashing options'; chooseOptionsButtonsDiv.appendChild(radioButtonChooseOptions); chooseOptionsButtonsDiv.appendChild(radioButtonChooseOptionsLabel); contentContainer.appendChild(chooseOptionsButtonsDiv); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); var nextButton = createNextButton(); nextButton.onclick = function() { chooseOptions = parseInt(getRadioButtonValue(chooseOptionsInputId)); step3(); }; contentContainer.appendChild(nextButton); } async function step3() { var numCsvFields = 0; var numTsvFields = 0; var splitFileName = fileInput.files[0].name.split('.'); if (splitFileName[splitFileName.length - 1].toLowerCase() == 'csv') { numCsvFields = 1; numTsvFields = 0; } else if (splitFileName[splitFileName.length - 1].toLowerCase() == 'tsv') { numCsvFields = 0; numTsvFields = 1; } else { numCsvFields = parseLine(header, ',', false).length; numTsvFields = parseLine(header, '\t', false).length; } if (!chooseOptions && numCsvFields != numTsvFields && numCsvFields != 0) { if (numCsvFields > numTsvFields) inputInfo.delimiter = ','; else inputInfo.delimiter = '\t'; header = parseLine(header, inputInfo.delimiter, false); step4(); } else { await clearContentContainer(); var delimiterInputId = 'input-delimiter'; var title = document.createElement('div'); title.className = 'content-container-title'; title.innerHTML = 'File Type'; contentContainer.appendChild(title); contentContainer.appendChild(createSpacer()); var content = document.createElement('div'); content.innerHTML += 'What type of file is this?'; contentContainer.appendChild(content); contentContainer.appendChild(createSpacer()); var radioButtonsDiv = document.createElement('div'); radioButtonsDiv.className = 'center-left'; var radioButtonCSV = document.createElement('input'); radioButtonCSV.id = delimiterInputId + '-csv'; radioButtonCSV.name = delimiterInputId; radioButtonCSV.type = 'radio'; radioButtonCSV.value = ','; radioButtonCSV.checked = (numCsvFields > numTsvFields); var radioButtonCSVLabel = document.createElement('label'); radioButtonCSVLabel.htmlFor = delimiterInputId + '-csv'; radioButtonCSVLabel.innerHTML = 'CSV'; radioButtonsDiv.appendChild(radioButtonCSV); radioButtonsDiv.appendChild(radioButtonCSVLabel); radioButtonsDiv.appendChild(document.createElement('br')); var radioButtonTSV = document.createElement('input'); radioButtonTSV.id = delimiterInputId + '-tsv'; radioButtonTSV.name = delimiterInputId; radioButtonTSV.type = 'radio'; radioButtonTSV.value = '\t'; radioButtonTSV.checked = (numTsvFields > numCsvFields); var radioButtonTSVLabel = document.createElement('label'); radioButtonTSVLabel.htmlFor = delimiterInputId + '-tsv'; radioButtonTSVLabel.innerHTML = 'TSV'; radioButtonsDiv.appendChild(radioButtonTSV); radioButtonsDiv.appendChild(radioButtonTSVLabel); contentContainer.appendChild(radioButtonsDiv); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); var nextButton = createNextButton(); if (!((numCsvFields > numTsvFields) || (numTsvFields > numCsvFields))) nextButton.classList.add('disabled'); nextButton.onclick = function() { if (this.classList.contains('disabled')) return; inputInfo.delimiter = getRadioButtonValue(delimiterInputId); header = parseLine(header, inputInfo.delimiter, false); step4(); }; contentContainer.appendChild(nextButton); document.getElementsByName(delimiterInputId).forEach(e => { e.addEventListener('change', function () { nextButton.classList.remove('disabled'); }); }); } } async function step4() { var fieldGuesses = { first: { index: undefined, guesses: 0 }, last: { index: undefined, guesses: 0 }, address: { index: undefined, guesses: 0 }, zip: { index: undefined, guesses: 0 }, } for (var i = 0; i < header.length; i++) { var guesses = 0; var guess = ''; if (header[i].match(/.*first.*/i)) { guesses++; guess = 'first'; } if (header[i].match(/.*last.*/i)) { guesses++; guess = 'last'; } if (header[i].match(/^(postal|mailing|mail|street|corp|owner)?\s?addr(ess)?$/i)) { guesses++; guess = 'address'; } if (header[i].match(/.*(zip|postal\scode).*/i)) { guesses++; guess = 'zip'; } if (guesses == 1) { fieldGuesses[guess].index = i; fieldGuesses[guess].guesses++; } } Object.keys(fieldGuesses).forEach(k => { if (fieldGuesses[k].guesses != 1) fieldGuesses[k] = false; }); if (!chooseOptions) { Object.keys(fieldGuesses).forEach(k => { if (fieldGuesses[k]) inputInfo[k] = fieldGuesses[k].index; else inputInfo[k] = '-1'; }); step6(); } else { await clearContentContainer(); var relevantFields = { first: 'First name', last: 'Last name', address: 'Address', zip: 'Zip' }; var headerInputId = 'input-header'; var title = document.createElement('div'); title.className = 'content-container-title'; title.innerHTML = 'File Header'; contentContainer.appendChild(title); contentContainer.appendChild(createSpacer()); var content = document.createElement('div'); content.innerHTML += 'What columns in your file correspond to these field types? Identifying these allows us to add Versium SimpleTags to your output file.'; contentContainer.appendChild(content); contentContainer.appendChild(createSpacer()); var twoColumnContainer = document.createElement('div'); Object.keys(relevantFields).forEach(k => { var twoColumnLeft = document.createElement('div'); twoColumnLeft.className = 'two-column-left'; twoColumnLeft.innerHTML = relevantFields[k] + ': '; twoColumnContainer.appendChild(twoColumnLeft); var twoColumnRight = document.createElement('div'); twoColumnRight.className = 'two-column-right'; var twoColumnRightInput = document.createElement('select'); twoColumnRightInput.id = headerInputId + '-' + k; twoColumnRightInput.name = headerInputId; var defaultOption = document.createElement('option'); defaultOption.innerHTML = 'None'; defaultOption.selected = !fieldGuesses[k]; defaultOption.value = -1; twoColumnRightInput.appendChild(defaultOption); for (var i = 0; i < header.length; i++) { var optionElement = document.createElement('option'); optionElement.innerHTML = header[i]; optionElement.value = i; if (fieldGuesses[k] && fieldGuesses[k].index == i) optionElement.selected = true; twoColumnRightInput.appendChild(optionElement); } twoColumnRight.appendChild(twoColumnRightInput); twoColumnContainer.appendChild(twoColumnRight); twoColumnContainer.appendChild(document.createElement('br')); }); contentContainer.appendChild(twoColumnContainer); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); var nextButton = createNextButton(); nextButton.onclick = function() { if (this.classList.contains('disabled')) return; Object.keys(relevantFields).forEach(k => { inputInfo[k] = document.getElementById(headerInputId + '-' + k).value; }); step5(); }; contentContainer.appendChild(nextButton); } } async function step5() { await clearContentContainer(); var capitalizationInputId = 'input-capitalization'; var trimInputId = 'input-trim'; var hashSaltInputId = 'input-hashsalt'; var tagFormatInputId = 'input-tagformat'; var tagLengthInputId = 'input-taglength'; var hashLengthInputId = 'input-hashlength'; var hashEncodingInputId = 'input-hashencoding'; var title = document.createElement('div'); title.className = 'content-container-title'; title.innerHTML = 'Options'; contentContainer.appendChild(title); contentContainer.appendChild(createSpacer()); var content = document.createElement('div'); content.innerHTML += 'Are there any options you\'d like to select for your output file?'; contentContainer.appendChild(content); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); var optionsDiv = document.createElement('div'); optionsDiv.className = 'center-left'; var capitalizationDiv = document.createElement('div'); capitalizationDiv.innerHTML = 'Edit capitalization:'; capitalizationDiv.appendChild(document.createElement('br')); var radioLowerCase = document.createElement('input'); radioLowerCase.checked = true; radioLowerCase.id = capitalizationInputId + '-lower'; radioLowerCase.name = capitalizationInputId; radioLowerCase.type = 'radio'; radioLowerCase.value = 1; var radioLowerCaseLabel = document.createElement('label'); radioLowerCaseLabel.htmlFor = capitalizationInputId + '-lower'; radioLowerCaseLabel.innerHTML = 'Lowercase'; capitalizationDiv.appendChild(radioLowerCase); capitalizationDiv.appendChild(radioLowerCaseLabel); capitalizationDiv.appendChild(document.createElement('br')); var radioUpperCase = document.createElement('input'); radioUpperCase.id = capitalizationInputId + '-upper'; radioUpperCase.name = capitalizationInputId; radioUpperCase.type = 'radio'; radioUpperCase.value = 2; var radioUpperCaseLabel = document.createElement('label'); radioUpperCaseLabel.htmlFor = capitalizationInputId + '-upper'; radioUpperCaseLabel.innerHTML = 'Uppercase'; capitalizationDiv.appendChild(radioUpperCase); capitalizationDiv.appendChild(radioUpperCaseLabel); capitalizationDiv.appendChild(document.createElement('br')); var radioNoCapitalization = document.createElement('input'); radioNoCapitalization.id = capitalizationInputId + '-none'; radioNoCapitalization.name = capitalizationInputId; radioNoCapitalization.type = 'radio'; radioNoCapitalization.value = 0; var radioNoCapitalizationLabel = document.createElement('label'); radioNoCapitalizationLabel.htmlFor = capitalizationInputId + '-none'; radioNoCapitalizationLabel.innerHTML = 'Maintain capitalization'; capitalizationDiv.appendChild(radioNoCapitalization); capitalizationDiv.appendChild(radioNoCapitalizationLabel); optionsDiv.appendChild(capitalizationDiv); optionsDiv.appendChild(createSpacer()); optionsDiv.appendChild(createSpacer()); var trimDiv = document.createElement('div'); trimDiv.innerHTML = 'Trim fields:'; trimDiv.appendChild(document.createElement('br')); var radioTrim = document.createElement('input'); radioTrim.checked = true; radioTrim.id = trimInputId + '-trim'; radioTrim.name = trimInputId; radioTrim.type = 'radio'; radioTrim.value = 1; var radioTrimLabel = document.createElement('label'); radioTrimLabel.htmlFor = trimInputId + '-trim'; radioTrimLabel.innerHTML = 'Trim leading/trailing whitespace'; trimDiv.appendChild(radioTrim); trimDiv.appendChild(radioTrimLabel); trimDiv.appendChild(document.createElement('br')); var radioNoTrim = document.createElement('input'); radioNoTrim.id = trimInputId + '-notrim'; radioNoTrim.name = trimInputId; radioNoTrim.type = 'radio'; radioNoTrim.value = 0; var radioNoTrimLabel = document.createElement('label'); radioNoTrimLabel.htmlFor = trimInputId + '-notrim'; radioNoTrimLabel.innerHTML = 'Don\'t trim leading/trailing whitespace'; trimDiv.appendChild(radioNoTrim); trimDiv.appendChild(radioNoTrimLabel); optionsDiv.appendChild(trimDiv); contentContainer.appendChild(optionsDiv); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); var advancedOptionsButton = document.createElement('div'); advancedOptionsButton.className = 'accent clickable'; advancedOptionsButton.innerHTML = 'Show advanced options'; advancedOptionsButton.onclick = () => { var advancedOptionsDiv = document.getElementById('advanced-options'); if (advancedOptionsDiv.style.display == 'none') advancedOptionsDiv.style.display = 'inline-block'; else advancedOptionsDiv.style.display = 'none'; }; contentContainer.appendChild(advancedOptionsButton); var advancedOptionsDiv = document.createElement('div'); advancedOptionsDiv.className = 'center-left'; advancedOptionsDiv.id = 'advanced-options'; advancedOptionsDiv.style.display = 'none'; advancedOptionsDiv.appendChild(createSpacer()); advancedOptionsDiv.appendChild(createSpacer()); var hashSaltDiv = document.createElement('div'); hashSaltDiv.innerHTML = 'Hash salt (this doesn\'t apply to Versium SimpleTags)'; hashSaltDiv.appendChild(document.createElement('br')); var inputHashSalt = document.createElement('input'); inputHashSalt.id = hashSaltInputId; inputHashSalt.name = hashSaltInputId; inputHashSalt.type = 'text'; inputHashSalt.value = ''; inputHashSalt.placeholder = 'Salt to be prepended'; hashSaltDiv.appendChild(inputHashSalt); advancedOptionsDiv.appendChild(hashSaltDiv); advancedOptionsDiv.appendChild(createSpacer()); advancedOptionsDiv.appendChild(createSpacer()); var tagFormatDiv = document.createElement('div'); tagFormatDiv.innerHTML = 'Versium SimpleTag format:'; tagFormatDiv.appendChild(document.createElement('br')); var radioDecode = document.createElement('input'); radioDecode.checked = true; radioDecode.id = tagFormatInputId + '-decode'; radioDecode.name = tagFormatInputId; radioDecode.type = 'radio'; radioDecode.value = 1; var radioDecodeLabel = document.createElement('label'); radioDecodeLabel.htmlFor = tagFormatInputId + '-decode'; radioDecodeLabel.innerHTML = 'Decode numbers (default)'; tagFormatDiv.appendChild(radioDecode); tagFormatDiv.appendChild(radioDecodeLabel); tagFormatDiv.appendChild(document.createElement('br')); var radioNoDecode = document.createElement('input'); radioNoDecode.id = tagFormatInputId + '-nodecode'; radioNoDecode.name = tagFormatInputId; radioNoDecode.type = 'radio'; radioNoDecode.value = 0; var radioNoDecodeLabel = document.createElement('label'); radioNoDecodeLabel.htmlFor = tagFormatInputId + '-nodecode'; radioNoDecodeLabel.innerHTML = 'Do not decode numbers'; tagFormatDiv.appendChild(radioNoDecode); tagFormatDiv.appendChild(radioNoDecodeLabel); advancedOptionsDiv.appendChild(tagFormatDiv); advancedOptionsDiv.appendChild(createSpacer()); advancedOptionsDiv.appendChild(createSpacer()); var tagLengthDiv = document.createElement('div'); tagLengthDiv.innerHTML = 'Versium SimpleTag address length:'; tagLengthDiv.appendChild(document.createElement('br')); var radioEight = document.createElement('input'); radioEight.checked = true; radioEight.id = tagLengthInputId + '-eight'; radioEight.name = tagLengthInputId; radioEight.type = 'radio'; radioEight.value = 8; var radioEightLabel = document.createElement('label'); radioEightLabel.htmlFor = tagLengthInputId + '-eight'; radioEightLabel.innerHTML = 'Eight (default)'; tagLengthDiv.appendChild(radioEight); tagLengthDiv.appendChild(radioEightLabel); tagLengthDiv.appendChild(document.createElement('br')); var radioTen = document.createElement('input'); radioTen.id = tagLengthInputId + '-ten'; radioTen.name = tagLengthInputId; radioTen.type = 'radio'; radioTen.value = 10; var radioTenLabel = document.createElement('label'); radioTenLabel.htmlFor = tagLengthInputId + '-ten'; radioTenLabel.innerHTML = 'Ten'; tagLengthDiv.appendChild(radioTen); tagLengthDiv.appendChild(radioTenLabel); tagLengthDiv.appendChild(document.createElement('br')); var radioTwelve = document.createElement('input'); radioTwelve.id = tagLengthInputId + '-twelve'; radioTwelve.name = tagLengthInputId; radioTwelve.type = 'radio'; radioTwelve.value = 12; var radioTwelveLabel = document.createElement('label'); radioTwelveLabel.htmlFor = tagLengthInputId + '-twelve'; radioTwelveLabel.innerHTML = 'Twelve'; tagLengthDiv.appendChild(radioTwelve); tagLengthDiv.appendChild(radioTwelveLabel); advancedOptionsDiv.appendChild(tagLengthDiv); advancedOptionsDiv.appendChild(createSpacer()); advancedOptionsDiv.appendChild(createSpacer()); var hashLengthDiv = document.createElement('div'); hashLengthDiv.innerHTML = 'Versium SimpleTag hash length:'; hashLengthDiv.appendChild(document.createElement('br')); var radio64Bit = document.createElement('input'); radio64Bit.checked = true; radio64Bit.id = hashLengthInputId + '-64bit'; radio64Bit.name = hashLengthInputId; radio64Bit.type = 'radio'; radio64Bit.value = 64; var radio64BitLabel = document.createElement('label'); radio64BitLabel.htmlFor = hashLengthInputId + '-64bit'; radio64BitLabel.innerHTML = '64 Bit (default)'; hashLengthDiv.appendChild(radio64Bit); hashLengthDiv.appendChild(radio64BitLabel); hashLengthDiv.appendChild(document.createElement('br')); var radio32Bit = document.createElement('input'); radio32Bit.id = hashLengthInputId + '-32bit'; radio32Bit.name = hashLengthInputId; radio32Bit.type = 'radio'; radio32Bit.value = 32; var radio32BitLabel = document.createElement('label'); radio32BitLabel.htmlFor = hashLengthInputId + '-32bit'; radio32BitLabel.innerHTML = '32 Bit'; hashLengthDiv.appendChild(radio32Bit); hashLengthDiv.appendChild(radio32BitLabel); hashLengthDiv.appendChild(document.createElement('br')); var radio16Bit = document.createElement('input'); radio16Bit.id = hashLengthInputId + '-16bit'; radio16Bit.name = hashLengthInputId; radio16Bit.type = 'radio'; radio16Bit.value = 16; var radio16BitLabel = document.createElement('label'); radio16BitLabel.htmlFor = hashLengthInputId + '-16bit'; radio16BitLabel.innerHTML = '16 Bit'; hashLengthDiv.appendChild(radio16Bit); hashLengthDiv.appendChild(radio16BitLabel); hashLengthDiv.appendChild(document.createElement('br')); var radio8Bit = document.createElement('input'); radio8Bit.id = hashLengthInputId + '-8bit'; radio8Bit.name = hashLengthInputId; radio8Bit.type = 'radio'; radio8Bit.value = 8; var radio8BitLabel = document.createElement('label'); radio8BitLabel.htmlFor = hashLengthInputId + '-8bit'; radio8BitLabel.innerHTML = '8 Bit'; hashLengthDiv.appendChild(radio8Bit); hashLengthDiv.appendChild(radio8BitLabel); advancedOptionsDiv.appendChild(hashLengthDiv); advancedOptionsDiv.appendChild(createSpacer()); advancedOptionsDiv.appendChild(createSpacer()); var hashEncodingDiv = document.createElement('div'); hashEncodingDiv.innerHTML = 'Versium SimpleTag hash encoding:'; hashEncodingDiv.appendChild(document.createElement('br')); var radioDecimal = document.createElement('input'); radioDecimal.checked = true; radioDecimal.id = hashEncodingInputId + '-decimal'; radioDecimal.name = hashEncodingInputId; radioDecimal.type = 'radio'; radioDecimal.value = 0; var radioDecimalLabel = document.createElement('label'); radioDecimalLabel.htmlFor = hashEncodingInputId + '-decimal'; radioDecimalLabel.innerHTML = 'Decimal (default)'; hashEncodingDiv.appendChild(radioDecimal); hashEncodingDiv.appendChild(radioDecimalLabel); hashEncodingDiv.appendChild(document.createElement('br')); var radioHex = document.createElement('input'); radioHex.id = hashEncodingInputId + '-hex'; radioHex.name = hashEncodingInputId; radioHex.type = 'radio'; radioHex.value = 1; var radioHexLabel = document.createElement('label'); radioHexLabel.htmlFor = hashEncodingInputId + '-hex'; radioHexLabel.innerHTML = 'Hex'; hashEncodingDiv.appendChild(radioHex); hashEncodingDiv.appendChild(radioHexLabel); hashEncodingDiv.appendChild(document.createElement('br')); var radioBase64 = document.createElement('input'); radioBase64.id = hashEncodingInputId + '-base64'; radioBase64.name = hashEncodingInputId; radioBase64.type = 'radio'; radioBase64.value = 2; var radioBase64Label = document.createElement('label'); radioBase64Label.htmlFor = hashEncodingInputId + '-base64'; radioBase64Label.innerHTML = 'Base64'; hashEncodingDiv.appendChild(radioBase64); hashEncodingDiv.appendChild(radioBase64Label); advancedOptionsDiv.appendChild(hashEncodingDiv); contentContainer.appendChild(advancedOptionsDiv); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); var nextButton = createNextButton('Finish'); nextButton.onclick = async function() { outputInfo.capitalization = Number(getRadioButtonValue(capitalizationInputId)); outputInfo.trim = Number(getRadioButtonValue(trimInputId)); outputInfo.hashSalt = document.getElementById(hashSaltInputId).value; outputInfo.tagFormat = Number(getRadioButtonValue(tagFormatInputId)); outputInfo.tagLength = Number(getRadioButtonValue(tagLengthInputId)); outputInfo.hashLength = Number(getRadioButtonValue(hashLengthInputId)); outputInfo.hashEncoding = Number(getRadioButtonValue(hashEncodingInputId)); step6(); }; contentContainer.appendChild(nextButton); } async function step6() { await clearContentContainer(); var title = document.createElement('div'); title.className = 'content-container-title'; title.innerHTML = 'Hashing...'; contentContainer.appendChild(title); contentContainer.appendChild(createSpacer()); var content = document.createElement('div'); content.innerHTML += 'We\'re processing your file. It will download as soon as we\'re done with it! Depending on the size of your file and your selected hashing algorithm, this may take several minutes.'; contentContainer.appendChild(content); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); var loadingSpinnerDiv = document.createElement('div'); loadingSpinnerDiv.className = 'spinner'; var emptyDiv = document.createElement('div'); for (var i = 0; i < 4; i++) loadingSpinnerDiv.appendChild(emptyDiv.cloneNode(true)); contentContainer.appendChild(loadingSpinnerDiv); var reader = new FileReader(); reader.fileName = fileInput.files[0].name; reader.onload = async function (progressEvent) { var delimiter = inputInfo.delimiter; var additionalHeaderFields = []; if (inputInfo.address >= 0 && inputInfo.zip >= 0) { additionalHeaderFields = ['VERSIUM STADDR HASHED']; if (inputInfo.last >= 0) { additionalHeaderFields.push('VERSIUM STHHLD HASHED'); if (inputInfo.first >= 0) additionalHeaderFields.push('VERSIUM ST10 HASHED'); } } var outputHeader = header.concat(additionalHeaderFields); output = outputHeader.join(delimiter) + '\n'; var textEncoder = new TextEncoder('utf-8'); var inputLines = this.result.split('\n'); for (var i = 1; i < inputLines.length; i++) { if (inputLines[i].trim() == '') continue; if (outputInfo.capitalization == 1) inputLines[i] = inputLines[i].toLowerCase(); else if (outputInfo.capitalization == 2) inputLines[i] = inputLines[i].toUpperCase(); var parsedLine = parseLine(inputLines[i], delimiter); if (parsedLine.length != header.length) { output += 'Malformatted line\n'; errors++; continue; } var outputLine = parsedLine.slice(); for (var j = 0; j < outputLine.length; j++) { if (outputInfo.trim) outputLine[j] = outputLine[j].trim(); outputLine[j] = await hashingFunctions[hashingAlgorithm](outputInfo.hashSalt + outputLine[j], textEncoder); } var appendedData = await generateHashedSimpleTags(parsedLine[inputInfo.first], parsedLine[inputInfo.last], parsedLine[inputInfo.address], parsedLine[inputInfo.zip], outputInfo.tagFormat, outputInfo.tagLength, outputInfo.hashLength, outputInfo.hashEncoding); outputLine = outputLine.concat(appendedData); output += outputLine.join(delimiter) + '\n'; } download(appendToFilename(this.fileName, '_versium'), output); step7(); }; reader.readAsText(fileInput.files[0]); } async function step7() { await clearContentContainer(); var title = document.createElement('div'); title.className = 'content-container-title'; title.innerHTML = 'All done'; contentContainer.appendChild(title); contentContainer.appendChild(createSpacer()); var content = document.createElement('div'); content.innerHTML += 'Your file has been processed and is downloading now!'; if (errors) { content.appendChild(createSpacer()); content.innerHTML += 'There were ' + errors + ' errors or malformatted lines in your input file. These lines are noted in the output file as "Malformatted line".'; } contentContainer.appendChild(content); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); contentContainer.appendChild(createSpacer()); var nextButton = createNextButton('Start Over'); nextButton.onclick = function() { if (this.classList.contains('disabled')) return; step0(); }; contentContainer.appendChild(nextButton); } function appendToFilename(filename, string){ var dotIndex = filename.lastIndexOf("."); if (dotIndex == -1) return filename + string; else return filename.substring(0, dotIndex) + string + filename.substring(dotIndex); } async function clearContentContainer() { contentContainer.style.opacity = 0; await new Promise(r => setTimeout(r, 500)); contentContainer.innerHTML = ''; contentContainer.style.opacity = 1; } function createNextButton(innerText = 'Next') { var nextButton = document.createElement('div'); nextButton.className = 'content-container-button'; nextButton.innerHTML = innerText; var icon = document.createElement('i'); icon.className = 'icon-right-arrow'; nextButton.appendChild(icon); return nextButton; } function createSpacer() { var spacer = document.createElement('div'); spacer.className = 'spacer'; return spacer; } function download(filename, contents) { var e = document.createElement('a'); e.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(contents)); e.setAttribute('download', filename); e.style.display = 'none'; document.body.appendChild(e); e.click(); document.body.removeChild(e); } function getFileHeader() { var reader = new FileReader(); reader.onload = function (progressEvent) { header = reader.result.split('\n').shift(); } reader.readAsText(fileInput.files[0]); } function getRadioButtonValue(name) { return document.querySelector('input[name="' + name + '"]:checked').value; } function parseLine(line, delimiter = ',') { var insideQuote = false, entries = [], entry = []; line = line.trimEnd(); line.split('').forEach (c => { if (c === '"') { insideQuote = !insideQuote; } else { if (c == delimiter && !insideQuote) { entries.push(entry.join('')); entry = []; } else { entry.push(c); } } }); entries.push(entry.join('')); return entries; } </script> <script> step0(true); </script> </body>