├── 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 | 
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 | Coin Toss
23 | Simulates a 'Quantum Coin Toss', and gives either Tails (0) or Heads (1)
24 |
25 |
26 | Integer
27 | Generates integers between the specified lower and upper limits
28 |
29 |
30 | Float
31 | Generates floating point numbers between the specified lower and upper limits
32 |
33 |
34 | N Digit Integer
35 | Generates integers with N digits
36 |
37 |
38 | Fraction
39 | Generates a float between 0 and 1
40 |
41 |
42 | N Digit Binary
43 | Sometimes you just want a binary string of N digits xD
44 |
45 |
46 |
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 |
62 | Coin Toss
63 | Integer
64 | Float
65 | N Digit Integer
66 | Fraction
67 | N Digit Binary
68 |
69 | Choose
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 | Copy
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 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | The Kolhe Project
45 |
52 |
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 |
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 | }
--------------------------------------------------------------------------------