├── Procfile ├── requirements.txt ├── static ├── favicon.ico ├── physics.jpg ├── Q_circuit.png ├── fractal_bg.jpg ├── milky-way.jpg ├── fractal-blue.jpg ├── fractal-flame.jpg ├── galaxy-infinity.jpg ├── css │ └── main.css └── javascript │ └── main.js ├── .vscode └── settings.json ├── LICENSE ├── .gitignore ├── app.py ├── README.md ├── templates ├── index.html └── base.html └── quantum_rng.py /Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn app:app -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | flask==2.0.1 2 | qiskit==0.28.0 3 | gunicorn==20.1.0 -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chasmiccoder/Truly-Random/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /static/physics.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chasmiccoder/Truly-Random/HEAD/static/physics.jpg -------------------------------------------------------------------------------- /static/Q_circuit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chasmiccoder/Truly-Random/HEAD/static/Q_circuit.png -------------------------------------------------------------------------------- /static/fractal_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chasmiccoder/Truly-Random/HEAD/static/fractal_bg.jpg -------------------------------------------------------------------------------- /static/milky-way.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chasmiccoder/Truly-Random/HEAD/static/milky-way.jpg -------------------------------------------------------------------------------- /static/fractal-blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chasmiccoder/Truly-Random/HEAD/static/fractal-blue.jpg -------------------------------------------------------------------------------- /static/fractal-flame.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chasmiccoder/Truly-Random/HEAD/static/fractal-flame.jpg -------------------------------------------------------------------------------- /static/galaxy-infinity.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chasmiccoder/Truly-Random/HEAD/static/galaxy-infinity.jpg -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "system_error": "cpp", 4 | "xlocale": "cpp" 5 | } 6 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Aryaman Kolhe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | import json 3 | import quantum_rng 4 | 5 | numbers = [] 6 | app = Flask(__name__) 7 | 8 | @app.route('/', methods=['GET', 'POST']) 9 | def index(): 10 | return render_template('index.html') 11 | 12 | 13 | # AJAX Requests from main.js 14 | @app.route('/funcInteger', methods=['GET', 'POST']) 15 | def funcInteger(): 16 | dataGet = request.get_json(force=True) 17 | 18 | lowerLimit = dataGet["lowerLimit"] 19 | upperLimit = dataGet["upperLimit"] 20 | howMany = dataGet["howMany"] 21 | numbers = [] 22 | 23 | for _ in range(howMany): 24 | num = quantum_rng.rand_int(lowerLimit, upperLimit) 25 | numbers += [num] 26 | 27 | dataReply = json.dumps( { "numbers": numbers } ) 28 | return dataReply 29 | 30 | 31 | @app.route('/funcFloat', methods=['GET', 'POST']) 32 | def funcFloat(): 33 | 34 | dataGet = request.get_json(force=True) 35 | 36 | lowerLimit = dataGet["lowerLimit"] 37 | upperLimit = dataGet["upperLimit"] 38 | howMany = dataGet["howMany"] 39 | precision = dataGet["precision"] 40 | numbers = [] 41 | 42 | for _ in range(howMany): 43 | num = quantum_rng.rand_float(lowerLimit, upperLimit, precision) 44 | numbers += [num] 45 | 46 | dataReply = json.dumps( { "numbers": numbers } ) 47 | return dataReply 48 | 49 | 50 | @app.route('/funcCoinToss', methods=['GET', 'POST']) 51 | def funcCoinToss(): 52 | 53 | dataGet = request.get_json(force=True) 54 | howMany = dataGet["howMany"] 55 | numbers = [] 56 | 57 | for _ in range(howMany): 58 | num = quantum_rng.random_coin_toss() 59 | numbers += [num] 60 | 61 | dataReply = json.dumps( { "numbers": numbers } ) 62 | return dataReply 63 | 64 | 65 | @app.route('/funcNDigitInt', methods=['GET', 'POST']) 66 | def funcNDigitInt(): 67 | 68 | dataGet = request.get_json(force=True) 69 | nValue = dataGet["nValue"] 70 | howMany = dataGet["howMany"] 71 | numbers = [] 72 | 73 | for _ in range(howMany): 74 | num = quantum_rng.rand_n_digit(nValue) 75 | numbers += [num] 76 | 77 | dataReply = json.dumps( { "numbers": numbers } ) 78 | return dataReply 79 | 80 | 81 | @app.route('/funcFraction', methods=['GET', 'POST']) 82 | def funcFraction(): 83 | 84 | dataGet = request.get_json(force=True) 85 | howMany = dataGet["howMany"] 86 | precision = dataGet["precision"] 87 | 88 | numbers = [] 89 | 90 | for _ in range(howMany): 91 | num = quantum_rng.rand( precision ) 92 | numbers += [num] 93 | 94 | dataReply = json.dumps( { "numbers": numbers } ) 95 | return dataReply 96 | 97 | 98 | @app.route('/funcNDigitBinary', methods=['GET', 'POST']) 99 | def funcNDigitBinary(): 100 | 101 | dataGet = request.get_json(force=True) 102 | nValue = dataGet["nValue"] 103 | howMany = dataGet["howMany"] 104 | numbers = [] 105 | 106 | for _ in range(howMany): 107 | num = quantum_rng.rand_n_digit_binary(nValue) 108 | numbers += [num] 109 | 110 | dataReply = json.dumps( { "numbers": numbers } ) 111 | return dataReply 112 | 113 | 114 | if __name__ == '__main__': 115 | app.run(debug=True) 116 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Truly-Random 2 | 3 | Our world is literally fuelled by random numbers. We use random numbers in Cryptography, Blockchain, Statistics, Gaming, and Gambling. However, classical methods of producing random numbers aren't truly 'random' as such and they rely on ever changing seeds and algorithms that imitate randomness. With the advent of Quantum Computing, all this is going to change, as Quantum Phenomena are fundametally random. In this project we use IBM's qiskit library to simulate a mini Quantum Computer and generate numbers that bring us closer to the dream of generating True Random Numbers! 4 | 5 | ### Deployed on: 6 | 7 | https://trulyrandom.herokuapp.com/ 8 | 9 | ### Installation (from Scratch): 10 | 11 | Install the virtualenv module using pip 12 | 13 | mkdir environments 14 | cd environments 15 | virtualenv myenv 16 | .\myenv\Scripts\activate.bat 17 | pip install -r requirements.txt 18 | 19 | Initialize the project folder as a git repository 20 | 21 | git init 22 | git add . 23 | git commit -m “Project Commit” 24 | 25 | Install the Heroku Toolkit 26 | 27 | heroku login 28 | heroku create 29 | heroku rename trulyrandom 30 | git push heroku master 31 | 32 | For errors, use the logs to debug 33 | 34 | heroku logs --tail 35 | 36 | 37 | ### Theory 38 | 39 | Most random number generators actually generate pseudorandom numbers, which rely on specific classical algorithms. The best alternative is an RNG that depend on atmospheric noise or thermal effects. Cryptography uses Cryptographically secure pseudo RNGs that rely on keys with high entropy. This project demonstrates that we can generate true random numbers by running the python scripts on a fault tolerant Quantum Computer. 40 | We first initialize a quantum register and a classical register, both with a size of 1 bit. Then we load both registers into a single circuit. 41 | 42 | ![Quantum Circuit](./static/Q_circuit.png) 43 | 44 | After that, we pass the quantum register as an argument to the Hadamard Gate. This gate takes a single qubit as its input and returns a number that is either 0 or 1, with equal probability. It does this by creating a superposition, which ultimately collapses to one of the two states. Then we 'measure' the quantity in the quantum register and store that in the classical register. This entire procedure has been described as a 'Coin Toss'. 45 | By repeating this coin toss over and over again, we can generate a string of binary digits, integers, floating point numbers and more! 46 | 47 |
48 | 49 | Original Repo: 50 |
51 | https://github.com/Chasmiccoder/Truly-Random 52 | 53 | ### Resources 54 | 55 | Qiskit Documentation 56 |

57 | 58 | Background Images by
59 | Garik Barseghyan (insspirito) 60 |
61 | Pete Linforth 62 |
63 | Elchinator 64 |
65 | Lumina Obscura 66 |
67 | Deutsch 68 |
69 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block head %} 4 | {% endblock %} 5 | 6 | {% block body %} 7 | 8 |
9 |
10 |
11 | 12 |
13 |
14 |
15 |

Usage

16 | 17 |

18 | First select the type of random number you want to generate.
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
Coin TossSimulates a 'Quantum Coin Toss', and gives either Tails (0) or Heads (1)
IntegerGenerates integers between the specified lower and upper limits
FloatGenerates floating point numbers between the specified lower and upper limits
N Digit Integer Generates integers with N digits
FractionGenerates a float between 0 and 1
N Digit BinarySometimes you just want a binary string of N digits xD
47 | 48 |
49 | 50 | The parameter 'How Many' specifies the number of random numbers you want to produce in a single query.
51 | The parameter 'Precision' specifies the number of digits after the decimal place during generation of floating point numbers.
52 |

53 | 54 |
55 | 56 |

Choose the type of Random Number you want to generate

57 | 58 | 59 |
60 | 61 | 69 | 70 | 71 |
72 | 73 |
74 | 75 |
76 |

77 | 78 |
79 | 80 |
81 | 82 |
83 | 84 |
85 | 86 |
87 | 88 |
89 |
90 |
91 | 92 |
93 |
94 |
95 | 96 | 97 |
98 | 99 |
100 | 101 |
102 |
103 |
104 | 105 |
106 | 107 | {% endblock %} -------------------------------------------------------------------------------- /quantum_rng.py: -------------------------------------------------------------------------------- 1 | from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister, execute, Aer 2 | import math 3 | 4 | 5 | def binary_to_decimal( binary_string ): 6 | """ 7 | Takes a binary number (as a string) and returns its decimal equivalent 8 | """ 9 | 10 | decimal = 0 11 | for i in range( len( binary_string ) ): 12 | decimal += 2**i * int( binary_string[-i-1] ) 13 | 14 | return decimal 15 | 16 | 17 | def print_quantum_circuit(): 18 | """ 19 | Prints the quantum circuit that simulates the coin toss 20 | """ 21 | 22 | q = QuantumRegister(1) 23 | c = ClassicalRegister(1) 24 | 25 | qc = QuantumCircuit(q,c) 26 | 27 | qc.h( q[0] ) 28 | qc.measure( q,c ) 29 | 30 | backend = Aer.get_backend("qasm_simulator") 31 | 32 | job_sim = execute ( qc, backend, shots = 1 ) 33 | 34 | print( qc ) 35 | 36 | 37 | def random_coin_toss(): 38 | """ 39 | This function simulates a perfectly random coin toss (when run on a quantum processor) 40 | Returns either 0 or 1 with exactly 50% probability of either event occuring 41 | """ 42 | 43 | q = QuantumRegister(1) 44 | c = ClassicalRegister(1) 45 | 46 | qc = QuantumCircuit(q,c) 47 | 48 | qc.h( q[0] ) 49 | 50 | qc.measure( q,c ) 51 | 52 | backend = Aer.get_backend("qasm_simulator") 53 | 54 | job_sim = execute ( qc, backend, shots = 1 ) 55 | sim_result = job_sim.result() 56 | 57 | # counts is {'1': 1} or {'0': 1} 58 | counts = sim_result.get_counts( qc ) 59 | 60 | # At this point, we have simulated a perfectly random coin toss 61 | toss_outcome = int( list(counts.keys())[0] ) 62 | 63 | return toss_outcome 64 | 65 | 66 | def rand_n_digit_binary( n ): 67 | """ 68 | Returns a randomly generated n digit binary number 69 | """ 70 | 71 | binary = "" 72 | for i in range( n ): 73 | coin_toss = random_coin_toss() 74 | binary += str( coin_toss ) 75 | 76 | return binary 77 | 78 | 79 | def rand_digit(): 80 | """ 81 | Returns a random digit from [0,9] 82 | """ 83 | 84 | # Obtain a random digit from 0 to 15 (1111 is 15 in binary) 85 | binary = rand_n_digit_binary( 4 ) 86 | 87 | # loop until we obtain a random number that is lesser than 10 88 | while ( binary_to_decimal(binary) >= 10 ): 89 | binary = rand_n_digit_binary( 4 ) 90 | 91 | # Now all that is left is an integer from [0,9] 92 | return binary_to_decimal( binary ) 93 | 94 | 95 | def rand( precision = 5 ): 96 | """ 97 | Returns a random float value between 0 and 1 98 | precision = number of digits after the decimal point 99 | 100 | There is a chance that it might produce a fraction with lesser than the specified 101 | digits becuase the trailing digits could also be 0 (and thus ignored in future processing by the programming language) 102 | """ 103 | 104 | random_float = "" 105 | 106 | for i in range( precision ): 107 | random_float += str( rand_digit() ) 108 | 109 | return float( "0." + random_float ) 110 | 111 | 112 | def rand_n_digit( n ): 113 | """ 114 | Takes an integer n and returns an n digit, randomly generated number in base 10 (decimal) 115 | """ 116 | 117 | random_number = "" 118 | for i in range( n ): 119 | randomDigit = rand_digit() 120 | 121 | if i == 0: 122 | while randomDigit == 0: 123 | randomDigit = rand_digit() 124 | 125 | random_number += str( randomDigit ) 126 | 127 | return random_number 128 | 129 | 130 | def rand_int( a,b, precision = 20 ): 131 | """ 132 | Returns a random integer value in the range of [a,b] 133 | precision = number of digits to be passed in rand() 134 | As the difference between a and b increases, precision must also increase (automate this later) 135 | """ 136 | 137 | # Make sure that both ranges are integers 138 | a = int(a) 139 | b = int(b) 140 | 141 | num = int( rand( precision ) * ( b - a ) ) + a 142 | return num 143 | 144 | 145 | def rand_float( a,b, precision = 5 ): 146 | """ 147 | Returns a random float value in the range of [a,b] 148 | """ 149 | 150 | # Make sure that both ranges are integers 151 | a = int(a) 152 | b = int(b) 153 | 154 | num = rand_int( a,b, precision ) + rand( precision ) 155 | # There is a chance that rand_int can return b. This condition retains the original range 156 | if ( num > b ): 157 | num -= 1 158 | 159 | return num -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | Truly Random - A Quantum Project 27 | 28 | {% block head %}{% endblock %} 29 | 30 | 31 | 32 | 33 | 34 | 35 | 53 | 54 |

55 | 56 |
57 |
58 |



59 | 60 |

Truly Random

61 |
62 |

Generate true random numbers using Quantum Phenomena

63 | 64 |
65 |
66 | 67 |
68 | 69 |
70 |
71 | 72 | 73 |
74 |
75 |

About

76 |

77 | Our world is literally fuelled by random numbers. We use random numbers in Cryptography, 78 | Blockchain, Statistics, Gaming, and Gambling. However, classical methods of producing random numbers aren't truly 'random' as such and they rely on ever changing seeds and algorithms that imitate randomness. With the advent of Quantum Computing, all this is going to change, as Quantum Phenomena are fundametally random. In this project we use IBM's qiskit library to simulate a mini Quantum Computer and generate numbers that bring us closer to the dream of generating True Random Numbers! 79 |

80 | 81 |
82 | 83 |
84 | 85 |
86 |
87 |
88 | 89 | {% block body %}{% endblock %} 90 | 91 |
92 |
93 |
94 | 95 |
96 | 97 |
98 |
99 | 100 |
101 |
102 | 103 |

Application

104 | 105 |

106 | Authentication 107 |
108 | Encryption 109 |
110 | Game Development 111 |
112 | Simulation 113 |
114 | Statistics 115 |
116 | Blockchain 117 |
118 | 119 |

120 | 121 |
122 |
123 | 124 |
125 |
126 | 127 |
128 |
129 |
130 | 131 |
132 |
133 | 134 |

Theory

135 | 136 |

137 | Most random number generators actually generate pseudorandom numbers, which rely on specific classical algorithms. The best alternative is an RNG that depend on atmospheric noise or thermal effects. Cryptography uses Cryptographically secure pseudo RNGs that rely on keys with high entropy. 138 | This project demonstrates that we can generate true random numbers by running the python scripts on a fault tolerant Quantum Computer. 139 |
140 | 141 | We first initialize a quantum register and a classical register, both with a size of 1 bit. Then we load both registers into a single circuit. 142 |

143 | Quantum Circuit 144 |

145 | 146 | After that, we pass the quantum register as an argument to the Hadamard Gate. This gate takes a single qubit as its input and returns a number that is either 0 or 1, with equal probability. It does this by creating a superposition, which ultimately collapses to one of the two states. 147 | Then we 'measure' the quantity in the quantum register and store that in the classical register. This entire procedure has been described as a 'Coin Toss'. 148 | 149 |
150 | By repeating this coin toss over and over again, we can generate a string of binary digits, integers, floating point numbers and more! 151 | 152 |

153 | 154 |
155 |
156 | 157 | 159 | 160 |
161 |
162 | 163 |
164 |
165 |

Cheers!

166 | 167 |

168 | Thanks for going through my project. I greatly appreciate it!
169 | Link to Source Code 170 |

171 | 172 |
173 | 174 |

175 |

Conclusion

176 | Quantum Computing itself is in its early stages, and this project fairly naive in its implementation. However, I learned a lot during the process including some of the basics of quantum circuits, web development, python backend integration (with Flask), and how JS can communicate with the python backend via ajax calls. 177 |

178 | 179 |
180 |
181 | 182 |
183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /static/css/main.css: -------------------------------------------------------------------------------- 1 | html,body { 2 | height:100%; 3 | margin:0; 4 | line-height: 180%; 5 | color: beige; 6 | background-color: #1f1d1d; 7 | width: auto; 8 | } 9 | 10 | #home_icon { 11 | display: flex; 12 | } 13 | 14 | ion-icon { 15 | color: beige; 16 | font-size: 32px; 17 | position: relative; 18 | left: 1rem; 19 | top: 1rem; 20 | } 21 | 22 | .img1 { 23 | background: url( ../fractal_bg.jpg); 24 | background-position: -1rem -8rem; 25 | min-height: 100%; 26 | } 27 | 28 | #navbar { 29 | padding: 0; 30 | margin: 0; 31 | text-decoration: none; 32 | list-style: none; 33 | box-sizing: border-box; 34 | font-family: montserrat; 35 | overflow: hidden; 36 | position: fixed; 37 | top:0; 38 | z-index: 1; 39 | border-bottom: 1px solid beige; 40 | background: url(../fractal-flame.jpg); 41 | background-position: 0rem 20rem; 42 | height: 80px; 43 | width: 100%; 44 | } 45 | 46 | .portfolio_link { 47 | font-size: 1.2rem; 48 | line-height: 60px; 49 | font-weight: bold; 50 | float: left; 51 | padding-left: 1rem; 52 | padding-right: 1rem; 53 | margin:0.7rem; 54 | border:1px invisible; 55 | border-radius:3px; 56 | color: beige; 57 | text-shadow: 2px 1px black; 58 | } 59 | 60 | 61 | .portfolio_link:hover{ 62 | transition: 0.5s; 63 | text-shadow: 0px 0px; 64 | background: lightcyan; 65 | color: black; 66 | } 67 | 68 | #nav_ul { 69 | float: right; 70 | } 71 | 72 | #nav_ul li { 73 | display: inline-block; 74 | line-height: 55px; 75 | margin: 0; 76 | } 77 | 78 | #nav_ul li a { 79 | color: beige; 80 | font-size: 17px; 81 | padding: 7px 13px; 82 | border-radius: 3px; 83 | text-decoration: none; 84 | } 85 | 86 | #nav_ul a:hover{ 87 | background: lightcyan; 88 | color: black; 89 | transition: 0.2s; 90 | } 91 | 92 | #checkbtn { 93 | font-size: 30px; 94 | color: beige; 95 | float: right; 96 | margin-right: 2rem; 97 | margin-top:0.8rem; 98 | cursor: pointer; 99 | display: none; 100 | } 101 | 102 | 103 | #check { 104 | display: none; 105 | } 106 | 107 | #heading { 108 | display: flex; 109 | justify-content: center; 110 | align-items: center; 111 | flex-direction: column; 112 | 113 | background-size: 56%; 114 | background-repeat: no-repeat; 115 | background-position: 16.5rem 8rem; 116 | text-shadow: 3px 3px #000000; 117 | 118 | padding: 4rem; 119 | padding-top: 0; 120 | padding-bottom: 0; 121 | } 122 | 123 | #main_heading { 124 | color:beige; 125 | font-family: 'Dancing Script', cursive; 126 | font-size: 4.5em; 127 | margin-bottom: 0; 128 | } 129 | 130 | #sub_heading { 131 | color: beige; 132 | font-style: italic; 133 | font-size: 3rem; 134 | font-family: 'Tangerine', cursive; 135 | } 136 | 137 | .img2 { 138 | background: url( ../fractal-flame.jpg); 139 | min-height: 50%; 140 | background-position: center; 141 | background-size: cover; 142 | } 143 | 144 | .content { 145 | margin-left: 2rem; 146 | margin-right: 2rem; 147 | text-align: center; 148 | margin-bottom: 3rem; 149 | font-family: 'Quicksand', sans-serif; 150 | font-size:1.3rem; 151 | } 152 | 153 | .content_heading { 154 | font-family: 'Tangerine', cursive; 155 | font-size: 4rem; 156 | } 157 | 158 | #chooseOperationButton { 159 | background-color: #4CAF50; 160 | border: none; 161 | color: white; 162 | text-align: center; 163 | text-decoration: none; 164 | display: inline-block; 165 | border-radius: 20px; 166 | } 167 | 168 | #operation_select { 169 | background-color:cadetblue; 170 | border: none; 171 | color: white; 172 | height: 1.5rem; 173 | width: 10rem; 174 | text-align: center; 175 | text-decoration: none; 176 | display: inline-block; 177 | font-size: 15px; 178 | border-radius: 5px; 179 | } 180 | 181 | #clipboardCopy { 182 | background-color: #4CAF50; 183 | border: none; 184 | color: white; 185 | text-align: center; 186 | text-decoration: none; 187 | display: inline-block; 188 | border-radius: 20px; 189 | width: 5rem; 190 | } 191 | 192 | .img3 { 193 | background: url( ../fractal-blue.jpg); 194 | background-position: center; 195 | min-height: 50%; 196 | } 197 | 198 | .img6 { 199 | background: url( ../galaxy-infinity.jpg); 200 | background-position: center; 201 | min-height: 50%; 202 | 203 | } 204 | 205 | .img5 { 206 | background: url( ../milky-way.jpg); 207 | background-position: center bottom; 208 | min-height: 50%; 209 | } 210 | 211 | .img4 { 212 | background: url( ../physics.jpg); 213 | background-position: center center; 214 | min-height: 50%; 215 | } 216 | 217 | #function_selection { 218 | position: relative; 219 | display: inline-block; 220 | margin-left: 5rem; 221 | color: beige; 222 | } 223 | 224 | .dropdown { 225 | background-color: #04AA6D; 226 | color: white; 227 | padding: 16px; 228 | font-size: 16px; 229 | border: none; 230 | } 231 | 232 | #function_selection:hover .dropdown-content { 233 | display: block; 234 | } 235 | 236 | #function_selection:hover .dropdown { 237 | background-color: #3e8e41; 238 | } 239 | 240 | body::-webkit-scrollbar { 241 | width: 12px; /* width of the entire scrollbar */ 242 | } 243 | 244 | body::-webkit-scrollbar-track { 245 | background: #343434; /* color of the tracking area */ 246 | } 247 | 248 | body::-webkit-scrollbar-thumb { 249 | background-color: #343434; /* color of the scroll thumb */ 250 | border-radius: 20px; /* roundness of the scroll thumb */ 251 | border: 1px solid snow; /* creates padding around scroll thumb */ 252 | } 253 | 254 | table, th, td { 255 | border: 1px solid #616060; 256 | border-collapse: collapse; 257 | margin-left: auto; 258 | margin-right: auto; 259 | padding: 1rem; 260 | text-align: left; 261 | font-size: 1rem; 262 | } 263 | 264 | #usage_output { 265 | background-color: #28282B; 266 | height: 150px; 267 | display: flex; 268 | flex-direction: column; 269 | margin-left: 2rem; 270 | margin-right: 2rem; 271 | 272 | overflow-y: scroll; 273 | 274 | font-weight: bold; 275 | 276 | border: 2px solid pink; 277 | border-radius: 20px; 278 | border-style: inset; 279 | } 280 | 281 | .img1, .img2, .img3, .img4, .img5, .img6 { 282 | position: relative; 283 | background-attachment: fixed; 284 | background-repeat: no-repeat; 285 | } 286 | 287 | form { 288 | border-top:1px dotted #D9D9D9; 289 | } 290 | 291 | button { 292 | width:246px; 293 | height:40px; 294 | color:#4C4C4C; 295 | margin-bottom:20px; 296 | margin-left:20px 297 | } 298 | 299 | input { 300 | width:280px; 301 | height:40px; 302 | padding:5px; 303 | margin:20px 0 10px; 304 | border-radius:5px; 305 | border:4px solid #acbfa5 306 | } 307 | 308 | input[type = submit] { 309 | width:100px; 310 | background-color:#4C4C4C; 311 | border-radius:5px; 312 | border:2px solid #616060; 313 | color: beige; 314 | } 315 | 316 | .selectOperation { 317 | margin-left: auto; 318 | margin-right: auto; 319 | } 320 | 321 | .formWrapper{ 322 | border:1px solid #D0D0D0; 323 | } 324 | 325 | .formWrapper form { 326 | width:auto; 327 | } 328 | 329 | .formWrapper input { 330 | width: auto; 331 | 332 | } 333 | 334 | #enter-values-tag { 335 | font-size: large; 336 | } 337 | 338 | #thanks a { 339 | color: beige; 340 | } 341 | #thanks a:hover{ 342 | transition: 0.5s; 343 | background: lightcyan; 344 | color: black; 345 | } 346 | 347 | 348 | 349 | /* Responsive */ 350 | /* If screen width is smaller, but not small enough for dropdown */ 351 | @media ( max-width: 952px ) { 352 | label#check { 353 | font-size: 30px; 354 | padding-left: 50px; 355 | } 356 | 357 | #nav_ul li a { 358 | font-size: 16px; 359 | } 360 | } 361 | 362 | @media ( max-width: 858px ) { 363 | .content { 364 | font-size: 2rem; 365 | } 366 | 367 | #checkbtn { 368 | display: block; 369 | } 370 | 371 | #nav_ul { 372 | position: fixed; 373 | height: 18rem; 374 | background: #2c3e50; 375 | border: 1px solid beige; 376 | padding-left: 0rem; 377 | 378 | top: 60px; 379 | left: -115%; 380 | text-align: center; 381 | 382 | transition: all 0.5s; 383 | 384 | } 385 | 386 | #nav_ul li { 387 | display: block; 388 | margin: 20px 0; 389 | line-height: 30px; 390 | } 391 | 392 | #nav_ul li a { 393 | font-size: 20px; 394 | } 395 | 396 | #nav_ul a:hover { 397 | background: none; 398 | color: #0082e6; 399 | } 400 | 401 | #check:checked ~ ul { 402 | left: 0; 403 | } 404 | 405 | .img1 { 406 | background: url( ../fractal_bg.jpg); 407 | min-height: 100%; 408 | background-position: -45rem; 409 | } 410 | } -------------------------------------------------------------------------------- /static/javascript/main.js: -------------------------------------------------------------------------------- 1 | // Global iterator i that helps keep track of the id's of elements 2 | var i = 0; 3 | function increment() { 4 | i += 1; 5 | } 6 | 7 | // Keeps track of the previous operation performed 8 | // (in order to clear the input field elements when needed, and to prevent additional fields from being created) 9 | var previous = ""; 10 | 11 | // Keeps track of the numbers generated 12 | var numbers = []; 13 | var numberOfNumbersGenerated = 0; 14 | 15 | // Forms that get displayed when the respective operation is chosen 16 | const formInteger = document.getElementById("formInteger"); 17 | formInteger.onsubmit = generateInt; 18 | 19 | const formFloat = document.getElementById("formFloat"); 20 | formFloat.onsubmit = generateFloat; 21 | 22 | const formCoinToss = document.getElementById("formCoinToss"); 23 | formCoinToss.onsubmit = generateCoinToss; 24 | 25 | const formNDigitInt = document.getElementById("formNDigitInt"); 26 | formNDigitInt.onsubmit = generateNDigitInt; 27 | 28 | const formFraction = document.getElementById("formFraction"); 29 | formFraction.onsubmit = generateFraction; 30 | 31 | const formNDigitBinary = document.getElementById("formNDigitBinary"); 32 | formNDigitBinary.onsubmit = generateNDigitBinary; 33 | 34 | 35 | function getOperation() { 36 | /* 37 | Activates when the user chooses the operation and initiates the generation of the parameter form 38 | */ 39 | 40 | var currentOp = document.getElementById("operation_select").value; 41 | 42 | if ( previous != currentOp ) { 43 | document.getElementById("enter-values-tag").innerHTML = "Enter Values!"; 44 | 45 | if ( previous == "integer" ) { 46 | var parent = document.getElementById("formInteger"); 47 | parent.removeChild( document.getElementById("parameterSpan") ); 48 | } 49 | 50 | if ( previous == "float" ) { 51 | var parent = document.getElementById("formFloat"); 52 | parent.removeChild( document.getElementById("parameterSpan") ); 53 | } 54 | 55 | if ( previous == "coin_toss" ) { 56 | var parent = document.getElementById("formCoinToss"); 57 | parent.removeChild( document.getElementById("parameterSpan") ); 58 | } 59 | 60 | if ( previous == "n_digit_int" ) { 61 | var parent = document.getElementById("formNDigitInt"); 62 | parent.removeChild( document.getElementById("parameterSpan") ); 63 | } 64 | 65 | if ( previous == "fraction" ) { 66 | var parent = document.getElementById("formFraction"); 67 | parent.removeChild( document.getElementById("parameterSpan") ); 68 | } 69 | 70 | if ( previous == "n_digit_binary" ) { 71 | var parent = document.getElementById("formNDigitBinary"); 72 | parent.removeChild( document.getElementById("parameterSpan") ); 73 | } 74 | 75 | generateParameterForm(currentOp); 76 | previous = currentOp; 77 | } 78 | } 79 | 80 | 81 | function generateParameterForm(operation) { 82 | /* 83 | Generates the parameter form for each type of operation 84 | For integer generation, it generates 3 fields: 85 | lower limit, upper limit and the number of numbers to be generated 86 | For float generation it generates the same integer fields along with a precision field 87 | 88 | For Coin Toss, it generates 1 field for the number of coin tosses 89 | 90 | For Fraction, it generates 2 fields for the number of numbers to generate, and the precision 91 | (number of digits after decimal) 92 | 93 | For n digit int and binary, it generates 2 fields for: n, number of numbers 94 | */ 95 | 96 | if ( operation == "integer" || operation == "float" ) { 97 | 98 | // First we need to get the lower and upper bounds 99 | var r = document.createElement('span'); 100 | var lower_limit = document.createElement('INPUT'); 101 | var upper_limit = document.createElement('INPUT'); 102 | 103 | // How many random nums to create within the range 104 | var how_many = document.createElement('INPUT'); 105 | 106 | var submit = document.createElement("INPUT"); 107 | submit.setAttribute("type", "submit"); 108 | 109 | 110 | increment(); 111 | 112 | lower_limit.setAttribute("type", "number"); 113 | lower_limit.setAttribute("placeholder", "Lower Limit"); 114 | lower_limit.setAttribute("name", "textelement_" + i); 115 | lower_limit.setAttribute("id", "lowerLimitField"); 116 | 117 | increment(); 118 | 119 | upper_limit.setAttribute("type", "number"); 120 | upper_limit.setAttribute("placeholder", "Upper Limit"); 121 | upper_limit.setAttribute("name", "textelement_" + i); 122 | upper_limit.setAttribute("id", "upperLimitField"); 123 | 124 | increment(); 125 | 126 | how_many.setAttribute("type", "number"); 127 | how_many.setAttribute("placeholder", "How Many"); 128 | how_many.setAttribute("name", "textelement_" + i); 129 | how_many.setAttribute("id", "howMany"); 130 | 131 | submit.style.setProperty("margin", "10px"); 132 | lower_limit.style.setProperty("margin", "10px"); 133 | upper_limit.style.setProperty("margin", "10px"); 134 | how_many.style.setProperty("margin", "10px"); 135 | 136 | r.appendChild(lower_limit); 137 | r.appendChild(upper_limit); 138 | r.appendChild(how_many); 139 | 140 | // Collect number of decimals for floats 141 | if ( operation == "float" ) { 142 | var precision = document.createElement('INPUT'); 143 | 144 | increment(); 145 | 146 | precision.setAttribute("type", "number"); 147 | precision.setAttribute("placeholder", "Precision"); 148 | precision.setAttribute("name", "textelement_" + i); 149 | precision.setAttribute("id", "precisionField"); 150 | 151 | precision.style.setProperty("margin", "10px"); 152 | 153 | r.appendChild(precision); 154 | } 155 | 156 | r.appendChild(submit); 157 | r.setAttribute("id", "parameterSpan"); 158 | 159 | if ( operation == "integer" ) { 160 | document.getElementById("formInteger").appendChild(r); 161 | } 162 | else { 163 | document.getElementById("formFloat").appendChild(r); 164 | } 165 | } 166 | 167 | else if ( operation == "coin_toss" || operation == "fraction" ) { 168 | var r = document.createElement('span'); 169 | var how_many = document.createElement('INPUT'); // how many 170 | var submit = document.createElement("INPUT"); 171 | submit.setAttribute("type", "submit"); 172 | 173 | increment(); 174 | 175 | how_many.setAttribute("type", "number"); 176 | how_many.setAttribute("placeholder", "How Many"); // Lower limit 177 | how_many.setAttribute("name", "textelement_" + i); 178 | how_many.setAttribute("id", "howMany"); 179 | 180 | increment(); 181 | 182 | submit.style.setProperty("margin", "10px"); 183 | how_many.style.setProperty("margin", "10px"); 184 | 185 | r.appendChild(how_many); 186 | 187 | // Collect number of decimals for floats 188 | if ( operation == "fraction" ) { 189 | var precision = document.createElement('INPUT'); 190 | 191 | increment(); 192 | 193 | precision.setAttribute("type", "number"); 194 | precision.setAttribute("placeholder", "Precision"); 195 | precision.setAttribute("name", "textelement_" + i); 196 | precision.setAttribute("id", "precisionField"); 197 | precision.style.setProperty("margin", "10px"); 198 | 199 | r.appendChild(precision); 200 | } 201 | 202 | r.appendChild(submit); 203 | r.setAttribute("id", "parameterSpan"); 204 | 205 | if ( operation == "coin_toss" ) { 206 | document.getElementById("formCoinToss").appendChild(r); 207 | } 208 | else { 209 | document.getElementById("formFraction").appendChild(r); 210 | } 211 | } 212 | 213 | else if ( operation == "n_digit_int" || operation == "n_digit_binary" ) { 214 | 215 | // First we need to get the lower and upper bounds 216 | var r = document.createElement('span'); 217 | var n_value = document.createElement('INPUT'); // length of integer / binary 218 | var how_many = document.createElement('INPUT'); // How many random ints to create within the range 219 | 220 | var submit = document.createElement("INPUT"); 221 | submit.setAttribute("type", "submit"); 222 | 223 | increment(); 224 | 225 | n_value.setAttribute("type", "number"); 226 | n_value.setAttribute("placeholder", "N"); // N number of digits 227 | n_value.setAttribute("name", "textelement_" + i); 228 | n_value.setAttribute("id", "nValue"); 229 | 230 | increment(); 231 | 232 | how_many.setAttribute("type", "number"); 233 | how_many.setAttribute("placeholder", "How Many"); // Lower limit 234 | how_many.setAttribute("name", "textelement_" + i); 235 | how_many.setAttribute("id", "howMany"); 236 | 237 | increment(); 238 | 239 | submit.style.setProperty("margin", "10px"); 240 | n_value.style.setProperty("margin", "10px"); 241 | how_many.style.setProperty("margin", "10px"); 242 | 243 | r.appendChild(n_value); 244 | r.appendChild(how_many); 245 | r.appendChild(submit); 246 | r.setAttribute("id", "parameterSpan"); 247 | 248 | if ( operation == "n_digit_int" ) { 249 | document.getElementById("formNDigitInt").appendChild(r); 250 | } 251 | else { 252 | document.getElementById("formNDigitBinary").appendChild(r); 253 | } 254 | } 255 | else { 256 | alert("Invalid Operation!"); 257 | } 258 | } 259 | 260 | 261 | function generateInt(event) { 262 | /* 263 | Sends a POST request (via an AJAX call) to the python backend and fetches a random integer between 264 | the upper and lower limits 265 | */ 266 | 267 | event.preventDefault(); // won't update the url, or go to a new page on submit 268 | 269 | var ll = document.getElementById('lowerLimitField').value; 270 | var ul = document.getElementById('upperLimitField').value; 271 | var how_many = document.getElementById('howMany').value; 272 | 273 | ll = parseInt(ll); 274 | ul = parseInt(ul); 275 | how_many = parseInt(how_many); 276 | 277 | var xml = new XMLHttpRequest(); 278 | 279 | xml.open("POST", "/funcInteger", true); 280 | // passing true to make the process asynchronous 281 | 282 | xml.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 283 | 284 | xml.onload = function() { 285 | // Gets executed once python sends a response (aka the numbers) 286 | var dataReply = JSON.parse(this.responseText); 287 | generatedNums = dataReply["numbers"]; 288 | updateOutput(generatedNums); 289 | }; 290 | 291 | dataSend = { 292 | "lowerLimit" : ll, 293 | "upperLimit" : ul, 294 | "howMany" : how_many 295 | }; 296 | 297 | xml.send(JSON.stringify(dataSend)); // sends the JSON file as 1 single string 298 | } 299 | 300 | 301 | function generateFloat(event) { 302 | event.preventDefault(); 303 | 304 | var ll = document.getElementById('lowerLimitField').value; 305 | var ul = document.getElementById('upperLimitField').value; 306 | var how_many = document.getElementById('howMany').value; 307 | var precision = document.getElementById('precisionField').value; 308 | 309 | ll = parseInt(ll); 310 | ul = parseInt(ul); 311 | how_many = parseInt(how_many); 312 | precision = parseInt(precision); 313 | 314 | var xml = new XMLHttpRequest(); 315 | xml.open("POST", "/funcFloat", true); 316 | xml.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 317 | 318 | xml.onload = function() { 319 | var dataReply = JSON.parse(this.responseText); 320 | generatedNums = dataReply["numbers"]; 321 | updateOutput(generatedNums); 322 | }; 323 | 324 | dataSend = { 325 | "lowerLimit" : ll, 326 | "upperLimit" : ul, 327 | "howMany" : how_many, 328 | "precision" : precision 329 | }; 330 | 331 | xml.send(JSON.stringify(dataSend)); 332 | } 333 | 334 | 335 | function generateCoinToss(event) { 336 | event.preventDefault(); 337 | 338 | var how_many = document.getElementById('howMany').value; 339 | how_many = parseInt(how_many); 340 | 341 | var xml = new XMLHttpRequest(); 342 | xml.open("POST", "/funcCoinToss", true); 343 | xml.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 344 | 345 | xml.onload = function() { 346 | var dataReply = JSON.parse(this.responseText); 347 | generatedNums = dataReply["numbers"]; 348 | updateOutput(generatedNums); 349 | }; 350 | 351 | dataSend = { 352 | "howMany" : how_many 353 | }; 354 | 355 | xml.send(JSON.stringify(dataSend)); 356 | } 357 | 358 | 359 | function generateNDigitInt(event) { 360 | event.preventDefault(); 361 | 362 | var n_value = document.getElementById('nValue').value; 363 | var how_many = document.getElementById('howMany').value; 364 | 365 | n_value = parseInt(n_value); 366 | how_many = parseInt(how_many); 367 | 368 | var xml = new XMLHttpRequest(); 369 | xml.open("POST", "/funcNDigitInt", true); 370 | xml.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 371 | 372 | xml.onload = function() { 373 | var dataReply = JSON.parse(this.responseText); 374 | generatedNums = dataReply["numbers"]; 375 | updateOutput(generatedNums); 376 | }; 377 | 378 | dataSend = { 379 | "nValue" : n_value, 380 | "howMany" : how_many 381 | }; 382 | 383 | xml.send(JSON.stringify(dataSend)); 384 | } 385 | 386 | 387 | function generateFraction(event) { 388 | event.preventDefault(); 389 | 390 | var how_many = document.getElementById('howMany').value; 391 | var precision = document.getElementById('precisionField').value; 392 | 393 | how_many = parseInt(how_many); 394 | precision = parseInt(precision); 395 | 396 | var xml = new XMLHttpRequest(); 397 | xml.open("POST", "/funcFraction", true); 398 | xml.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 399 | 400 | xml.onload = function() { 401 | var dataReply = JSON.parse(this.responseText); 402 | generatedNums = dataReply["numbers"]; 403 | updateOutput(generatedNums); 404 | }; 405 | 406 | dataSend = { 407 | "howMany" : how_many, 408 | "precision" : precision 409 | }; 410 | 411 | xml.send(JSON.stringify(dataSend)); 412 | } 413 | 414 | function generateNDigitBinary(event) { 415 | event.preventDefault(); 416 | 417 | var n_value = document.getElementById('nValue').value; 418 | var how_many = document.getElementById('howMany').value; 419 | 420 | n_value = parseInt(n_value); 421 | how_many = parseInt(how_many); 422 | 423 | var xml = new XMLHttpRequest(); 424 | xml.open("POST", "/funcNDigitBinary", true); 425 | xml.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 426 | 427 | xml.onload = function() { 428 | var dataReply = JSON.parse(this.responseText); 429 | generatedNums = dataReply["numbers"]; 430 | updateOutput(generatedNums); 431 | }; 432 | 433 | dataSend = { 434 | "nValue" : n_value, 435 | "howMany" : how_many 436 | }; 437 | 438 | xml.send(JSON.stringify(dataSend)); // sends the JSON file as 1 single string 439 | } 440 | 441 | 442 | function updateOutput(generatedNums) { 443 | /* 444 | Takes an array of integers and adds them to the output field 445 | */ 446 | 447 | // Everytime the output gets updated, we need to refresh the text in the copy button 448 | document.getElementById('clipboardCopy').innerHTML = "Copy"; 449 | 450 | howMany = generatedNums.length; 451 | for ( var i = 0; i < howMany; i++ ) { 452 | numberOfNumbersGenerated += 1; 453 | numbers.push(generatedNums[i]); 454 | } 455 | 456 | var r = document.createElement('span'); 457 | 458 | for ( var i = 0; i < numberOfNumbersGenerated; i++ ) { 459 | var oneNumber = document.createElement('p'); 460 | oneNumber.setAttribute("id", "outputPTag" + i ); 461 | r.appendChild(oneNumber); 462 | } 463 | 464 | document.getElementById("usage_output").appendChild(r); 465 | 466 | for ( var i = 0; i < numberOfNumbersGenerated; i++ ) { 467 | document.getElementById("outputPTag" + i).innerHTML = numbers[i]; 468 | } 469 | } 470 | 471 | 472 | document.getElementById('clipboardCopy').addEventListener('click', clipboardCopy); 473 | async function clipboardCopy() { 474 | var text = ""; 475 | 476 | for ( var i = 0; i < numberOfNumbersGenerated; i++ ) { 477 | text += numbers[i]; 478 | if ( i != numberOfNumbersGenerated - 1 ) { 479 | text += " "; 480 | } 481 | } 482 | 483 | console.log(text); 484 | await navigator.clipboard.writeText(text); 485 | document.getElementById('clipboardCopy').innerHTML = "Copied!"; 486 | } --------------------------------------------------------------------------------