├── .gitignore
├── README.md
├── draw
├── __init__.py
├── test.py
└── DrawBot.py
├── photo
├── __init__.py
├── test.py
└── PhotoConverter.py
├── cup.png
├── out.jpg
├── banana.jpg
├── dogman.jpg
├── js
├── webcam.swf
└── webcam.js
├── outputface_0001.gcode
├── tsquare.jpeg
├── brown-logo1.png
├── templates
├── hello.html
├── static
│ ├── contour.jpg
│ ├── frame.jpg
│ ├── placeholder.png
│ ├── index.html
│ ├── normalize.css
│ └── skeleton.css
├── test.html
├── gcode.html
├── camera.html
├── index.html
├── admin.html
└── css
│ ├── normalize.css
│ └── skeleton.css
├── Village_Square.gif
├── static
├── contour.jpg
├── frame.jpg
├── placeholder.png
├── index.html
├── normalize.css
└── skeleton.css
├── outputface_0005.gcode
├── output_0001.gcode
├── outputface_0003.gcode
├── outputface_0004.gcode
├── test_server.py
├── flasktest.py
├── draw_module_test.py
├── googletest.py
├── banana.html
├── gcode.py
├── outputface_0006.gcode
├── outputface_0007.gcode
├── outputface_0008.gcode
├── outputface_0009.gcode
├── outputface_0002.gcode
├── server.csr
├── server.key.org
├── randon_walk.py
├── edge_filter.py
├── spiral.py
├── server.crt
├── photo_server.py
├── contour.py
├── hatch_test.py
├── hatch.py
├── webspeech
└── index.html
├── control.py
├── gcode2.py
├── Core_XY_control2
└── Core_XY_control2.ino
├── server.key
├── Core_XY_control3
└── Core_XY_control3.ino
├── Core_XY_control
└── Core_XY_control.ino
├── gcode3.py
├── drawing.eps
├── speech.py
├── Core_XY_control4
└── Core_XY_control4.ino
├── draw_server.py
├── Core_XY_control5
└── Core_XY_control5.ino
├── Core_XY_control6
└── Core_XY_control6.ino
└── gnu_0001.gcode
/.gitignore:
--------------------------------------------------------------------------------
1 | images
2 | *.pyc
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FartMachine10
2 |
--------------------------------------------------------------------------------
/draw/__init__.py:
--------------------------------------------------------------------------------
1 | from DrawBot import DrawBot
2 |
--------------------------------------------------------------------------------
/photo/__init__.py:
--------------------------------------------------------------------------------
1 | from PhotoConverter import PhotoConverter
2 |
3 |
--------------------------------------------------------------------------------
/cup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/cup.png
--------------------------------------------------------------------------------
/out.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/out.jpg
--------------------------------------------------------------------------------
/banana.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/banana.jpg
--------------------------------------------------------------------------------
/dogman.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/dogman.jpg
--------------------------------------------------------------------------------
/js/webcam.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/js/webcam.swf
--------------------------------------------------------------------------------
/outputface_0001.gcode:
--------------------------------------------------------------------------------
1 | M05 S0
2 |
3 | G90
4 | G21
5 | G1 F3000
6 | G1 X0 Y0
7 | M18
8 |
--------------------------------------------------------------------------------
/tsquare.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/tsquare.jpeg
--------------------------------------------------------------------------------
/brown-logo1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/brown-logo1.png
--------------------------------------------------------------------------------
/templates/hello.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Coooooool
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Village_Square.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/Village_Square.gif
--------------------------------------------------------------------------------
/static/contour.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/static/contour.jpg
--------------------------------------------------------------------------------
/static/frame.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/static/frame.jpg
--------------------------------------------------------------------------------
/static/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/static/placeholder.png
--------------------------------------------------------------------------------
/templates/static/contour.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/templates/static/contour.jpg
--------------------------------------------------------------------------------
/templates/static/frame.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/templates/static/frame.jpg
--------------------------------------------------------------------------------
/templates/static/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philzook58/FartMachine10/master/templates/static/placeholder.png
--------------------------------------------------------------------------------
/templates/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Test
4 |
5 |
6 | Here we gooooo {{a}}
7 |
8 |
9 |
--------------------------------------------------------------------------------
/templates/gcode.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Gcode
4 |
5 |
6 | Draw
7 |
8 |
9 |
--------------------------------------------------------------------------------
/draw/test.py:
--------------------------------------------------------------------------------
1 | from DrawBot import DrawBot
2 |
3 | bot = DrawBot()
4 | print bot.draw(["G1 X300 400"])
5 | print "mybutt"
6 | print bot.draw(["G1 X300 400"])
7 | print "your butt"
8 | print bot.draw(["G1 X300 400"])
9 | print "his butt"
--------------------------------------------------------------------------------
/outputface_0005.gcode:
--------------------------------------------------------------------------------
1 | M05 S0
2 |
3 | G90
4 | G21
5 | G1 F3000
6 | G1 X0.5702 Y0.5702
7 | G4 P0
8 | M03 S256
9 | G4 P0
10 | G1 F100.000000
11 | G1 X9.693 Y8.8377
12 | G4 P0
13 | M05 S0
14 | G1 F3000
15 | G1 X0 Y0
16 | M18
17 |
--------------------------------------------------------------------------------
/output_0001.gcode:
--------------------------------------------------------------------------------
1 | M05 S0
2 |
3 | G90
4 | G21
5 | G1 F3000
6 | G1 X48.381 Y92.7302
7 | G4 P0
8 | M03 S256
9 | G4 P0
10 | G1 F100.000000
11 | G1 X121.7587 Y146.7556
12 | G1 X18.546 Y169.3333
13 | G1 X-1.6127 Y13.7079
14 | G1 X48.381 Y92.7302
15 | G4 P0
16 | M05 S0
17 | G1 F3000
18 | G1 X0 Y0
19 | M18
20 |
--------------------------------------------------------------------------------
/outputface_0003.gcode:
--------------------------------------------------------------------------------
1 | M05 S0
2 |
3 | G90
4 | G21
5 | G1 F3000
6 | G1 X4.8465 Y13.114
7 | G4 P0
8 | M03 S256
9 | G4 P0
10 | G1 F100.000000
11 | G1 X38.2017 Y13.114
12 | G1 X38.2017 Y40.1973
13 | G1 X5.1316 Y40.1973
14 | G1 X4.8465 Y13.114
15 | G4 P0
16 | M05 S0
17 | G1 F3000
18 | G1 X0 Y0
19 | M18
20 |
--------------------------------------------------------------------------------
/outputface_0004.gcode:
--------------------------------------------------------------------------------
1 | M05 S0
2 |
3 | G90
4 | G21
5 | G1 F3000
6 | G1 X0.5702 Y0.2851
7 | G4 P0
8 | M03 S256
9 | G4 P0
10 | G1 F100.000000
11 | G1 X33.9254 Y0.2851
12 | G1 X33.9254 Y27.3684
13 | G1 X0.8553 Y27.3684
14 | G1 X0.5702 Y0.2851
15 | G4 P0
16 | M05 S0
17 | G1 F3000
18 | G1 X0 Y0
19 | M18
20 |
--------------------------------------------------------------------------------
/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | /photo to take picture.
5 | go to /gcode to enter gcode.
6 | go to /home to home pne height.
7 | /reset for xy position reset
8 | /move
9 |
10 |
11 |
--------------------------------------------------------------------------------
/templates/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | /photo to take picture.
5 | go to /gcode to enter gcode.
6 | go to /home to home pne height.
7 | /reset for xy position reset
8 | /move
9 |
10 |
11 |
--------------------------------------------------------------------------------
/photo/test.py:
--------------------------------------------------------------------------------
1 | from PhotoConverter import PhotoConverter
2 | import time
3 |
4 | mydude = PhotoConverter()
5 | mydude.takePhoto()
6 | mydude.drawContours()
7 | mydude.sortContours()
8 | mydude.drawContours()
9 | mydude.scaleContours(1600,1200)
10 | mydude.drawContours()
11 | #print mydude.convertContourstoGcode()
12 | #mydude.simplifyContours()
13 | #mydude.drawContours()
14 |
15 |
--------------------------------------------------------------------------------
/test_server.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from flask import render_template
3 | import threading
4 | import time
5 |
6 | app = Flask(__name__)
7 |
8 | a = 1
9 |
10 | @app.route("/")
11 | def hello():
12 | return render_template('test.html', a=a)
13 |
14 |
15 |
16 | t = threading.Thread(target=app.run)
17 | t.start()
18 |
19 | for i in range(1000):
20 | a+=1
21 | time.sleep(1)
22 |
23 |
--------------------------------------------------------------------------------
/flasktest.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, url_for
2 | from flask import render_template
3 | app = Flask(__name__)
4 |
5 | @app.route("/")
6 | def whathello():
7 | return "Hello World!"
8 |
9 | if __name__ == "__main__":
10 | app.run()
11 |
12 | @app.route('/hello/')
13 | @app.route('/hello/')
14 | def hello(name=None):
15 | return render_template('hello.html', name=name)
16 |
17 | url_for('static', filename='style.css')
18 |
--------------------------------------------------------------------------------
/draw_module_test.py:
--------------------------------------------------------------------------------
1 | from draw import DrawBot
2 | import sys
3 | from flask import Flask
4 | from flask import render_template
5 | import threading
6 | import time
7 |
8 | bot = DrawBot("/dev/ttyUSB0")
9 |
10 |
11 |
12 | filename = sys.argv[1]
13 | gcode = '''
14 | G90
15 |
16 | G21
17 |
18 | G1 F3000
19 |
20 | G1 X0.5702 Y0.5702
21 |
22 | G1 X0 Y0
23 |
24 | G1 X0.5 Y0.5
25 | '''
26 |
27 |
28 | bot.draw(gcode.split('\n'))
29 | #bot.drawFromFile(filename)
30 |
--------------------------------------------------------------------------------
/googletest.py:
--------------------------------------------------------------------------------
1 | #need to install firefox
2 | # selenium, unidecode
3 |
4 | from google import google, images
5 |
6 | options = images.ImageOptions()
7 | #options.image_type = images.ImageType.LINE_DRAWING
8 | #options.format =
9 | results = google.search_images("banana svg", options)
10 | print results
11 |
12 | for result in results:
13 | if result.link[-4:] == '.svg':
14 | images.download([result], path = "images/")
15 | print "downloaded image"
16 |
--------------------------------------------------------------------------------
/banana.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gcode.py:
--------------------------------------------------------------------------------
1 |
2 | from parse import compile
3 | mycode = "G01 X1.0000 Y3.0000"
4 | p = compile("G{code} X{x} Y{y}")
5 | command = p.parse(mycode)
6 | print command
7 |
8 |
9 | #Does not do what I want
10 | '''
11 | mycode = "G04"
12 | command = p.parse(mycode)
13 | print command
14 | '''
15 |
16 |
17 |
18 | f= open("output_001.gcode")
19 | for line in f:
20 | print line
21 | if line[0:3] == "G01":
22 | command = p.parse(line)
23 | draw_line
24 | elif line[0:3] == "G03":
25 | raisepen()
26 | elif line[0:3] == "G05":
27 | lowerpen()
28 |
--------------------------------------------------------------------------------
/outputface_0006.gcode:
--------------------------------------------------------------------------------
1 | M05 S0
2 |
3 | G90
4 | G21
5 | G1 F3000
6 | G1 X0.5702 Y0.5702
7 | G4 P0
8 | M03 S256
9 | G4 P0
10 | G1 F100.000000
11 | G1 X9.693 Y8.8377
12 | G4 P0
13 | M05 S0
14 | G1 F3000
15 | G1 X0.8553 Y27.3684
16 | G4 P0
17 | M03 S256
18 | G4 P0
19 | G1 F100.000000
20 | G1 X9.4079 Y35.6359
21 | G4 P0
22 | M05 S0
23 | G1 F3000
24 | G1 X33.3552 Y26.7982
25 | G4 P0
26 | M03 S256
27 | G4 P0
28 | G1 F100.000000
29 | G1 X42.478 Y35.3509
30 | G4 P0
31 | M05 S0
32 | G1 F3000
33 | G1 X34.4956 Y0.
34 | G4 P0
35 | M03 S256
36 | G4 P0
37 | G1 F100.000000
38 | G1 X43.0482 Y8.5526
39 | G4 P0
40 | M05 S0
41 | G1 F3000
42 | G1 X0.5702 Y0.2851
43 | G4 P0
44 | M03 S256
45 | G4 P0
46 | G1 F100.000000
47 | G1 X33.9254 Y0.2851
48 | G1 X33.9254 Y27.3684
49 | G1 X0.8553 Y27.3684
50 | G1 X0.5702 Y0.2851
51 | G4 P0
52 | M05 S0
53 | G1 F3000
54 | G1 X0 Y0
55 | M18
56 |
--------------------------------------------------------------------------------
/outputface_0007.gcode:
--------------------------------------------------------------------------------
1 | M05 S0
2 |
3 | G90
4 | G21
5 | G1 F3000
6 | G1 X0.5702 Y0.5702
7 | G4 P0
8 | M03 S256
9 | G4 P0
10 | G1 F100.000000
11 | G1 X9.693 Y8.8377
12 | G4 P0
13 | M05 S0
14 | G1 F3000
15 | G1 X0.8553 Y27.3684
16 | G4 P0
17 | M03 S256
18 | G4 P0
19 | G1 F100.000000
20 | G1 X9.4079 Y35.6359
21 | G4 P0
22 | M05 S0
23 | G1 F3000
24 | G1 X33.3552 Y26.7982
25 | G4 P0
26 | M03 S256
27 | G4 P0
28 | G1 F100.000000
29 | G1 X42.478 Y35.3509
30 | G4 P0
31 | M05 S0
32 | G1 F3000
33 | G1 X34.4956 Y0.
34 | G4 P0
35 | M03 S256
36 | G4 P0
37 | G1 F100.000000
38 | G1 X43.0482 Y8.5526
39 | G4 P0
40 | M05 S0
41 | G1 F3000
42 | G1 X0.5702 Y0.2851
43 | G4 P0
44 | M03 S256
45 | G4 P0
46 | G1 F100.000000
47 | G1 X33.9254 Y0.2851
48 | G1 X33.9254 Y27.3684
49 | G1 X0.8553 Y27.3684
50 | G1 X0.5702 Y0.2851
51 | G4 P0
52 | M05 S0
53 | G1 F3000
54 | G1 X0 Y0
55 | M18
56 |
--------------------------------------------------------------------------------
/outputface_0008.gcode:
--------------------------------------------------------------------------------
1 | M05 S0
2 |
3 | G90
4 | G21
5 | G1 F3000
6 | G1 X0.5702 Y0.5702
7 | G4 P0
8 | M03 S256
9 | G4 P0
10 | G1 F100.000000
11 | G1 X9.693 Y8.8377
12 | G4 P0
13 | M05 S0
14 | G1 F3000
15 | G1 X0.8553 Y27.3684
16 | G4 P0
17 | M03 S256
18 | G4 P0
19 | G1 F100.000000
20 | G1 X9.4079 Y35.6359
21 | G4 P0
22 | M05 S0
23 | G1 F3000
24 | G1 X33.3552 Y26.7982
25 | G4 P0
26 | M03 S256
27 | G4 P0
28 | G1 F100.000000
29 | G1 X42.478 Y35.3509
30 | G4 P0
31 | M05 S0
32 | G1 F3000
33 | G1 X34.4956 Y0.
34 | G4 P0
35 | M03 S256
36 | G4 P0
37 | G1 F100.000000
38 | G1 X43.0482 Y8.5526
39 | G4 P0
40 | M05 S0
41 | G1 F3000
42 | G1 X8.4724 Y35.2706
43 | G4 P0
44 | M03 S256
45 | G4 P0
46 | G1 F100.000000
47 | G1 X41.8276 Y35.2706
48 | G1 X41.8276 Y8.1873
49 | G1 X8.7575 Y8.1873
50 | G1 X8.4724 Y35.2706
51 | G4 P0
52 | M05 S0
53 | G1 F3000
54 | G1 X0 Y0
55 | M18
56 |
--------------------------------------------------------------------------------
/templates/camera.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
28 |
29 | Take Snapshot
30 |
--------------------------------------------------------------------------------
/outputface_0009.gcode:
--------------------------------------------------------------------------------
1 | M05 S0
2 |
3 | G90
4 | G21
5 | G1 F3000
6 | G1 X31.3596 Y31.6447
7 | G4 P0
8 | M03 S256
9 | G4 P0
10 | G1 F100.000000
11 | G1 X31.6447 Y61.2938
12 | G4 P0
13 | M05 S0
14 | G1 F3000
15 | G1 X23.0921 Y53.5965
16 | G4 P0
17 | M03 S256
18 | G4 P0
19 | G1 F100.000000
20 | G1 X31.6447 Y61.5789
21 | G1 X66.4254 Y61.2938
22 | G4 P0
23 | M05 S0
24 | G1 F3000
25 | G1 X58.4429 Y53.3114
26 | G4 P0
27 | M03 S256
28 | G4 P0
29 | G1 F100.000000
30 | G1 X66.9956 Y60.7236
31 | G1 X66.7105 Y31.3596
32 | G1 X58.4429 Y23.6623
33 | G1 X58.1578 Y24.8026
34 | G4 P0
35 | M05 S0
36 | G1 F3000
37 | G1 X23.0921 Y24.2324
38 | G4 P0
39 | M03 S256
40 | G4 P0
41 | G1 F100.000000
42 | G1 X32.2149 Y31.3596
43 | G1 X66.4254 Y31.3596
44 | G4 P0
45 | M05 S0
46 | G1 F3000
47 | G1 X23.0921 Y23.9474
48 | G4 P0
49 | M03 S256
50 | G4 P0
51 | G1 F100.000000
52 | G1 X58.4429 Y23.9474
53 | G1 X58.4429 Y53.3114
54 | G1 X22.807 Y53.3114
55 | G1 X23.0921 Y23.9474
56 | G4 P0
57 | M05 S0
58 | G1 F3000
59 | G1 X0 Y0
60 | M18
61 |
--------------------------------------------------------------------------------
/outputface_0002.gcode:
--------------------------------------------------------------------------------
1 | M05 S0
2 |
3 | G90
4 | G21
5 | G1 F3000
6 | G1 X27.9383 Y38.9866
7 | G4 P0
8 | M03 S256
9 | G4 P0
10 | G1 F100.000000
11 | G3 X15.0865 Y33.6632 I0. J-18.1752
12 | G3 X9.7631 Y20.8114 I12.8518 J-12.8518
13 | G3 X15.0865 Y7.9596 I18.1752 J-0.
14 | G3 X27.9383 Y2.6362 I12.8518 J12.8518
15 | G3 X40.7905 Y7.9595 I0. J18.1762
16 | G3 X46.1141 Y20.8114 I-12.8512 J12.8519
17 | G3 X40.7905 Y33.6633 I-18.1748 J0.
18 | G3 X27.9383 Y38.9866 I-12.8522 J-12.8528
19 | G1 X27.9383 Y38.9866
20 | G4 P0
21 | M05 S0
22 | G1 F3000
23 | G1 X27.9383 Y37.9867
24 | G4 P0
25 | M03 S256
26 | G4 P0
27 | G1 F100.000000
28 | G2 X40.0835 Y32.9562 I-0. J-17.1763
29 | G2 X45.1142 Y20.8114 I-12.1442 J-12.1448
30 | G2 X40.0835 Y8.6665 I-17.1749 J-0.
31 | G2 X27.9383 Y3.6361 I-12.1451 J12.1458
32 | G2 X15.7936 Y8.6666 I-0. J17.1753
33 | G2 X10.763 Y20.8114 I12.1448 J12.1448
34 | G2 X15.7936 Y32.9562 I17.1753 J0.
35 | G2 X27.9383 Y37.9867 I12.1448 J-12.1448
36 | G1 X27.9383 Y37.9867
37 | G4 P0
38 | M05 S0
39 | G1 F3000
40 | G1 X0 Y0
41 | M18
42 |
--------------------------------------------------------------------------------
/server.csr:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE REQUEST-----
2 | MIIClzCCAX8CAQAwUjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlJJMRMwEQYDVQQH
3 | DApQcm92aWRlbmNlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQw
4 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSLNTDP6NzVFCzxdnB9Axg
5 | GLr6Uxl0muhSs0CMHU4bKKfrk+8JJpu+LJAEh7fguf+8WiLvX59GQxrxbT4khV/u
6 | dG4ZkQtyvP9DdcEmM/86jLqNPDj+yXohGp72jLQB0vvLrqUcdZy0MeiUbAVW6ywx
7 | uQca3RqjpsrSyNf0HN+ShVjONGfSW2R+IYGUXR6pAI9NiDliaOTPayPfETbWmPOB
8 | EY2zlG6xy71O2eNSoCKj6Dz0HEnucRU1Mo0wKrpOSmHZ/qQL+/LJQlo9jd7y0wpI
9 | Awmioh7ZkAoPrs7LCxCFDnSygZZLqQsbluVy333VWI+GIzwPv7f/Jv2Ad6n51qLb
10 | AgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAqDnOBCpqXfhcstzvshW9nKofe88H
11 | lHjwlelcjavcIuiKfoFNhFzmxj4xJi4Hw+6jIoLTYMaFXHRcqgedI8EQclahFW0T
12 | n+r46il94b9Z6ncAk19vDjoB4tCGycAhUm2vnEpB0JCgOnoJ9Sa9wT0/KClN52bP
13 | xyPAF6CZ6nKb36T09swMQFIEPJZSNWs+CNYiatg63+LMyNuFUWH8pZ5mRM05Glhg
14 | sk0mqaVPLL4k52Ls1tep4XGXJQaRIkGVDEy+08a5DLb2W8gs3mMHvYZn+bB7Vgfu
15 | EEEeBIymXtULtLPBlcb1QFakq/Il17RLytv46uoexORQnMNPneQl7tnK2Q==
16 | -----END CERTIFICATE REQUEST-----
17 |
--------------------------------------------------------------------------------
/server.key.org:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | Proc-Type: 4,ENCRYPTED
3 | DEK-Info: DES-EDE3-CBC,CD8DEB8891BEC75F
4 |
5 | xXDF8x8fEbPmId90CYveXlbqTf4Q4mkCJl+2SnduVvT/nK2ETts6ZJVxU6vvaMoh
6 | BwlbHlwf1+LLP0lfb6LmLo+7OVLACO2X8lsE7wun7PbxsavflnIsXhuHTXQpQwH8
7 | tFPWUteP2Q0fJTa5JWEmNu5i1vUizru7cdSg8W92VbQm5RUnUgaqEq/59jWrbOW+
8 | 6kzhLIwrV/ShWQs2LKACH2TvH3+Py7uTAXdSvLQHMcsssEWe7XGxEUqADv1Vc55I
9 | pw7qeV7wZmjVlmUtaPe1vQfdRmbxtk059L/WEHBkWrcwIlrAzt8DuAvgK4lKJGTS
10 | Mi+QRt3olR50ScKuC4OtwI1KjVgbcVA7JTrvVZ323/6UMIjY79Rak3gCbTtUg1or
11 | pxtMsDaEDHMj7gGh6vyzCGxa5YX2YpVHFOyXDndR34FF5UQhBnBdBHuuGtIQk8AH
12 | 3a8o+ZWS3vT4ezCJX5QAwr/81D/O+VnHj6v9wP4nTujLoO18Rh4LNiGtbN+zR51y
13 | u92IccyzKXT1CGUYKdtfGyJ4e86ihL8LZGWK93u/p5M6hZ+03ttnLIoltd1pKoK3
14 | c01ZXsU3nEXvQV34G8mlUNmbUd72MWMCWZbRL2PqwRjQJ7Fvtyqq3N62syuXzh2g
15 | mlfCwk8Zlv+ViA2PuSYBcJMZW9hnUYtwhUSoGY1lvzYJu2OQAQAepp8+MLpKZvNj
16 | t5We6bOk9U4BhgpRXLoF5lkHJxoTZ5oBhQtjEyc2Q5cgM/koOxc+w7yzvCCqnkcT
17 | 4wqdJKGldIxHXiJEtVDJHC5rTp/wgt7kamgr3baauS62rfArsuaoYQ==
18 | -----END RSA PRIVATE KEY-----
19 |
--------------------------------------------------------------------------------
/randon_walk.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import cv2
3 |
4 |
5 | grayimg = cv2.imread('./dogman.jpg',0)
6 | maxval = np.max(grayimg)
7 | img = np.zeros((512,512,3), np.uint8)
8 |
9 |
10 | def inbounds(pos):
11 | if pos[0] < 0:
12 | return False
13 | if pos[1] < 0:
14 | return False
15 | if pos[0] > grayimg.shape[0]:
16 | return False
17 | if pos[1] > grayimg.shape[1]:
18 | return False
19 | return True
20 |
21 |
22 | def move_to(pos):
23 | #cv2.line(img,(int(x[1]),int(x[0])),(int(pos[1]),int(pos[0])),(255,0,0),1)
24 | cv2.circle(img,(int(pos[1]),int(pos[0])),1,(255,0,0),1)
25 |
26 | def accept(pos):
27 | return inbounds(pos) and np.random.random()*maxval > grayimg[ int(pos[0]), int(pos[1])]
28 | x = np.zeros(2)
29 |
30 |
31 | for i in range(100000):
32 | angle = np.random.random()*2*np.pi
33 | r = 50
34 | pos = x + np.array([np.cos(angle), np.sin(angle)]) * r
35 |
36 | if accept(pos):
37 | move_to(pos)
38 | x = pos
39 |
40 | cv2.imshow('lineman',img)
41 | cv2.imshow('dogman',grayimg)
42 | cv2.waitKey(0)
43 |
--------------------------------------------------------------------------------
/edge_filter.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import random
3 |
4 | import numpy as np
5 | import matplotlib.pyplot as plt
6 | import time
7 |
8 | cam = cv2.VideoCapture(0)
9 | s, im = cam.read() # captures image
10 | s, im = cam.read()
11 | time.sleep(.2)
12 | s, im = cam.read()
13 | gray_im = cv2.cvtColor( im, cv2.COLOR_BGR2GRAY );
14 |
15 | edges = cv2.Canny(gray_im,100,200)
16 |
17 | height, width = edges.shape
18 | contours, hierarchy = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
19 |
20 |
21 | target = open('out.gcode', 'w')
22 |
23 |
24 | cv2.drawContours(im, contours, -1, (0,255,0), 3)
25 | cv2.imshow("Test Picture", im)
26 | cv2.waitKey()
27 |
28 | pen_down = False
29 |
30 |
31 | for contour in contours:
32 | for point in contour:
33 | target.write("G1 X" + str(point[0][0] * 1280 / width) + " Y" + str(point[0][1] * 720 / height) + "\n")
34 | if not pen_down:
35 | target.write("M03\n")
36 | pen_down = True
37 | target.write("M05\n")
38 | pen_down = False
39 |
40 | '''
41 | for contour in contours:
42 | for point in contour:
43 | print point[0]
44 | print
45 | '''
46 |
--------------------------------------------------------------------------------
/spiral.py:
--------------------------------------------------------------------------------
1 |
2 | from parse import compile
3 | p = compile("G{code} X{x} Y{y}")
4 | import sys
5 | import serial
6 | port = '/dev/cu.wch'#'/dev/ttyUSB0'#'tty.wch'#'cu.wch ch341 USB=>RS232 1410'
7 | ser = serial.Serial(port,38400) # open serial port
8 | print(ser.name) # check which port was really used
9 | import numpy as np
10 | import time
11 |
12 |
13 | def raisepen():
14 | ser.write('30c')
15 | #time.sleep(0.1)
16 | def lowerpen():
17 | ser.write('20c')
18 | #time.sleep(0.1)
19 |
20 |
21 | def convertToMotor(x):
22 | return np.array([x[0]+x[1],x[0]-x[1]])/np.sqrt(2)
23 |
24 |
25 | def move_to(x):
26 | x = convertToMotor(x)
27 | ser.write(str(int(x[0])) + b'a')
28 | ser.write(str(int(x[1])) + b'b')
29 | ser.write(b'x')
30 | print ser.readline()
31 | #time.sleep(.1)
32 | print ser.readline()
33 |
34 | radius = 400
35 | N = 14
36 | maxangle = 2 * np.pi * N
37 | deltaangle = 2 * np.pi / 6
38 | angles = np.arange(0,maxangle,deltaangle)
39 | r = angles * radius / maxangle
40 | x = r * np.cos(angles)
41 | y = r * np.sin(angles)
42 |
43 | lowerpen()
44 | for i in range(len(x)):
45 | move_to(np.array([x[i],y[i]]))
46 |
47 | ser.close()
48 |
--------------------------------------------------------------------------------
/server.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDIDCCAggCCQD4tbLQPwroeDANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJV
3 | UzELMAkGA1UECAwCUkkxEzARBgNVBAcMClByb3ZpZGVuY2UxITAfBgNVBAoMGElu
4 | dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNjA1MTEwMDE1MjRaFw0xNzA1MTEw
5 | MDE1MjRaMFIxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJSSTETMBEGA1UEBwwKUHJv
6 | dmlkZW5jZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjAN
7 | BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0izUwz+jc1RQs8XZwfQMYBi6+lMZ
8 | dJroUrNAjB1OGyin65PvCSabviyQBIe34Ln/vFoi71+fRkMa8W0+JIVf7nRuGZEL
9 | crz/Q3XBJjP/Ooy6jTw4/sl6IRqe9oy0AdL7y66lHHWctDHolGwFVussMbkHGt0a
10 | o6bK0sjX9BzfkoVYzjRn0ltkfiGBlF0eqQCPTYg5Ymjkz2sj3xE21pjzgRGNs5Ru
11 | scu9TtnjUqAio+g89BxJ7nEVNTKNMCq6Tkph2f6kC/vyyUJaPY3e8tMKSAMJoqIe
12 | 2ZAKD67OywsQhQ50soGWS6kLG5blct991ViPhiM8D7+3/yb9gHep+dai2wIDAQAB
13 | MA0GCSqGSIb3DQEBCwUAA4IBAQCWTqqzfyR2PoIPEFuVwYx+2ws2FAwN+mkJur8o
14 | QLq0MsEglvHD6BJIoXt5lw0IN0hM+QRMA82cr2+skhFL3n8+TSMVxwHDoWmEV3iw
15 | NV1Rt/3caMuibT+tgVq1tk1919MQBKUZQcqK3E8M8A8TYYzHHCLxtCSMW5ELVJ9E
16 | BAA3WqJC/ZevsZpCdGaexlEy86E8kdR0+FhxAIFcLE1fGfCm4kHs9LaaE3WyeU4k
17 | pm+TpuehOxyYFH3CstXtQ5Y2/aVZ9IvVzRfYPtJJaBuo1MBu/kUutuQSbzCVwTzl
18 | GWmFOxySkDUqQlSyfmGst8Eu5LA5rMDr9LL/vFjxMWnGYAbm
19 | -----END CERTIFICATE-----
20 |
--------------------------------------------------------------------------------
/photo_server.py:
--------------------------------------------------------------------------------
1 | from draw import DrawBot
2 | import sys
3 | from flask import Flask
4 | from flask import request
5 | from flask import render_template
6 | from flask import send_from_directory
7 | import threading
8 | import time
9 | import base64
10 |
11 | app = Flask(__name__)
12 | app.debug = True
13 |
14 | #bot = DrawBot("/dev/ttyUSB0")
15 |
16 | from OpenSSL import SSL
17 | context = SSL.Context(SSL.SSLv23_METHOD)
18 | context.use_privatekey_file('server.key')
19 | context.use_certificate_file('server.crt')
20 |
21 | @app.route("/")
22 | def hello():
23 | return render_template("camera.html")
24 |
25 | @app.route('/js/')
26 | def send_js(path):
27 | print path
28 | return send_from_directory('js', path)
29 |
30 | @app.route("/draw")
31 | def draw():
32 | bot.draw(request.args.get('gcode','').split('\r\n'))
33 | return 'done '
34 |
35 | @app.route("/image", methods=['POST'])
36 | def image():
37 | #newjpgtxt = request.get_json().get('data','').split(",")
38 | newjpgtxt = request.form['data'].split(",")[1]
39 | g = open("out.jpg", "w")
40 | g.write(base64.decodestring(newjpgtxt))
41 | g.close()
42 | return 'done '
43 |
44 | app.run(host='0.0.0.0', ssl_context=context)
45 |
--------------------------------------------------------------------------------
/contour.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import cv2
3 |
4 | def show_contour(filename):
5 | im = cv2.imread(filename)
6 | imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
7 |
8 |
9 | #Tighten up threshold to avoid watermarks
10 | ret,thresh = cv2.threshold(imgray,200,255,0)
11 | #thresh = cv2.Canny(imgray,100,200)
12 | contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
13 | print hierarchy
14 | #**[Next, Previous, First_Child, Parent]**
15 |
16 | empty = np.zeros(im.shape,np.uint8)
17 | empty2 = np.zeros(im.shape,np.uint8)
18 | #To remove border. This is bad if image touches boundaries. Buffer image?
19 | ymax = 1000.
20 | xmax = 1000.
21 | scale = min(ymax/im.shape[0], xmax/im.shape[1])
22 |
23 |
24 | for i in range(len(contours)):
25 | if hierarchy[0,i,3] != -1:
26 | cv2.drawContours(empty,contours,i,(0,255,0),1)
27 | #cv2.imshow('res',empty)
28 | cv2.drawContours(empty2,contours,-1,(0,255,0),1)
29 | #cv2.imshow('butt',empty2)
30 | #if cv2.waitKey(0) & 0xff == 27:
31 | # cv2.destroyAllWindows()
32 | writename = '/'.join(filename.split('/')[:-1]) + '/' + 'contour.jpg'
33 | cv2.imwrite(writename,empty)
34 | #show_contour('images/bird_bird/bird-skeleton-big.jpg')
35 |
--------------------------------------------------------------------------------
/hatch_test.py:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | import numpy as np
5 | import cv2
6 |
7 |
8 | pendown = False
9 | img = np.zeros((512,512,3), np.uint8)
10 | x = np.array([0,0])
11 | def raisepen():
12 | global pendown
13 | pendown = False
14 | def lowerpen():
15 | global pendown
16 | pendown = True
17 | def move_to(xnew):
18 | global img
19 | global x
20 | xnew = np.rint(xnew).astype(int)
21 | if pendown:
22 | cv2.line(img,(x[1],x[0]),(xnew[1],xnew[0]),(255,0,0),5)
23 | x = xnew
24 |
25 | grayimg = cv2.imread('./dogman.jpg',0)
26 |
27 | #cv2.imshow('dogman',grayimg)
28 | #cv2.waitKey(0)
29 | grayimg = cv2.pyrDown(grayimg)
30 | grayimg = cv2.pyrDown(grayimg)
31 | grayimg = cv2.pyrDown(grayimg)
32 | grayimg = cv2.pyrDown(grayimg)
33 | print grayimg.shape
34 |
35 | scale = 20.
36 | maxval = float(np.max(grayimg))
37 | #cv2.line(img,(0,0),(511,511),(255,0,0),5)
38 | print maxval
39 | print grayimg
40 | for i in range(grayimg.shape[0]):
41 | move_to( np.array([i , 0] ) * scale)
42 | for j in range(grayimg.shape[1]):
43 | raisepen()
44 | move_to( np.array([i , j + grayimg[i,j]/maxval] ) * scale)
45 | lowerpen()
46 | move_to( np.array([i, j+1]) * scale )
47 | raisepen()
48 |
49 | cv2.imshow('lineman',img)
50 | cv2.imshow('dogman',grayimg)
51 | cv2.waitKey(0)
52 |
--------------------------------------------------------------------------------
/hatch.py:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | import numpy as np
5 | import cv2
6 |
7 |
8 | import sys
9 | import serial
10 | port = '/dev/cu.wch ch341 USB=>RS232 1410'#'tty.wch'#'cu.wch ch341 USB=>RS232 1410'
11 | ser = serial.Serial(port,38400) # open serial port
12 | print(ser.name) # check which port was really used
13 | import numpy as np
14 | import time
15 |
16 |
17 | def raisepen():
18 | ser.write('55c')
19 | time.sleep(0.1)
20 | def lowerpen():
21 | ser.write('40c')
22 | time.sleep(0.1)
23 |
24 | def convertToMotor(x):
25 | return np.array([x[0]+x[1],x[0]-x[1]])*5/np.sqrt(2)
26 |
27 | def move_to(x):
28 | x = convertToMotor(x)
29 | ser.write(str(int(x[0])) + b'a')
30 | ser.write(str(int(x[1])) + b'b')
31 | ser.write(b'x')
32 | print ser.readline()
33 | time.sleep(.1)
34 |
35 | print ser.readline()
36 | grayimg = cv2.imread('./dogman.jpg',0)
37 |
38 | #cv2.imshow('dogman',grayimg)
39 | #cv2.waitKey(0)
40 | grayimg = cv2.pyrDown(grayimg)
41 | grayimg = cv2.pyrDown(grayimg)
42 | grayimg = cv2.pyrDown(grayimg)
43 | grayimg = cv2.pyrDown(grayimg)
44 | print grayimg.shape
45 |
46 | scale = 6.
47 | maxval = np.max(grayimg)
48 |
49 | for i in range(grayimg.shape[0]):
50 | for j in range(grayimg.shape[1]):
51 | lowerpen()
52 | move_to( np.array([i , j + grayimg[i,j]/maxval] ) * scale)
53 | raisepen()
54 | move_to( np.array([i, j+1]) * scale )
55 |
--------------------------------------------------------------------------------
/webspeech/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
47 |
48 |
49 |
50 |
51 |
52 | Click to talk
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/control.py:
--------------------------------------------------------------------------------
1 | import serial
2 | port = '/dev/cu.wch ch341 USB=>RS232 1410'#'tty.wch'#'cu.wch ch341 USB=>RS232 1410'
3 | ser = serial.Serial(port,38400) # open serial port
4 | print(ser.name) # check which port was really used
5 | import numpy as np
6 | import time
7 |
8 |
9 | x = np.zeros(2)
10 |
11 | N=1000
12 |
13 | globalsteps = np.array([0,0])
14 |
15 | def raisepen():
16 | pass
17 | def lowerpen():
18 | pass
19 |
20 |
21 | def move(steps):
22 | #print steps
23 | global globalsteps
24 | ser.write(str(int(steps[0])) + b'a')
25 | ser.write(str(int(steps[1])) + b'b')
26 | globalsteps = globalsteps + steps
27 | #print globalsteps
28 |
29 |
30 |
31 | def convertToMotor(x):
32 | return np.array([x[0]+x[1],x[0]-x[1]])
33 |
34 | def draw_line(x,xend):
35 | x = convertToMotor(x)
36 | xend = convertToMotor(xend)
37 | deltax = (xend - x)/N
38 | xint = np.rint(x)
39 | for i in range(N):
40 | x = x + deltax
41 | #print x
42 | if np.any(np.rint(x) != xint):
43 | steps = np.rint(x) - xint
44 | move(steps)
45 | xint = np.rint(x)
46 | time.sleep(0.03)
47 |
48 |
49 | pos = np.array([[-10.,-10.], [10.,-10.],[-10.,-10.], [-10.,10.]])*3
50 | i = 0
51 | while(1):
52 |
53 | draw_line(x,pos[i,:])
54 | x = pos[i,:]
55 | print x
56 | time.sleep(.5)
57 | print("YO")
58 | #print(ser.read(100))
59 | i+= 1
60 | i = i%4
61 | ser.close() # close port
62 |
--------------------------------------------------------------------------------
/gcode2.py:
--------------------------------------------------------------------------------
1 |
2 | from parse import compile
3 | p = compile("G{code} X{x} Y{y}")
4 | import sys
5 | import serial
6 | port = '/dev/cu.wch ch341 USB=>RS232 1410'#'tty.wch'#'cu.wch ch341 USB=>RS232 1410'
7 | ser = serial.Serial(port,38400) # open serial port
8 | print(ser.name) # check which port was really used
9 | import numpy as np
10 | import time
11 |
12 |
13 | def raisepen():
14 | ser.write('70c')
15 | time.sleep(0.1)
16 | def lowerpen():
17 | ser.write('95c')
18 | time.sleep(0.1)
19 |
20 |
21 |
22 |
23 | def move(steps):
24 | ser.write(str(int(steps[0])) + b'a')
25 | ser.write(str(int(steps[1])) + b'b')
26 |
27 | def convertToMotor(x):
28 | return np.array([x[0]+x[1],x[0]-x[1]])
29 |
30 | def draw_line(x,xend):
31 | x = convertToMotor(x)
32 | xend = convertToMotor(xend)
33 | deltax = (xend - x)/N
34 | xint = np.rint(x)
35 | for i in range(N):
36 | x = x + deltax
37 | #print x
38 | if np.any(np.rint(x) != xint):
39 | steps = np.rint(x) - xint
40 | move(steps)
41 | xint = np.rint(x)
42 | time.sleep(0.03)
43 |
44 | x = np.zeros(2)
45 | N=1000
46 | raisepen()
47 | filename = sys.argv[1]
48 | f= open(filename)
49 | for line in f:
50 | print line
51 | if line[0:2] == "G1":
52 | command = p.parse(line)
53 | if command != None:
54 | command = command.named
55 | xnew = np.array([float(command['x']),float(command['y'])])
56 | draw_line(x, xnew)
57 | x = xnew
58 | elif line[0:3] == "M05":
59 | raisepen()
60 | elif line[0:3] == "M03":
61 | lowerpen()
62 |
63 | ser.close() # close port
64 |
--------------------------------------------------------------------------------
/Core_XY_control2/Core_XY_control2.ino:
--------------------------------------------------------------------------------
1 |
2 | int v = 0;
3 | int sign = 1;
4 |
5 | #include
6 | #include
7 | // write a,b for steppers
8 | Stepper motor1 = Stepper(200, 4,5, 6,7);
9 | Stepper motor2 = Stepper(200, 10,11,12,13);
10 | Servo myservo;
11 |
12 | void setup() {
13 |
14 | Serial.begin(38400);
15 | Serial.println("Stepper test!");
16 | motor1.setSpeed(60); // rpm
17 | motor2.setSpeed(60);
18 | myservo.attach(3);
19 | }
20 |
21 | void loop() {
22 | // put your main code here, to run repeatedly:
23 | if ( Serial.available()) {
24 | char ch = Serial.read();
25 |
26 | switch(ch) {
27 | case '0'...'9':
28 | //Pretty goddamn clever right here. Not mine.
29 | v = v * 10 + ch - '0';
30 | break;
31 | case '-':
32 | //Pretty goddamn clever right here. This time ours.
33 | sign *= -1;
34 | //Serial.println("NEGATE!");
35 | break;
36 | case 'a':
37 | move('a', v, sign);
38 | resetV();
39 | break;
40 | case 'b':
41 | move('b', v, sign);
42 | resetV();
43 | break;
44 | case 'c':
45 | move('c', v, sign);
46 | resetV();
47 | break;
48 |
49 | default:
50 | Serial.write("...the fuck is that?");
51 | resetV();
52 | break;
53 | }
54 | }
55 | }
56 |
57 | void resetV() {
58 | sign = 1;
59 | v = 0;
60 | }
61 |
62 | void move(char ch, int steps, int sign) {
63 |
64 | switch(ch) {
65 |
66 | case 'a':
67 | motor1.step(steps*sign);
68 | break;
69 | case 'b':
70 | motor2.step(steps* sign);
71 | break;
72 | case 'c':
73 | myservo.write(steps);
74 | break;
75 |
76 |
77 | }
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/server.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEowIBAAKCAQEA0izUwz+jc1RQs8XZwfQMYBi6+lMZdJroUrNAjB1OGyin65Pv
3 | CSabviyQBIe34Ln/vFoi71+fRkMa8W0+JIVf7nRuGZELcrz/Q3XBJjP/Ooy6jTw4
4 | /sl6IRqe9oy0AdL7y66lHHWctDHolGwFVussMbkHGt0ao6bK0sjX9BzfkoVYzjRn
5 | 0ltkfiGBlF0eqQCPTYg5Ymjkz2sj3xE21pjzgRGNs5Ruscu9TtnjUqAio+g89BxJ
6 | 7nEVNTKNMCq6Tkph2f6kC/vyyUJaPY3e8tMKSAMJoqIe2ZAKD67OywsQhQ50soGW
7 | S6kLG5blct991ViPhiM8D7+3/yb9gHep+dai2wIDAQABAoIBAA4kiiShUaRfFhci
8 | xyZv/60vvNU/ZkUcb2mxOjSzfCADulj12W3qNSy03vQPFeZ/XaAVCKjG7HbT6So5
9 | yaa3et8W4pnB0t1jrmGhuN+TPCd6dMswND2g3SEBI5U/npVI1zy7gczKdUMC4L2s
10 | DyfsJ0spQjsiibpdbOSGM1Hv53N6elojiI4xSJ8C8hSuwNqVWWgNVmwDYeiGjsxw
11 | B7jkjt2WzgtOfnRJi/dXXxstXJ5UycwWnGq5H+/xNc20htm5fGqSSfuxlsQDWqrz
12 | KrxWPl5mejDbaK/QOnR/zOvuLprWBO+9FdidBFxIqjKpHMW4pspEUBzMDeY6i0g3
13 | FiADJAECgYEA9twiceXauRbQtjoYfYGMas2hDltkTmMD0YUArmpDm5T51SolVvyJ
14 | vHdNVnHM8/rTOEPpIIBphYxzSZV+A9R69YLgZZtuG1XVpxVEZcZAzPk334OTShnG
15 | 5wcn8DlRDpxp+UxHLcEb86Kktky+lzBmHHfCVUlpjS5x/wGSDPNoMQECgYEA2fT6
16 | s0xpDdbL6a0dailMq1OCe2f4+2+C4GZwbAqPo7oSoj09w5tAXPlBo9WJPRMdmiyE
17 | 3eMzaJZz7hoEVft5YpWnrIDVN19VF5DnCfq1JQFsC2S9tCuW2Z2zQM4mh5i6yVD7
18 | CsAF5SAvsGg6tUDnCr7JQM3B3g6P/JgRtiett9sCgYAp3vTItOAAfOoxvnDg+NRE
19 | WVR0BvRgh1Lieti+vK9y+DXX/ioPMw55tRKdEvhcebLR3FLyfFVpnYUAeibBp4yj
20 | j+tX0KFAabKvgF/1k0byfWMIulyFORIPpZsUl+QzwjwHWPTJwfNnw7KEaUf6hO8M
21 | 7RM9PBJ3K+WSB0YqhC6sAQKBgQDE0Zl2QgD380jOanqOfF70s4O3xssq2qbX1wmc
22 | NulBE21yPlVBBzhW/OsOdGzqzxFDQQJ2kI3C22Iy2CGkN2OE59mzR9/Ckf74Oey4
23 | sUHU+fTEUSORyG7/co4FbmOSvROnac5ZBdAM+US3S1gAh2xb4q9AKs3vpTzW/8e2
24 | sxwHUwKBgECcdzllYaYovU2CfnpeoYuXSsUwVWo5vCyoewn0c4slEqor/6QiwsQF
25 | IJCPGpbSJphT/3vCFapQ/SZjNR/UXVUPX6FtSM5zpEB7t65PNeZBXS0wGFwSzJkr
26 | yUtGxWJxDJ0KX9BwbAIJODXAz/EdLjW/Rd3sk/GAsZGyfUOwcAqe
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/Core_XY_control3/Core_XY_control3.ino:
--------------------------------------------------------------------------------
1 |
2 | int v = 0;
3 | int sign = 1;
4 |
5 | #include
6 | #include
7 | // write a,b for steppers
8 | Stepper motor1 = Stepper(200, 4,5, 6,7);
9 | Stepper motor2 = Stepper(200, 10,11,12,13);
10 | Servo myservo;
11 | int rpm = 60;
12 |
13 | void setup() {
14 |
15 | Serial.begin(38400);
16 | Serial.println("Stepper test!");
17 | motor1.setSpeed(rpm); // rpm
18 | motor2.setSpeed(rpm);
19 | myservo.attach(3);
20 | }
21 |
22 | void loop() {
23 | // put your main code here, to run repeatedly:
24 | if ( Serial.available()) {
25 | char ch = Serial.read();
26 |
27 | switch(ch) {
28 | case '0'...'9':
29 | //Pretty goddamn clever right here. Not mine.
30 | v = v * 10 + ch - '0';
31 | break;
32 | case '-':
33 | //Pretty goddamn clever right here. This time ours.
34 | sign *= -1;
35 | //Serial.println("NEGATE!");
36 | break;
37 | case 'a':
38 | move('a', v, sign);
39 | resetV();
40 | break;
41 | case 'b':
42 | move('b', v, sign);
43 | resetV();
44 | break;
45 | case 'c':
46 | move('c', v, sign);
47 | resetV();
48 | break;
49 |
50 | default:
51 | Serial.write("...the fuck is that?");
52 | resetV();
53 | break;
54 | }
55 | }
56 | }
57 |
58 | void resetV() {
59 | sign = 1;
60 | v = 0;
61 | }
62 |
63 | void move(char ch, int steps, int sign) {
64 |
65 | switch(ch) {
66 |
67 | case 'a':
68 | motor1.step(steps*sign);
69 | break;
70 | case 'b':
71 | motor2.step(steps* sign);
72 | break;
73 | case 'c':
74 | myservo.write(steps);
75 | break;
76 |
77 |
78 | }
79 | }
80 |
81 |
--------------------------------------------------------------------------------
/Core_XY_control/Core_XY_control.ino:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | int v = 0;
4 | int sign = 1;
5 |
6 | // Connect a stepper motor with 48 steps per revolution (7.5 degree)
7 | // to motor port #2 (M3 and M4)
8 | AF_Stepper motor1(200, 1);
9 | AF_Stepper motor2(200, 2);
10 |
11 | void setup() {
12 | // put your setup code here, to run once:
13 |
14 | Serial.begin(38400); // set up Serial library at 9600 bps
15 | Serial.println("Stepper test!");
16 |
17 | motor1.setSpeed(200); // 10 rpm
18 | motor2.setSpeed(200);
19 | }
20 |
21 | void loop() {
22 | // put your main code here, to run repeatedly:
23 | if ( Serial.available()) {
24 | char ch = Serial.read();
25 |
26 | switch(ch) {
27 | case '0'...'9':
28 | //Pretty goddamn clever right here. Not mine.
29 | v = v * 10 + ch - '0';
30 | break;
31 | case '-':
32 | //Pretty goddamn clever right here. This time ours.
33 | sign *= -1;
34 | //Serial.println("NEGATE!");
35 | break;
36 | case 'a':
37 | move('a', v, sign);
38 | resetV();
39 | break;
40 | case 'b':
41 | move('b', v, sign);
42 | resetV();
43 | break;
44 | default:
45 | Serial.write("...the fuck is that?");
46 | resetV();
47 | break;
48 | }
49 | }
50 | }
51 |
52 | void resetV() {
53 | sign = 1;
54 | v = 0;
55 | }
56 |
57 | void move(char ch, int steps, int sign) {
58 | int dir;
59 | if(sign <= 0){
60 | //Serial.println("BACKWARD!");
61 | dir = BACKWARD;
62 | }
63 | else{
64 | dir = FORWARD;
65 | }
66 | switch(ch) {
67 |
68 | case 'a':
69 | motor1.step(steps, dir, MICROSTEP);
70 | break;
71 | case 'b':
72 | motor2.step(steps, dir, MICROSTEP);
73 | break;
74 |
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/gcode3.py:
--------------------------------------------------------------------------------
1 | #Now we're going to use control4 firmware
2 |
3 |
4 | from parse import compile
5 | p = compile("G{code} X{x} Y{y}")
6 | import sys
7 | import serial
8 | port = '/dev/ttyUSB0'#'/dev/cu.wch ch341 USB=>RS232 1410'#'tty.wch'#'cu.wch ch341 USB=>RS232 1410'
9 | ser = serial.Serial(port,38400) # open serial port
10 | print(ser.name) # check which port was really used
11 | import numpy as np
12 | import time
13 |
14 |
15 | def raisepen():
16 | ser.write('50c')
17 | #time.sleep(0.1)
18 | def lowerpen():
19 | ser.write('40c')
20 | #time.sleep(0.1)
21 |
22 |
23 |
24 |
25 | def move(steps):
26 | ser.write(str(int(steps[0])) + b'a')
27 | ser.write(str(int(steps[1])) + b'b')
28 | ser.write(b'x')
29 |
30 | def convertToMotor(x):
31 | return np.array([x[0]+x[1],x[0]-x[1]])/np.sqrt(2)
32 | '''
33 | def draw_line(x,xend):
34 | x = convertToMotor(x)
35 | xend = convertToMotor(xend)
36 | deltax = (xend - x)/N
37 | xint = np.rint(x)
38 | for i in range(N):
39 | x = x + deltax
40 | #print x
41 | if np.any(np.rint(x) != xint):
42 | steps = np.rint(x) - xint
43 | move(steps)
44 | xint = np.rint(x)
45 | time.sleep(0.03)
46 | '''
47 |
48 | def move_to(x):
49 | x = convertToMotor(x)
50 | ser.write(str(int(x[0])) + b'a')
51 | ser.write(str(int(x[1])) + b'b')
52 | ser.write(b'x')
53 | print ser.readline()
54 | #time.sleep(.1)
55 |
56 |
57 |
58 | x = np.zeros(2)
59 | N=1000
60 | raisepen()
61 | filename = sys.argv[1]
62 | f= open(filename)
63 |
64 | #We need initial readline for some inexplicable reason. Seriously.
65 | print ser.readline()
66 |
67 | for line in f:
68 | #print line
69 | if line[0:2] == "G1":
70 | command = p.parse(line)
71 | if command != None:
72 | command = command.named
73 | x = np.array([float(command['x']),float(command['y'])])
74 | move_to(x)
75 |
76 | elif line[0:3] == "M05":
77 | raisepen()
78 | elif line[0:3] == "M03":
79 | lowerpen()
80 |
81 | ser.close() # close port
82 |
--------------------------------------------------------------------------------
/drawing.eps:
--------------------------------------------------------------------------------
1 | %!PS-Adobe-3.0 EPSF-3.0
2 | %%Creator: cairo 1.14.0 (http://cairographics.org)
3 | %%CreationDate: Wed Apr 13 22:58:59 2016
4 | %%Pages: 1
5 | %%DocumentData: Clean7Bit
6 | %%LanguageLevel: 2
7 | %%BoundingBox: 0 -1 352 442
8 | %%EndComments
9 | %%BeginProlog
10 | save
11 | 50 dict begin
12 | /q { gsave } bind def
13 | /Q { grestore } bind def
14 | /cm { 6 array astore concat } bind def
15 | /w { setlinewidth } bind def
16 | /J { setlinecap } bind def
17 | /j { setlinejoin } bind def
18 | /M { setmiterlimit } bind def
19 | /d { setdash } bind def
20 | /m { moveto } bind def
21 | /l { lineto } bind def
22 | /c { curveto } bind def
23 | /h { closepath } bind def
24 | /re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
25 | 0 exch rlineto 0 rlineto closepath } bind def
26 | /S { stroke } bind def
27 | /f { fill } bind def
28 | /f* { eofill } bind def
29 | /n { newpath } bind def
30 | /W { clip } bind def
31 | /W* { eoclip } bind def
32 | /BT { } bind def
33 | /ET { } bind def
34 | /pdfmark where { pop globaldict /?pdfmark /exec load put }
35 | { globaldict begin /?pdfmark /pop load def /pdfmark
36 | /cleartomark load def end } ifelse
37 | /BDC { mark 3 1 roll /BDC pdfmark } bind def
38 | /EMC { mark /EMC pdfmark } bind def
39 | /cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
40 | /Tj { show currentpoint cairo_store_point } bind def
41 | /TJ {
42 | {
43 | dup
44 | type /stringtype eq
45 | { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
46 | } forall
47 | currentpoint cairo_store_point
48 | } bind def
49 | /cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
50 | cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
51 | /Tf { pop /cairo_font exch def /cairo_font_matrix where
52 | { pop cairo_selectfont } if } bind def
53 | /Td { matrix translate cairo_font_matrix matrix concatmatrix dup
54 | /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
55 | /cairo_font where { pop cairo_selectfont } if } bind def
56 | /Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
57 | cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
58 | /g { setgray } bind def
59 | /rg { setrgbcolor } bind def
60 | /d1 { setcachedevice } bind def
61 | %%EndProlog
62 | %%BeginSetup
63 | %%EndSetup
64 | %%Page: 1 1
65 | %%BeginPageSetup
66 | %%PageBoundingBox: 0 -1 352 442
67 | %%EndPageSetup
68 | q 0 -1 352 443 rectclip q
69 | 0 g
70 | 0.8 w
71 | 0 J
72 | 0 j
73 | [] 0.0 d
74 | 4 M q 1 0 0 -1 0 441.840698 cm
75 | 142.109 217.625 m 350.109 64.484 l 57.539 0.484 l 0.398 441.625 l h
76 | 142.109 217.625 m S Q
77 | Q Q
78 | showpage
79 | %%Trailer
80 | end restore
81 | %%EOF
82 |
--------------------------------------------------------------------------------
/speech.py:
--------------------------------------------------------------------------------
1 | import speech_recognition as sr
2 |
3 | import contour
4 |
5 | from google import google, images
6 |
7 | options = images.ImageOptions()
8 | options.image_type = images.ImageType.LINE_DRAWING
9 |
10 | from os import listdir
11 |
12 | #options.format =
13 |
14 | import threading
15 |
16 | # this is called from the background thread
17 | def callback(recognizer, audio):
18 | # received audio data, now we'll recognize it using Google Speech Recognition
19 | try:
20 | # for testing purposes, we're just using the default API key
21 | # to use another API key, use `r.recognize_google(audio, key="GOOGLE_SPEECH_RECOGNITION_API_KEY")`
22 | # instead of `r.recognize_google(audio)`
23 | #text = recognizer.recognize_sphinx(audio)
24 | text = recognizer.recognize_google(audio)
25 | print("Google Speech Recognition thinks you said " +text)
26 | if len(text.split())>=2:
27 | request = text.split()[-2:]
28 | else:
29 | request = [text]
30 | results = google.search_images(' '.join(request), options)
31 | print results
32 | '''
33 | for result in results:
34 | if result.link[-4:] == '.svg':
35 | images.download([result], path = "images/"+ '_'.join(request))
36 | print "downloaded image"
37 | break
38 | '''
39 | filepath = "images/"+ '_'.join(request)
40 | images.download([results[0]], path = filepath)
41 | filename = listdir(filepath)[0]
42 | #stop_listening()
43 | contour.show_contour(filepath+'/'+filename)
44 | #t = threading.Thread(target=contour.show_contour, args=(filepath+'/'+filename,))
45 | #t.start()
46 | #r.listen_in_background(m, callback)
47 | except sr.UnknownValueError:
48 | print("Google Speech Recognition could not understand audio")
49 | except sr.RequestError as e:
50 | print("Could not request results from Google Speech Recognition service; {0}".format(e))
51 |
52 | r = sr.Recognizer()
53 | m = sr.Microphone()
54 | with m as source:
55 | r.adjust_for_ambient_noise(source) # we only need to calibrate once, before we start listening
56 |
57 | r.pause_threshold = 0.2
58 | r.non_speaking_duration = r.pause_threshold - 0.1
59 | # start listening in the background (note that we don't have to do this inside a `with` statement)
60 | stop_listening = r.listen_in_background(m, callback)
61 | # `stop_listening` is now a function that, when called, stops background listening
62 |
63 | # do some other computation for 5 seconds, then stop listening and keep doing other computations
64 | import time
65 | for _ in range(50): time.sleep(0.1) # we're still listening even though the main thread is doing other things
66 | #print "didn't find nothing"
67 | #stop_listening() # calling this function requests that the background listener stop listening
68 | while True: time.sleep(0.1)
69 |
--------------------------------------------------------------------------------
/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 | Your page title here :)
9 |
10 |
11 |
12 |
14 |
15 |
16 |
18 |
19 |
20 |
22 |
23 |
24 |
25 |
27 |
28 |
29 |
31 |
32 |
33 |
34 |
35 |
36 |
38 |
39 |
40 |
41 |
DrawBot
42 |
43 |
44 |
45 |
46 |
47 | Take Photo
48 | Draw Photo
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
58 |
59 |
60 |
106 |
107 |
--------------------------------------------------------------------------------
/Core_XY_control4/Core_XY_control4.ino:
--------------------------------------------------------------------------------
1 |
2 | int v = 0;
3 | int sign = 1;
4 |
5 | #include
6 | #include
7 | #include
8 | #define SERVOPIN 3
9 | #define TOUCHDOWN_PIN 9
10 |
11 | // write a,b for steppers
12 | AccelStepper stepper1(AccelStepper::FULL4WIRE, 4, 5, 6, 7);
13 | AccelStepper stepper2(AccelStepper::FULL4WIRE, 10, 11, 12, 13);
14 |
15 | long positions[2]= {0,0};
16 |
17 | // Up to 10 steppers can be handled as a group by MultiStepper
18 | MultiStepper steppers;
19 | Servo myservo;
20 |
21 |
22 | void setup() {
23 |
24 | Serial.begin(38400);
25 | Serial.print("LET'S PRINT BABAAAAH!\n"); //This is important for some reason?
26 | stepper1.setMaxSpeed(100);
27 | stepper2.setMaxSpeed(100);
28 | myservo.attach(SERVOPIN);
29 | // Then give them to MultiStepper to manage
30 | steppers.addStepper(stepper1);
31 | steppers.addStepper(stepper2);
32 | pinMode(TOUCHDOWN_PIN, INPUT_PULLUP);
33 | }
34 |
35 | void loop() {
36 | // put your main code here, to run repeatedly:
37 | if ( Serial.available()) {
38 | char ch = Serial.read();
39 |
40 | switch(ch) {
41 | case '0'...'9':
42 | //Pretty goddamn clever right here. Not mine.
43 | v = v * 10 + ch - '0';
44 | break;
45 | case '-':
46 | //Pretty goddamn clever right here. This time ours.
47 | sign *= -1;
48 | //Serial.println("NEGATE!");
49 | break;
50 | case 'a':
51 | move('a', v, sign);
52 | resetV();
53 | break;
54 | case 'b':
55 | move('b', v, sign);
56 | resetV();
57 | break;
58 | case 'c': // Move
59 | move('c', v, sign);
60 | resetV();
61 | break;
62 | case 's': // Set Speed
63 | stepper1.setMaxSpeed(v);
64 | stepper2.setMaxSpeed(v);
65 | resetV();
66 | break;
67 | case 'r':
68 | stepper1.setCurrentPosition(0);
69 | stepper2.setCurrentPosition(0);
70 | resetV();
71 | break;
72 | case 'h':
73 | touchdown();
74 | resetV();
75 | break;
76 |
77 | case 'x': // Execute action
78 | steppers.moveTo(positions);
79 | steppers.runSpeedToPosition();
80 | Serial.print("Ready\n");
81 | resetV();
82 | break;
83 |
84 | default:
85 | Serial.write("...the fuck is that?");
86 | resetV();
87 | break;
88 | }
89 | }
90 | }
91 |
92 | void resetV() {
93 | sign = 1;
94 | v = 0;
95 | }
96 |
97 |
98 | void touchdown(){
99 | int angle = 90;
100 | myservo.write(angle);
101 | delay(10);
102 | while(digitalRead(TOUCHDOWN_PIN) == 1 && angle > 0){
103 | angle--;
104 | myservo.write(angle);
105 | delay(50);
106 | //Serial.println(digitalRead(TOUCHDOWN_PIN));
107 | }
108 | Serial.println(angle);
109 | myservo.write(90);
110 | }
111 |
112 | void move(char ch, int steps, int sign) {
113 |
114 | switch(ch) {
115 |
116 | case 'a':
117 | positions[0]=long(steps*sign);
118 | break;
119 | case 'b':
120 | positions[1]=long(steps*sign);
121 | break;
122 | case 'c':
123 | myservo.write(steps);
124 | break;
125 |
126 |
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/draw_server.py:
--------------------------------------------------------------------------------
1 | from draw import DrawBot
2 | import sys
3 | from flask import Flask
4 | from flask import request
5 | from flask import render_template
6 | import threading
7 | import time
8 | import json
9 | from photo import PhotoConverter
10 | app = Flask(__name__)
11 | #app.debug = True
12 | bot = DrawBot()
13 |
14 | #!/usr/bin/env python
15 | import signal
16 |
17 | def signal_handler(signal, frame):
18 | print('You pressed Ctrl+C!')
19 | bot.ser.close()
20 | sys.exit(0)
21 | signal.signal(signal.SIGINT, signal_handler)
22 | #bot = False
23 | gcode = ""
24 |
25 |
26 |
27 | @app.route("/gcode")
28 | def hello():
29 | return ''
30 |
31 |
32 | @app.route('/')
33 | def root():
34 | return render_template('index.html')
35 |
36 | @app.route('/contour')
37 | def contour():
38 | return app.send_static_file('contour.jpg')
39 |
40 | @app.route('/frame')
41 | def frame():
42 | return app.send_static_file('frame.jpg')
43 |
44 | @app.route('/admin')
45 | def admin():
46 | return render_template('admin.html')
47 |
48 | '''
49 | @app.route('/js/')
50 | def send_js(path):
51 | return send_from_directory('js', path)
52 | '''
53 |
54 | @app.route("/home")
55 | def home():
56 | bot.homepen()
57 | return json.dumps({'success':True}), 200, {'ContentType':'application/json'}
58 |
59 |
60 |
61 | @app.route("/draw")
62 | def draw():
63 | bot.draw(request.args.get('gcode','').split('\r\n'))
64 | return json.dumps({'success':True}), 200, {'ContentType':'application/json'}
65 |
66 | @app.route("/photo") #This is pretend
67 | def photo():
68 | photo = PhotoConverter()
69 | photo.takePhoto()
70 | gcode = photo.convertContourstoGcode().split('\r\n')
71 | photo.closeCamera()
72 | photo.saveContour('static/contour.jpg')
73 | photo.saveFrame('static/frame.jpg')
74 | photo.sortContours()
75 | photo.scaleContours()
76 | status = bot.draw(gcode)
77 | if status == "busy":
78 | return json.dumps({'success':False}), 200, {'ContentType':'application/json'}
79 | else:
80 | return json.dumps({'success':True}), 200, {'ContentType':'application/json'}
81 |
82 | @app.route("/takephoto")
83 | def takePhoto():
84 | photo = PhotoConverter()
85 | photo.takePhoto()
86 | global gcode
87 | photo.closeCamera()
88 | photo.saveContour('static/contour.jpg')
89 | photo.saveFrame('static/frame.jpg')
90 | photo.sortContours()
91 | photo.scaleContours()
92 | gcode = photo.convertContourstoGcode().split('\r\n')
93 | return json.dumps({'success':True}), 200, {'ContentType':'application/json'}
94 |
95 | @app.route("/drawphoto")
96 | def drawPhoto():
97 | print gcode
98 | bot.draw(gcode)
99 | return json.dumps({'success':True}), 200, {'ContentType':'application/json'}
100 |
101 | '''
102 |
103 | @app.route('/offset/')
104 | def set_offset(offset):
105 | bot.offset = offset
106 | print offset
107 | print type(offset)
108 | return 'New offset'
109 | '''
110 |
111 | @app.route('/move', methods=['GET', 'POST'])
112 | def move():
113 | if request.method == 'POST':
114 | bot.move_to( [int(request.form['x']), int(request.form['y'])] )
115 | return ' x y '
116 |
117 |
118 | @app.route('/reset')
119 | def reset():
120 | bot.reset()
121 | return json.dumps({'success':True}), 200, {'ContentType':'application/json'}
122 |
123 | @app.route('/stop')
124 | def stop():
125 | bot.setStop(True)
126 | return json.dumps({'success':True}), 200, {'ContentType':'application/json'}
127 |
128 |
129 |
130 |
131 | app.run(host="0.0.0.0", port=5000)
132 |
--------------------------------------------------------------------------------
/Core_XY_control5/Core_XY_control5.ino:
--------------------------------------------------------------------------------
1 |
2 | int v = 0;
3 | int sign = 1;
4 |
5 | #include
6 | #include
7 | #include
8 | #define SERVOPIN 3
9 | #define TOUCHDOWN_PIN 9
10 | #define X_LIMIT_PIN 2
11 | #define Y_LIMIT_PIN 8
12 |
13 | // write a,b for steppers
14 | AccelStepper stepper1(AccelStepper::FULL4WIRE, 4, 5, 6, 7);
15 | AccelStepper stepper2(AccelStepper::FULL4WIRE, 10, 11, 12, 13);
16 |
17 | long positions[2]= {0,0};
18 |
19 | // Up to 10 steppers can be handled as a group by MultiStepper
20 | MultiStepper steppers;
21 | Servo myservo;
22 |
23 |
24 | void setup() {
25 |
26 | Serial.begin(38400);
27 | Serial.print("LET'S PRINT BABAAAAH!\n"); //This is important for some reason?
28 | stepper1.setMaxSpeed(100);
29 | stepper2.setMaxSpeed(100);
30 | myservo.attach(SERVOPIN);
31 | // Then give them to MultiStepper to manage
32 | steppers.addStepper(stepper1);
33 | steppers.addStepper(stepper2);
34 | pinMode(TOUCHDOWN_PIN, INPUT_PULLUP);
35 | pinMode(X_LIMIT_PIN, INPUT_PULLUP);
36 | pinMode(Y_LIMIT_PIN, INPUT_PULLUP);
37 | }
38 |
39 | void loop() {
40 | // put your main code here, to run repeatedly:
41 | if ( Serial.available()) {
42 | char ch = Serial.read();
43 |
44 | switch(ch) {
45 | case '0'...'9':
46 | //Pretty goddamn clever right here. Not mine.
47 | v = v * 10 + ch - '0';
48 | break;
49 | case '-':
50 | //Pretty goddamn clever right here. This time ours.
51 | sign *= -1;
52 | //Serial.println("NEGATE!");
53 | break;
54 | case 'a':
55 | move('a', v, sign);
56 | resetV();
57 | break;
58 | case 'b':
59 | move('b', v, sign);
60 | resetV();
61 | break;
62 | case 'c': // Move
63 | move('c', v, sign);
64 | resetV();
65 | break;
66 | case 's': // Set Speed
67 | stepper1.setMaxSpeed(v);
68 | stepper2.setMaxSpeed(v);
69 | resetV();
70 | break;
71 | case 'r':
72 | resetCoordinates();
73 | resetV();
74 | break;
75 | case 'h':
76 | touchdown();
77 | resetV();
78 | break;
79 | case 'z':
80 | homeCoords();
81 | resetV();
82 | break;
83 | case 'x': // Execute action
84 | steppers.moveTo(positions);
85 | steppers.runSpeedToPosition();
86 | Serial.print("Ready\n");
87 | resetV();
88 | break;
89 |
90 | default:
91 | Serial.write("...the fuck is that?");
92 | resetV();
93 | break;
94 | }
95 | }
96 | }
97 |
98 | void resetV() {
99 | sign = 1;
100 | v = 0;
101 | }
102 |
103 | void homeCoords() {
104 | Serial.println("homing");
105 | bool x_home = false;
106 | bool y_home = false;
107 | y_home = (digitalRead(Y_LIMIT_PIN) == 0);
108 | while (!y_home){
109 | positions[0] -= 1;
110 | positions[1] += 1;
111 | steppers.moveTo(positions);
112 | steppers.runSpeedToPosition();
113 | y_home = (digitalRead(Y_LIMIT_PIN) == 0);
114 | }
115 |
116 |
117 | x_home = (digitalRead(X_LIMIT_PIN) == 0);
118 | while (!x_home){
119 | positions[0] -= 1;
120 | positions[1] -= 1;
121 | steppers.moveTo(positions);
122 | steppers.runSpeedToPosition();
123 | x_home = (digitalRead(X_LIMIT_PIN) == 0);
124 | }
125 |
126 | resetCoordinates();
127 | }
128 |
129 | void resetCoordinates() {
130 | stepper1.setCurrentPosition(0);
131 | stepper2.setCurrentPosition(0);
132 | }
133 |
134 | void touchdown(){
135 | int angle = 90;
136 | myservo.write(angle);
137 | delay(10);
138 | while(digitalRead(TOUCHDOWN_PIN) == 1 && angle > 0){
139 | angle--;
140 | myservo.write(angle);
141 | delay(50);
142 | //Serial.println(digitalRead(TOUCHDOWN_PIN));
143 | }
144 | Serial.println(angle);
145 | myservo.write(90);
146 | }
147 |
148 | void move(char ch, int steps, int sign) {
149 |
150 | switch(ch) {
151 |
152 | case 'a':
153 | positions[0]=long(steps*sign);
154 | break;
155 | case 'b':
156 | positions[1]=long(steps*sign);
157 | break;
158 | case 'c':
159 | myservo.write(steps);
160 | break;
161 |
162 |
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/Core_XY_control6/Core_XY_control6.ino:
--------------------------------------------------------------------------------
1 |
2 | int v = 0;
3 | int sign = 1;
4 |
5 | #include
6 | #include
7 | #include
8 | #define SERVOPIN 9
9 | #define TOUCHDOWN_PIN 8
10 | #define X_LIMIT_PIN 2
11 | #define Y_LIMIT_PIN 3
12 |
13 | // write a,b for steppers
14 | AccelStepper stepper1(AccelStepper::FULL4WIRE, 4, 5, 6, 7);
15 | AccelStepper stepper2(AccelStepper::FULL4WIRE, A5, A4, A3, A2);
16 |
17 | long positions[2]= {0,0};
18 |
19 | // Up to 10 steppers can be handled as a group by MultiStepper
20 | MultiStepper steppers;
21 | Servo myservo;
22 |
23 |
24 | void setup() {
25 |
26 | Serial.begin(38400);
27 | Serial.print("LET'S PRINT BABAAAAH!\n"); //This is important for some reason?
28 | stepper1.setMaxSpeed(100);
29 | stepper2.setMaxSpeed(100);
30 | myservo.attach(SERVOPIN);
31 | myservo.write(150);
32 | // Then give them to MultiStepper to manage
33 | steppers.addStepper(stepper1);
34 | steppers.addStepper(stepper2);
35 | pinMode(TOUCHDOWN_PIN, INPUT_PULLUP);
36 | pinMode(X_LIMIT_PIN, INPUT_PULLUP);
37 | pinMode(Y_LIMIT_PIN, INPUT_PULLUP);
38 | }
39 |
40 | void loop() {
41 | // put your main code here, to run repeatedly:
42 | if ( Serial.available()) {
43 | char ch = Serial.read();
44 |
45 | switch(ch) {
46 | case '0'...'9':
47 | //Pretty goddamn clever right here. Not mine.
48 | v = v * 10 + ch - '0';
49 | break;
50 | case '-':
51 | //Pretty goddamn clever right here. This time ours.
52 | sign *= -1;
53 | //Serial.println("NEGATE!");
54 | break;
55 | case 'a':
56 | move('a', v, sign);
57 | resetV();
58 | break;
59 | case 'b':
60 | move('b', v, sign);
61 | resetV();
62 | break;
63 | case 'c': // Move
64 | move('c', v, sign);
65 | resetV();
66 | break;
67 | case 's': // Set Speed
68 | stepper1.setMaxSpeed(v);
69 | stepper2.setMaxSpeed(v);
70 | resetV();
71 | break;
72 | case 'r':
73 | resetCoordinates();
74 | resetV();
75 | break;
76 | case 'h':
77 | touchdown();
78 | resetV();
79 | break;
80 | case 'z':
81 | homeCoords();
82 | resetV();
83 | break;
84 | case 'x': // Execute action
85 | steppers.moveTo(positions);
86 | steppers.runSpeedToPosition();
87 | Serial.print("Ready\n");
88 | resetV();
89 | break;
90 |
91 | default:
92 | Serial.write("...the fuck is that?");
93 | resetV();
94 | break;
95 | }
96 | }
97 | }
98 |
99 | void resetV() {
100 | sign = 1;
101 | v = 0;
102 | }
103 |
104 | void homeCoords() {
105 | Serial.println("homing");
106 | bool x_home = false;
107 | bool y_home = false;
108 | y_home = (digitalRead(Y_LIMIT_PIN) == 0);
109 | while (!y_home){
110 | positions[0] -= 1;
111 | positions[1] += 1;
112 | steppers.moveTo(positions);
113 | steppers.runSpeedToPosition();
114 | y_home = (digitalRead(Y_LIMIT_PIN) == 0);
115 | }
116 |
117 |
118 | x_home = (digitalRead(X_LIMIT_PIN) == 0);
119 | while (!x_home){
120 | positions[0] -= 1;
121 | positions[1] -= 1;
122 | steppers.moveTo(positions);
123 | steppers.runSpeedToPosition();
124 | x_home = (digitalRead(X_LIMIT_PIN) == 0);
125 | }
126 |
127 | resetCoordinates();
128 | Serial.println("homed");
129 | }
130 |
131 | void resetCoordinates() {
132 | stepper1.setCurrentPosition(0);
133 | stepper2.setCurrentPosition(0);
134 | }
135 |
136 | void touchdown(){
137 | int angle = 150;
138 | myservo.write(angle);
139 | delay(10);
140 | while(digitalRead(TOUCHDOWN_PIN) == 1 && angle > 0){
141 | angle--;
142 | myservo.write(angle);
143 | delay(50);
144 | //Serial.println(digitalRead(TOUCHDOWN_PIN));
145 | }
146 | Serial.println(angle);
147 | myservo.write(90);
148 | }
149 |
150 | void move(char ch, int steps, int sign) {
151 |
152 | switch(ch) {
153 |
154 | case 'a':
155 | positions[0]=long(steps*sign);
156 | break;
157 | case 'b':
158 | positions[1]=long(steps*sign);
159 | break;
160 | case 'c':
161 | myservo.write(steps);
162 | break;
163 |
164 |
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/templates/admin.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 | Your page title here :)
9 |
10 |
11 |
12 |
14 |
15 |
16 |
18 |
19 |
20 |
22 |
23 |
24 |
25 |
27 |
28 |
29 |
31 |
32 |
33 |
34 |
35 |
36 |
38 |
39 |
40 |
41 |
DrawBot Control Page
42 |
43 |
44 |
45 |
46 | Home
47 | Reset
48 | Stop
49 |
50 |
51 |
52 | Draw
53 |
54 |
55 |
Take Photo
56 |
57 |
Draw Photo
58 |
59 |
60 |
61 |
62 |
64 |
65 |
66 |
156 |
157 |
--------------------------------------------------------------------------------
/draw/DrawBot.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import time
3 | from parse import compile
4 | import sys
5 | import serial
6 | import serial.tools.list_ports
7 | import threading
8 |
9 | #Full Range of x is 1600, y is 1200
10 |
11 | class DrawBot:
12 | def __init__(self, port=None, baud=38400):
13 | if port:
14 | self.port = port
15 | else:
16 | self.port = serial.tools.list_ports.comports()[-1][0]
17 | #self.port = "/dev/ttyUSB0"
18 | self.ser = serial.Serial(self.port, baud,timeout=30.) # open serial port
19 | self.ser.flushInput()
20 | self.p = compile("G{code} X{x} Y{y}")
21 | print self.ser.readline()
22 | self.busy = False
23 | #self.homepen()
24 | self.ser.write(str(150) + 'c')
25 | self.stop = False
26 | self.homexy()
27 | self.ser.flushInput()
28 |
29 | self.w = 1600
30 | self.h= 1200
31 |
32 | #Checks if busy, spins off a thread if not that will set busy to false when done
33 | def busyCheck(func):
34 | def func_wrapper(self,*args, **kwargs):
35 | if not self.busy:
36 | self.busy = True
37 | def func_wrapper2(*args, **kwargs):
38 | func(self,*args, **kwargs)
39 | self.busy = False
40 | threading.Thread(target=func_wrapper2, args=args, kwargs=kwargs).start()
41 | return "printing"
42 | else:
43 | print "busy"
44 | return "busy"
45 | return func_wrapper
46 |
47 | def drawFromFile(self, file_name):
48 | file = open(file_name)
49 | self.draw(file)
50 | file.close()
51 |
52 | @busyCheck
53 | def draw(self,gcode):
54 | self.ser.flushInput()
55 | x = np.zeros(2)
56 | #self.raisepen()
57 | self.ser.write(str(150) + 'c')
58 | self.goToPad()
59 |
60 | self.ser.flushInput()
61 |
62 |
63 | #self.ser.timeout=0.5
64 | #print self.ser.readline()
65 | #self.ser.timeout =0.
66 | self.ser.flushInput()
67 |
68 | for line in gcode:
69 | print line
70 | if line[0:2] == "G1":
71 | command = self.p.parse(line)
72 | print command
73 | if command != None:
74 | command = command.named
75 | x = np.array([float(command['x']),float(command['y'])])
76 | self.move_to(x)
77 |
78 | elif line[0:3] == "M05":
79 | self.raisepen()
80 | elif line[0:3] == "M03":
81 | self.lowerpen()
82 | if self.stop:
83 | print "Bird Stopped"
84 | self.stop = False
85 | self.ser.flushInput()
86 | self.homexy()
87 | return "Bird. You Stopped"
88 | self.homexy()
89 | return "bird"
90 | def __del__(self):
91 | self.ser.close()
92 | def raisepen(self):
93 | self.ser.write(str(self.penAngle) + 'c')
94 | print str(self.penAngle)
95 | def lowerpen(self):
96 | self.ser.write(str(self.penAngle - 10) + 'c')
97 | print str(self.penAngle - 10)
98 | def homepen(self):
99 | self.ser.flushInput()
100 | self.ser.write('h');
101 | self.penAngle = int(self.ser.readline())
102 | def setStop(self, val):
103 | self.stop = val
104 | def reset(self):
105 | self.ser.flushInput()
106 | self.ser.write('r');
107 | def homexy(self):
108 | self.ser.flushInput()
109 | self.ser.write('z');
110 | print self.ser.readline()
111 | print self.ser.readline()
112 | def goToPad(self):
113 | self.move_to([0,1100])
114 | self.move_to([815,1100])
115 | self.move_to([815,665])
116 | self.ser.flushInput()
117 | self.homepen()
118 | def move(self,steps): #DO NOT USE
119 | self.ser.write(str(int(steps[0])) + b'a')
120 | self.ser.write(str(int(steps[1])) + b'b')
121 | self.ser.write(b'x')
122 | def convertToMotor(self,x):
123 | return np.array([x[0]+x[1],x[0]-x[1]])/np.sqrt(2)
124 | def move_to(self,x):
125 | self.ser.flushInput()
126 | x = self.convertToMotor(x)
127 | self.ser.write(str(int(x[0])) + b'a')
128 | self.ser.write(str(int(x[1])) + b'b')
129 | self.ser.write(b'x')
130 | print self.ser.readline()
131 | #while self.ser.readline() != "Ready\n":
132 | #self.ser.write(str(int(x[0])) + b'a')
133 | #self.ser.write(str(int(x[1])) + b'b')
134 | #self.ser.write(b'x')
135 | # time.sleep(0.05)
136 |
--------------------------------------------------------------------------------
/photo/PhotoConverter.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import numpy as np
3 |
4 |
5 | class PhotoConverter:
6 |
7 | def __init__(self):
8 | self.fraction = 16 # 1/fraction largest area contours are drawn
9 | self.openCamera()
10 | self.robotFraction = 0.25 #Full Range of x is 1600, y is 1200
11 |
12 |
13 | def openCamera(self):
14 | self.cap = cv2.VideoCapture(0)
15 | _, frame = self.cap.read()
16 | def closeCamera(self):
17 | self.cap.release()
18 |
19 | def setDrawFraction(self, newfrac):
20 | self.robotFraction = newfrac
21 |
22 | def squareFrame(self,frame):
23 | print frame.shape
24 | if frame.shape[0] < frame.shape[1]:
25 | offset = int((frame.shape[1]-frame.shape[0])/2)
26 |
27 | return frame[:,offset:frame.shape[1]-offset,:]
28 | else:
29 | offset = int((frame.shape[0]-frame.shape[1])/2)
30 | return frame[offset:frame.shape[0]-offset,:,:]
31 |
32 |
33 | def takePhoto(self):
34 | #Take photo, convert to gray, downsample, threshold, find contours
35 | for i in range(10):
36 | _, frame = self.cap.read()
37 | if frame != None:
38 | break
39 |
40 |
41 | self.frame = self.squareFrame(frame)
42 | #self.frame = frame
43 | gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)
44 | #gray = self.findFace(gray)
45 | gray = cv2.pyrDown(gray)
46 |
47 | self.h = gray.shape[0]
48 | self.w = gray.shape[1]
49 |
50 | self.thres = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,15,2)
51 | self.contours,self.hierarchy = cv2.findContours(self.thres,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
52 | #Order contours by area
53 | area = np.asarray(map(cv2.contourArea, self.contours))
54 | self.indexorder = np.argsort(area)[::-1]
55 | self.contours = np.array(self.contours)
56 | self.contours = self.contours[self.indexorder[: int(len(self.contours)/self.fraction)]]
57 |
58 |
59 | def drawContours(self):
60 | newempty = np.ones((self.h,self.w,3), dtype=np.uint8)
61 | for i in range(len(self.contours)):
62 | cv2.drawContours(newempty, self.contours, i, (0,0,255), 1)
63 | #Simplified triangles
64 | cv2.imshow('Contours',newempty)
65 | k = cv2.waitKey(0)
66 | cv2.destroyAllWindows()
67 |
68 | def saveContour(self, filename):
69 | newempty = np.ones((self.h,self.w,3), dtype=np.uint8)
70 | for i in range(len(self.contours)):
71 | cv2.drawContours(newempty, self.contours, i, (0,0,255), 1)
72 | cv2.imwrite(filename, newempty)
73 |
74 | '''
75 | def scaleContours(self, w, h):
76 | xmax = 0
77 | ymax = 0
78 | w = float(w)
79 | h = float(h)
80 |
81 | scale = self.robotFraction * min(w / self.w, h / self.h)
82 | offsetx = (w - scale*self.w)/2
83 | offsety = (h - scale*self.h)/2
84 |
85 | for cnt in self.contours:
86 | for point in cnt:
87 | point = point[0]
88 | point[0] = int(point[0] * scale + offsetx)
89 | point[1] = int(point[1] * scale + offsety)
90 | self.w = w #int(self.w * scale)
91 | self.h = h #int(self.h * scale)
92 | print self.contours
93 | '''
94 | #x = 630
95 | #y = 480
96 | #w = 370
97 | #h = 370
98 | def scaleContours(self, x=630, y=480, w=370, h=370):
99 |
100 |
101 | xmax = 0
102 | ymax = 0
103 | w = float(w)
104 | h = float(h)
105 |
106 | scale = min(w / self.w, h / self.h)
107 | offsetx = x#(w - scale*self.w)/2
108 | offsety = y#(h - scale*self.h)/2
109 |
110 | for cnt in self.contours:
111 | for point in cnt:
112 | point = point[0]
113 | point[0] = int(point[0] * scale + offsetx)
114 | point[1] = int((self.h-point[1]) * scale + offsety)
115 | self.w = w #int(self.w * scale)
116 | self.h = h #int(self.h * scale)
117 | #print self.contours
118 |
119 | def sortContours(self):
120 | temp = []
121 | unused = np.copy(self.contours)
122 | temp.append(self.contours[0])
123 |
124 | def rotateList(l,n): #cyclically roatets the list l so that the n index position is now at index 0
125 | return np.concatenate((l[n:],l[:n]))
126 |
127 | for i in range(1,len(self.contours)):
128 | closestdist = 10000000000
129 | closestcontourindex = 0
130 | lastpoint = temp[i-1][0] #where the pen is after drawing i-1 contour
131 |
132 | dists = map(lambda cnt: (cnt[:,0,0]-lastpoint[0][0])**2 + (cnt[:,0,1]-lastpoint[0][1])**2, unused)
133 | minofcnt = np.asarray(map(lambda cnt: np.amin(cnt), dists))
134 | closestcontourindex = np.argmin(minofcnt)
135 | firstpointindex = np.argmin(dists[closestcontourindex])
136 |
137 | closestcnt = unused[closestcontourindex]
138 | unused = np.delete(unused, closestcontourindex , axis=0)
139 | temp.append(rotateList(closestcnt, firstpointindex))
140 |
141 |
142 | self.contours = np.asarray(temp)
143 |
144 |
145 |
146 |
147 |
148 | def saveFrame(self,filename):
149 | cv2.imwrite(filename, self.frame)
150 |
151 |
152 | def convertContourstoGcode(self):
153 | raisepen = "M05\r\n"
154 | lowerpen = "M03\r\n"
155 | def move(x,y):
156 | return "G1 X" + str(x) + " Y" + str(y) + "\r\n"
157 |
158 | gcode = ""
159 | #for cnt in self.contours[self.indexorder]: #format of contour is [ [[x y]], [[x,y]] ] Why they put double array in there god knows
160 | #for i in range(int(len(self.indexorder)/self.fraction)):
161 | for i in range(len(self.contours)):
162 | #cnt = self.contours[self.indexorder[i]]
163 | cnt = self.contours[i]
164 | gcode += raisepen # Also dule note that i needed to convert contours to numpy array to index like this
165 | gcode += move(cnt[0][0][0],cnt[0][0][1])
166 | gcode += lowerpen
167 | for point in cnt:
168 | point = point[0]
169 | gcode += move(point[0],point[1])
170 | gcode += raisepen
171 | gcode += move(0,0)
172 | return gcode
173 |
174 | def simplifyContours(self,eps=0.001):
175 | for i in range(len(self.contours)):
176 | cnt = self.contours[i]
177 | epsilon = eps*cv2.arcLength(cnt,True)
178 | self.contours[i] = cv2.approxPolyDP(cnt,epsilon,True)
179 |
180 | def findFace(self,gray):
181 | face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
182 | faces = face_cascade.detectMultiScale(gray, 1.3, 5)
183 | if faces: #Perhaps a better approach would be to blur using faces as crispness points? Might want mutiple faces
184 | faces = sorted(faces, key = lambda (x,y,w,h): w * h, reverse=True) #Also sort for largest faces rather than arbitrary face
185 | (x,y,w,h) = faces[0]
186 | left = max(x-w/2,0)
187 | right = min(x+3*w/2,gray.shape[1])
188 | down = min(y+3*h/2,gray.shape[0])
189 | up = max(y-h/2,0)
190 | return gray[up:down, left:right] #Yes. The coordinate system of computers is goofy.
191 | else:
192 | return gray
193 |
--------------------------------------------------------------------------------
/static/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */
2 |
3 | /**
4 | * 1. Set default font family to sans-serif.
5 | * 2. Prevent iOS text size adjust after orientation change, without disabling
6 | * user zoom.
7 | */
8 |
9 | html {
10 | font-family: sans-serif; /* 1 */
11 | -ms-text-size-adjust: 100%; /* 2 */
12 | -webkit-text-size-adjust: 100%; /* 2 */
13 | }
14 |
15 | /**
16 | * Remove default margin.
17 | */
18 |
19 | body {
20 | margin: 0;
21 | }
22 |
23 | /* HTML5 display definitions
24 | ========================================================================== */
25 |
26 | /**
27 | * Correct `block` display not defined for any HTML5 element in IE 8/9.
28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11
29 | * and Firefox.
30 | * Correct `block` display not defined for `main` in IE 11.
31 | */
32 |
33 | article,
34 | aside,
35 | details,
36 | figcaption,
37 | figure,
38 | footer,
39 | header,
40 | hgroup,
41 | main,
42 | menu,
43 | nav,
44 | section,
45 | summary {
46 | display: block;
47 | }
48 |
49 | /**
50 | * 1. Correct `inline-block` display not defined in IE 8/9.
51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
52 | */
53 |
54 | audio,
55 | canvas,
56 | progress,
57 | video {
58 | display: inline-block; /* 1 */
59 | vertical-align: baseline; /* 2 */
60 | }
61 |
62 | /**
63 | * Prevent modern browsers from displaying `audio` without controls.
64 | * Remove excess height in iOS 5 devices.
65 | */
66 |
67 | audio:not([controls]) {
68 | display: none;
69 | height: 0;
70 | }
71 |
72 | /**
73 | * Address `[hidden]` styling not present in IE 8/9/10.
74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
75 | */
76 |
77 | [hidden],
78 | template {
79 | display: none;
80 | }
81 |
82 | /* Links
83 | ========================================================================== */
84 |
85 | /**
86 | * Remove the gray background color from active links in IE 10.
87 | */
88 |
89 | a {
90 | background-color: transparent;
91 | }
92 |
93 | /**
94 | * Improve readability when focused and also mouse hovered in all browsers.
95 | */
96 |
97 | a:active,
98 | a:hover {
99 | outline: 0;
100 | }
101 |
102 | /* Text-level semantics
103 | ========================================================================== */
104 |
105 | /**
106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
107 | */
108 |
109 | abbr[title] {
110 | border-bottom: 1px dotted;
111 | }
112 |
113 | /**
114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
115 | */
116 |
117 | b,
118 | strong {
119 | font-weight: bold;
120 | }
121 |
122 | /**
123 | * Address styling not present in Safari and Chrome.
124 | */
125 |
126 | dfn {
127 | font-style: italic;
128 | }
129 |
130 | /**
131 | * Address variable `h1` font-size and margin within `section` and `article`
132 | * contexts in Firefox 4+, Safari, and Chrome.
133 | */
134 |
135 | h1 {
136 | font-size: 2em;
137 | margin: 0.67em 0;
138 | }
139 |
140 | /**
141 | * Address styling not present in IE 8/9.
142 | */
143 |
144 | mark {
145 | background: #ff0;
146 | color: #000;
147 | }
148 |
149 | /**
150 | * Address inconsistent and variable font size in all browsers.
151 | */
152 |
153 | small {
154 | font-size: 80%;
155 | }
156 |
157 | /**
158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers.
159 | */
160 |
161 | sub,
162 | sup {
163 | font-size: 75%;
164 | line-height: 0;
165 | position: relative;
166 | vertical-align: baseline;
167 | }
168 |
169 | sup {
170 | top: -0.5em;
171 | }
172 |
173 | sub {
174 | bottom: -0.25em;
175 | }
176 |
177 | /* Embedded content
178 | ========================================================================== */
179 |
180 | /**
181 | * Remove border when inside `a` element in IE 8/9/10.
182 | */
183 |
184 | img {
185 | border: 0;
186 | }
187 |
188 | /**
189 | * Correct overflow not hidden in IE 9/10/11.
190 | */
191 |
192 | svg:not(:root) {
193 | overflow: hidden;
194 | }
195 |
196 | /* Grouping content
197 | ========================================================================== */
198 |
199 | /**
200 | * Address margin not present in IE 8/9 and Safari.
201 | */
202 |
203 | figure {
204 | margin: 1em 40px;
205 | }
206 |
207 | /**
208 | * Address differences between Firefox and other browsers.
209 | */
210 |
211 | hr {
212 | -moz-box-sizing: content-box;
213 | box-sizing: content-box;
214 | height: 0;
215 | }
216 |
217 | /**
218 | * Contain overflow in all browsers.
219 | */
220 |
221 | pre {
222 | overflow: auto;
223 | }
224 |
225 | /**
226 | * Address odd `em`-unit font size rendering in all browsers.
227 | */
228 |
229 | code,
230 | kbd,
231 | pre,
232 | samp {
233 | font-family: monospace, monospace;
234 | font-size: 1em;
235 | }
236 |
237 | /* Forms
238 | ========================================================================== */
239 |
240 | /**
241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited
242 | * styling of `select`, unless a `border` property is set.
243 | */
244 |
245 | /**
246 | * 1. Correct color not being inherited.
247 | * Known issue: affects color of disabled elements.
248 | * 2. Correct font properties not being inherited.
249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
250 | */
251 |
252 | button,
253 | input,
254 | optgroup,
255 | select,
256 | textarea {
257 | color: inherit; /* 1 */
258 | font: inherit; /* 2 */
259 | margin: 0; /* 3 */
260 | }
261 |
262 | /**
263 | * Address `overflow` set to `hidden` in IE 8/9/10/11.
264 | */
265 |
266 | button {
267 | overflow: visible;
268 | }
269 |
270 | /**
271 | * Address inconsistent `text-transform` inheritance for `button` and `select`.
272 | * All other form control elements do not inherit `text-transform` values.
273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
274 | * Correct `select` style inheritance in Firefox.
275 | */
276 |
277 | button,
278 | select {
279 | text-transform: none;
280 | }
281 |
282 | /**
283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
284 | * and `video` controls.
285 | * 2. Correct inability to style clickable `input` types in iOS.
286 | * 3. Improve usability and consistency of cursor style between image-type
287 | * `input` and others.
288 | */
289 |
290 | button,
291 | html input[type="button"], /* 1 */
292 | input[type="reset"],
293 | input[type="submit"] {
294 | -webkit-appearance: button; /* 2 */
295 | cursor: pointer; /* 3 */
296 | }
297 |
298 | /**
299 | * Re-set default cursor for disabled elements.
300 | */
301 |
302 | button[disabled],
303 | html input[disabled] {
304 | cursor: default;
305 | }
306 |
307 | /**
308 | * Remove inner padding and border in Firefox 4+.
309 | */
310 |
311 | button::-moz-focus-inner,
312 | input::-moz-focus-inner {
313 | border: 0;
314 | padding: 0;
315 | }
316 |
317 | /**
318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in
319 | * the UA stylesheet.
320 | */
321 |
322 | input {
323 | line-height: normal;
324 | }
325 |
326 | /**
327 | * It's recommended that you don't attempt to style these elements.
328 | * Firefox's implementation doesn't respect box-sizing, padding, or width.
329 | *
330 | * 1. Address box sizing set to `content-box` in IE 8/9/10.
331 | * 2. Remove excess padding in IE 8/9/10.
332 | */
333 |
334 | input[type="checkbox"],
335 | input[type="radio"] {
336 | box-sizing: border-box; /* 1 */
337 | padding: 0; /* 2 */
338 | }
339 |
340 | /**
341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain
342 | * `font-size` values of the `input`, it causes the cursor style of the
343 | * decrement button to change from `default` to `text`.
344 | */
345 |
346 | input[type="number"]::-webkit-inner-spin-button,
347 | input[type="number"]::-webkit-outer-spin-button {
348 | height: auto;
349 | }
350 |
351 | /**
352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
354 | * (include `-moz` to future-proof).
355 | */
356 |
357 | input[type="search"] {
358 | -webkit-appearance: textfield; /* 1 */
359 | -moz-box-sizing: content-box;
360 | -webkit-box-sizing: content-box; /* 2 */
361 | box-sizing: content-box;
362 | }
363 |
364 | /**
365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X.
366 | * Safari (but not Chrome) clips the cancel button when the search input has
367 | * padding (and `textfield` appearance).
368 | */
369 |
370 | input[type="search"]::-webkit-search-cancel-button,
371 | input[type="search"]::-webkit-search-decoration {
372 | -webkit-appearance: none;
373 | }
374 |
375 | /**
376 | * Define consistent border, margin, and padding.
377 | */
378 |
379 | fieldset {
380 | border: 1px solid #c0c0c0;
381 | margin: 0 2px;
382 | padding: 0.35em 0.625em 0.75em;
383 | }
384 |
385 | /**
386 | * 1. Correct `color` not being inherited in IE 8/9/10/11.
387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets.
388 | */
389 |
390 | legend {
391 | border: 0; /* 1 */
392 | padding: 0; /* 2 */
393 | }
394 |
395 | /**
396 | * Remove default vertical scrollbar in IE 8/9/10/11.
397 | */
398 |
399 | textarea {
400 | overflow: auto;
401 | }
402 |
403 | /**
404 | * Don't inherit the `font-weight` (applied by a rule above).
405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
406 | */
407 |
408 | optgroup {
409 | font-weight: bold;
410 | }
411 |
412 | /* Tables
413 | ========================================================================== */
414 |
415 | /**
416 | * Remove most spacing between table cells.
417 | */
418 |
419 | table {
420 | border-collapse: collapse;
421 | border-spacing: 0;
422 | }
423 |
424 | td,
425 | th {
426 | padding: 0;
427 | }
--------------------------------------------------------------------------------
/templates/static/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */
2 |
3 | /**
4 | * 1. Set default font family to sans-serif.
5 | * 2. Prevent iOS text size adjust after orientation change, without disabling
6 | * user zoom.
7 | */
8 |
9 | html {
10 | font-family: sans-serif; /* 1 */
11 | -ms-text-size-adjust: 100%; /* 2 */
12 | -webkit-text-size-adjust: 100%; /* 2 */
13 | }
14 |
15 | /**
16 | * Remove default margin.
17 | */
18 |
19 | body {
20 | margin: 0;
21 | }
22 |
23 | /* HTML5 display definitions
24 | ========================================================================== */
25 |
26 | /**
27 | * Correct `block` display not defined for any HTML5 element in IE 8/9.
28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11
29 | * and Firefox.
30 | * Correct `block` display not defined for `main` in IE 11.
31 | */
32 |
33 | article,
34 | aside,
35 | details,
36 | figcaption,
37 | figure,
38 | footer,
39 | header,
40 | hgroup,
41 | main,
42 | menu,
43 | nav,
44 | section,
45 | summary {
46 | display: block;
47 | }
48 |
49 | /**
50 | * 1. Correct `inline-block` display not defined in IE 8/9.
51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
52 | */
53 |
54 | audio,
55 | canvas,
56 | progress,
57 | video {
58 | display: inline-block; /* 1 */
59 | vertical-align: baseline; /* 2 */
60 | }
61 |
62 | /**
63 | * Prevent modern browsers from displaying `audio` without controls.
64 | * Remove excess height in iOS 5 devices.
65 | */
66 |
67 | audio:not([controls]) {
68 | display: none;
69 | height: 0;
70 | }
71 |
72 | /**
73 | * Address `[hidden]` styling not present in IE 8/9/10.
74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
75 | */
76 |
77 | [hidden],
78 | template {
79 | display: none;
80 | }
81 |
82 | /* Links
83 | ========================================================================== */
84 |
85 | /**
86 | * Remove the gray background color from active links in IE 10.
87 | */
88 |
89 | a {
90 | background-color: transparent;
91 | }
92 |
93 | /**
94 | * Improve readability when focused and also mouse hovered in all browsers.
95 | */
96 |
97 | a:active,
98 | a:hover {
99 | outline: 0;
100 | }
101 |
102 | /* Text-level semantics
103 | ========================================================================== */
104 |
105 | /**
106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
107 | */
108 |
109 | abbr[title] {
110 | border-bottom: 1px dotted;
111 | }
112 |
113 | /**
114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
115 | */
116 |
117 | b,
118 | strong {
119 | font-weight: bold;
120 | }
121 |
122 | /**
123 | * Address styling not present in Safari and Chrome.
124 | */
125 |
126 | dfn {
127 | font-style: italic;
128 | }
129 |
130 | /**
131 | * Address variable `h1` font-size and margin within `section` and `article`
132 | * contexts in Firefox 4+, Safari, and Chrome.
133 | */
134 |
135 | h1 {
136 | font-size: 2em;
137 | margin: 0.67em 0;
138 | }
139 |
140 | /**
141 | * Address styling not present in IE 8/9.
142 | */
143 |
144 | mark {
145 | background: #ff0;
146 | color: #000;
147 | }
148 |
149 | /**
150 | * Address inconsistent and variable font size in all browsers.
151 | */
152 |
153 | small {
154 | font-size: 80%;
155 | }
156 |
157 | /**
158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers.
159 | */
160 |
161 | sub,
162 | sup {
163 | font-size: 75%;
164 | line-height: 0;
165 | position: relative;
166 | vertical-align: baseline;
167 | }
168 |
169 | sup {
170 | top: -0.5em;
171 | }
172 |
173 | sub {
174 | bottom: -0.25em;
175 | }
176 |
177 | /* Embedded content
178 | ========================================================================== */
179 |
180 | /**
181 | * Remove border when inside `a` element in IE 8/9/10.
182 | */
183 |
184 | img {
185 | border: 0;
186 | }
187 |
188 | /**
189 | * Correct overflow not hidden in IE 9/10/11.
190 | */
191 |
192 | svg:not(:root) {
193 | overflow: hidden;
194 | }
195 |
196 | /* Grouping content
197 | ========================================================================== */
198 |
199 | /**
200 | * Address margin not present in IE 8/9 and Safari.
201 | */
202 |
203 | figure {
204 | margin: 1em 40px;
205 | }
206 |
207 | /**
208 | * Address differences between Firefox and other browsers.
209 | */
210 |
211 | hr {
212 | -moz-box-sizing: content-box;
213 | box-sizing: content-box;
214 | height: 0;
215 | }
216 |
217 | /**
218 | * Contain overflow in all browsers.
219 | */
220 |
221 | pre {
222 | overflow: auto;
223 | }
224 |
225 | /**
226 | * Address odd `em`-unit font size rendering in all browsers.
227 | */
228 |
229 | code,
230 | kbd,
231 | pre,
232 | samp {
233 | font-family: monospace, monospace;
234 | font-size: 1em;
235 | }
236 |
237 | /* Forms
238 | ========================================================================== */
239 |
240 | /**
241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited
242 | * styling of `select`, unless a `border` property is set.
243 | */
244 |
245 | /**
246 | * 1. Correct color not being inherited.
247 | * Known issue: affects color of disabled elements.
248 | * 2. Correct font properties not being inherited.
249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
250 | */
251 |
252 | button,
253 | input,
254 | optgroup,
255 | select,
256 | textarea {
257 | color: inherit; /* 1 */
258 | font: inherit; /* 2 */
259 | margin: 0; /* 3 */
260 | }
261 |
262 | /**
263 | * Address `overflow` set to `hidden` in IE 8/9/10/11.
264 | */
265 |
266 | button {
267 | overflow: visible;
268 | }
269 |
270 | /**
271 | * Address inconsistent `text-transform` inheritance for `button` and `select`.
272 | * All other form control elements do not inherit `text-transform` values.
273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
274 | * Correct `select` style inheritance in Firefox.
275 | */
276 |
277 | button,
278 | select {
279 | text-transform: none;
280 | }
281 |
282 | /**
283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
284 | * and `video` controls.
285 | * 2. Correct inability to style clickable `input` types in iOS.
286 | * 3. Improve usability and consistency of cursor style between image-type
287 | * `input` and others.
288 | */
289 |
290 | button,
291 | html input[type="button"], /* 1 */
292 | input[type="reset"],
293 | input[type="submit"] {
294 | -webkit-appearance: button; /* 2 */
295 | cursor: pointer; /* 3 */
296 | }
297 |
298 | /**
299 | * Re-set default cursor for disabled elements.
300 | */
301 |
302 | button[disabled],
303 | html input[disabled] {
304 | cursor: default;
305 | }
306 |
307 | /**
308 | * Remove inner padding and border in Firefox 4+.
309 | */
310 |
311 | button::-moz-focus-inner,
312 | input::-moz-focus-inner {
313 | border: 0;
314 | padding: 0;
315 | }
316 |
317 | /**
318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in
319 | * the UA stylesheet.
320 | */
321 |
322 | input {
323 | line-height: normal;
324 | }
325 |
326 | /**
327 | * It's recommended that you don't attempt to style these elements.
328 | * Firefox's implementation doesn't respect box-sizing, padding, or width.
329 | *
330 | * 1. Address box sizing set to `content-box` in IE 8/9/10.
331 | * 2. Remove excess padding in IE 8/9/10.
332 | */
333 |
334 | input[type="checkbox"],
335 | input[type="radio"] {
336 | box-sizing: border-box; /* 1 */
337 | padding: 0; /* 2 */
338 | }
339 |
340 | /**
341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain
342 | * `font-size` values of the `input`, it causes the cursor style of the
343 | * decrement button to change from `default` to `text`.
344 | */
345 |
346 | input[type="number"]::-webkit-inner-spin-button,
347 | input[type="number"]::-webkit-outer-spin-button {
348 | height: auto;
349 | }
350 |
351 | /**
352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
354 | * (include `-moz` to future-proof).
355 | */
356 |
357 | input[type="search"] {
358 | -webkit-appearance: textfield; /* 1 */
359 | -moz-box-sizing: content-box;
360 | -webkit-box-sizing: content-box; /* 2 */
361 | box-sizing: content-box;
362 | }
363 |
364 | /**
365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X.
366 | * Safari (but not Chrome) clips the cancel button when the search input has
367 | * padding (and `textfield` appearance).
368 | */
369 |
370 | input[type="search"]::-webkit-search-cancel-button,
371 | input[type="search"]::-webkit-search-decoration {
372 | -webkit-appearance: none;
373 | }
374 |
375 | /**
376 | * Define consistent border, margin, and padding.
377 | */
378 |
379 | fieldset {
380 | border: 1px solid #c0c0c0;
381 | margin: 0 2px;
382 | padding: 0.35em 0.625em 0.75em;
383 | }
384 |
385 | /**
386 | * 1. Correct `color` not being inherited in IE 8/9/10/11.
387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets.
388 | */
389 |
390 | legend {
391 | border: 0; /* 1 */
392 | padding: 0; /* 2 */
393 | }
394 |
395 | /**
396 | * Remove default vertical scrollbar in IE 8/9/10/11.
397 | */
398 |
399 | textarea {
400 | overflow: auto;
401 | }
402 |
403 | /**
404 | * Don't inherit the `font-weight` (applied by a rule above).
405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
406 | */
407 |
408 | optgroup {
409 | font-weight: bold;
410 | }
411 |
412 | /* Tables
413 | ========================================================================== */
414 |
415 | /**
416 | * Remove most spacing between table cells.
417 | */
418 |
419 | table {
420 | border-collapse: collapse;
421 | border-spacing: 0;
422 | }
423 |
424 | td,
425 | th {
426 | padding: 0;
427 | }
--------------------------------------------------------------------------------
/templates/css/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */
2 |
3 | /**
4 | * 1. Set default font family to sans-serif.
5 | * 2. Prevent iOS text size adjust after orientation change, without disabling
6 | * user zoom.
7 | */
8 |
9 | html {
10 | font-family: sans-serif; /* 1 */
11 | -ms-text-size-adjust: 100%; /* 2 */
12 | -webkit-text-size-adjust: 100%; /* 2 */
13 | }
14 |
15 | /**
16 | * Remove default margin.
17 | */
18 |
19 | body {
20 | margin: 0;
21 | }
22 |
23 | /* HTML5 display definitions
24 | ========================================================================== */
25 |
26 | /**
27 | * Correct `block` display not defined for any HTML5 element in IE 8/9.
28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11
29 | * and Firefox.
30 | * Correct `block` display not defined for `main` in IE 11.
31 | */
32 |
33 | article,
34 | aside,
35 | details,
36 | figcaption,
37 | figure,
38 | footer,
39 | header,
40 | hgroup,
41 | main,
42 | menu,
43 | nav,
44 | section,
45 | summary {
46 | display: block;
47 | }
48 |
49 | /**
50 | * 1. Correct `inline-block` display not defined in IE 8/9.
51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
52 | */
53 |
54 | audio,
55 | canvas,
56 | progress,
57 | video {
58 | display: inline-block; /* 1 */
59 | vertical-align: baseline; /* 2 */
60 | }
61 |
62 | /**
63 | * Prevent modern browsers from displaying `audio` without controls.
64 | * Remove excess height in iOS 5 devices.
65 | */
66 |
67 | audio:not([controls]) {
68 | display: none;
69 | height: 0;
70 | }
71 |
72 | /**
73 | * Address `[hidden]` styling not present in IE 8/9/10.
74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
75 | */
76 |
77 | [hidden],
78 | template {
79 | display: none;
80 | }
81 |
82 | /* Links
83 | ========================================================================== */
84 |
85 | /**
86 | * Remove the gray background color from active links in IE 10.
87 | */
88 |
89 | a {
90 | background-color: transparent;
91 | }
92 |
93 | /**
94 | * Improve readability when focused and also mouse hovered in all browsers.
95 | */
96 |
97 | a:active,
98 | a:hover {
99 | outline: 0;
100 | }
101 |
102 | /* Text-level semantics
103 | ========================================================================== */
104 |
105 | /**
106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
107 | */
108 |
109 | abbr[title] {
110 | border-bottom: 1px dotted;
111 | }
112 |
113 | /**
114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
115 | */
116 |
117 | b,
118 | strong {
119 | font-weight: bold;
120 | }
121 |
122 | /**
123 | * Address styling not present in Safari and Chrome.
124 | */
125 |
126 | dfn {
127 | font-style: italic;
128 | }
129 |
130 | /**
131 | * Address variable `h1` font-size and margin within `section` and `article`
132 | * contexts in Firefox 4+, Safari, and Chrome.
133 | */
134 |
135 | h1 {
136 | font-size: 2em;
137 | margin: 0.67em 0;
138 | }
139 |
140 | /**
141 | * Address styling not present in IE 8/9.
142 | */
143 |
144 | mark {
145 | background: #ff0;
146 | color: #000;
147 | }
148 |
149 | /**
150 | * Address inconsistent and variable font size in all browsers.
151 | */
152 |
153 | small {
154 | font-size: 80%;
155 | }
156 |
157 | /**
158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers.
159 | */
160 |
161 | sub,
162 | sup {
163 | font-size: 75%;
164 | line-height: 0;
165 | position: relative;
166 | vertical-align: baseline;
167 | }
168 |
169 | sup {
170 | top: -0.5em;
171 | }
172 |
173 | sub {
174 | bottom: -0.25em;
175 | }
176 |
177 | /* Embedded content
178 | ========================================================================== */
179 |
180 | /**
181 | * Remove border when inside `a` element in IE 8/9/10.
182 | */
183 |
184 | img {
185 | border: 0;
186 | }
187 |
188 | /**
189 | * Correct overflow not hidden in IE 9/10/11.
190 | */
191 |
192 | svg:not(:root) {
193 | overflow: hidden;
194 | }
195 |
196 | /* Grouping content
197 | ========================================================================== */
198 |
199 | /**
200 | * Address margin not present in IE 8/9 and Safari.
201 | */
202 |
203 | figure {
204 | margin: 1em 40px;
205 | }
206 |
207 | /**
208 | * Address differences between Firefox and other browsers.
209 | */
210 |
211 | hr {
212 | -moz-box-sizing: content-box;
213 | box-sizing: content-box;
214 | height: 0;
215 | }
216 |
217 | /**
218 | * Contain overflow in all browsers.
219 | */
220 |
221 | pre {
222 | overflow: auto;
223 | }
224 |
225 | /**
226 | * Address odd `em`-unit font size rendering in all browsers.
227 | */
228 |
229 | code,
230 | kbd,
231 | pre,
232 | samp {
233 | font-family: monospace, monospace;
234 | font-size: 1em;
235 | }
236 |
237 | /* Forms
238 | ========================================================================== */
239 |
240 | /**
241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited
242 | * styling of `select`, unless a `border` property is set.
243 | */
244 |
245 | /**
246 | * 1. Correct color not being inherited.
247 | * Known issue: affects color of disabled elements.
248 | * 2. Correct font properties not being inherited.
249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
250 | */
251 |
252 | button,
253 | input,
254 | optgroup,
255 | select,
256 | textarea {
257 | color: inherit; /* 1 */
258 | font: inherit; /* 2 */
259 | margin: 0; /* 3 */
260 | }
261 |
262 | /**
263 | * Address `overflow` set to `hidden` in IE 8/9/10/11.
264 | */
265 |
266 | button {
267 | overflow: visible;
268 | }
269 |
270 | /**
271 | * Address inconsistent `text-transform` inheritance for `button` and `select`.
272 | * All other form control elements do not inherit `text-transform` values.
273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
274 | * Correct `select` style inheritance in Firefox.
275 | */
276 |
277 | button,
278 | select {
279 | text-transform: none;
280 | }
281 |
282 | /**
283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
284 | * and `video` controls.
285 | * 2. Correct inability to style clickable `input` types in iOS.
286 | * 3. Improve usability and consistency of cursor style between image-type
287 | * `input` and others.
288 | */
289 |
290 | button,
291 | html input[type="button"], /* 1 */
292 | input[type="reset"],
293 | input[type="submit"] {
294 | -webkit-appearance: button; /* 2 */
295 | cursor: pointer; /* 3 */
296 | }
297 |
298 | /**
299 | * Re-set default cursor for disabled elements.
300 | */
301 |
302 | button[disabled],
303 | html input[disabled] {
304 | cursor: default;
305 | }
306 |
307 | /**
308 | * Remove inner padding and border in Firefox 4+.
309 | */
310 |
311 | button::-moz-focus-inner,
312 | input::-moz-focus-inner {
313 | border: 0;
314 | padding: 0;
315 | }
316 |
317 | /**
318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in
319 | * the UA stylesheet.
320 | */
321 |
322 | input {
323 | line-height: normal;
324 | }
325 |
326 | /**
327 | * It's recommended that you don't attempt to style these elements.
328 | * Firefox's implementation doesn't respect box-sizing, padding, or width.
329 | *
330 | * 1. Address box sizing set to `content-box` in IE 8/9/10.
331 | * 2. Remove excess padding in IE 8/9/10.
332 | */
333 |
334 | input[type="checkbox"],
335 | input[type="radio"] {
336 | box-sizing: border-box; /* 1 */
337 | padding: 0; /* 2 */
338 | }
339 |
340 | /**
341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain
342 | * `font-size` values of the `input`, it causes the cursor style of the
343 | * decrement button to change from `default` to `text`.
344 | */
345 |
346 | input[type="number"]::-webkit-inner-spin-button,
347 | input[type="number"]::-webkit-outer-spin-button {
348 | height: auto;
349 | }
350 |
351 | /**
352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
354 | * (include `-moz` to future-proof).
355 | */
356 |
357 | input[type="search"] {
358 | -webkit-appearance: textfield; /* 1 */
359 | -moz-box-sizing: content-box;
360 | -webkit-box-sizing: content-box; /* 2 */
361 | box-sizing: content-box;
362 | }
363 |
364 | /**
365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X.
366 | * Safari (but not Chrome) clips the cancel button when the search input has
367 | * padding (and `textfield` appearance).
368 | */
369 |
370 | input[type="search"]::-webkit-search-cancel-button,
371 | input[type="search"]::-webkit-search-decoration {
372 | -webkit-appearance: none;
373 | }
374 |
375 | /**
376 | * Define consistent border, margin, and padding.
377 | */
378 |
379 | fieldset {
380 | border: 1px solid #c0c0c0;
381 | margin: 0 2px;
382 | padding: 0.35em 0.625em 0.75em;
383 | }
384 |
385 | /**
386 | * 1. Correct `color` not being inherited in IE 8/9/10/11.
387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets.
388 | */
389 |
390 | legend {
391 | border: 0; /* 1 */
392 | padding: 0; /* 2 */
393 | }
394 |
395 | /**
396 | * Remove default vertical scrollbar in IE 8/9/10/11.
397 | */
398 |
399 | textarea {
400 | overflow: auto;
401 | }
402 |
403 | /**
404 | * Don't inherit the `font-weight` (applied by a rule above).
405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
406 | */
407 |
408 | optgroup {
409 | font-weight: bold;
410 | }
411 |
412 | /* Tables
413 | ========================================================================== */
414 |
415 | /**
416 | * Remove most spacing between table cells.
417 | */
418 |
419 | table {
420 | border-collapse: collapse;
421 | border-spacing: 0;
422 | }
423 |
424 | td,
425 | th {
426 | padding: 0;
427 | }
428 |
--------------------------------------------------------------------------------
/static/skeleton.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skeleton V2.0.4
3 | * Copyright 2014, Dave Gamache
4 | * www.getskeleton.com
5 | * Free to use under the MIT license.
6 | * http://www.opensource.org/licenses/mit-license.php
7 | * 12/29/2014
8 | */
9 |
10 |
11 | /* Table of contents
12 | ––––––––––––––––––––––––––––––––––––––––––––––––––
13 | - Grid
14 | - Base Styles
15 | - Typography
16 | - Links
17 | - Buttons
18 | - Forms
19 | - Lists
20 | - Code
21 | - Tables
22 | - Spacing
23 | - Utilities
24 | - Clearing
25 | - Media Queries
26 | */
27 |
28 |
29 | /* Grid
30 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
31 | .container {
32 | position: relative;
33 | width: 100%;
34 | max-width: 960px;
35 | margin: 0 auto;
36 | padding: 0 20px;
37 | box-sizing: border-box; }
38 | .column,
39 | .columns {
40 | width: 100%;
41 | float: left;
42 | box-sizing: border-box; }
43 |
44 | /* For devices larger than 400px */
45 | @media (min-width: 400px) {
46 | .container {
47 | width: 85%;
48 | padding: 0; }
49 | }
50 |
51 | /* For devices larger than 550px */
52 | @media (min-width: 550px) {
53 | .container {
54 | width: 80%; }
55 | .column,
56 | .columns {
57 | margin-left: 4%; }
58 | .column:first-child,
59 | .columns:first-child {
60 | margin-left: 0; }
61 |
62 | .one.column,
63 | .one.columns { width: 4.66666666667%; }
64 | .two.columns { width: 13.3333333333%; }
65 | .three.columns { width: 22%; }
66 | .four.columns { width: 30.6666666667%; }
67 | .five.columns { width: 39.3333333333%; }
68 | .six.columns { width: 48%; }
69 | .seven.columns { width: 56.6666666667%; }
70 | .eight.columns { width: 65.3333333333%; }
71 | .nine.columns { width: 74.0%; }
72 | .ten.columns { width: 82.6666666667%; }
73 | .eleven.columns { width: 91.3333333333%; }
74 | .twelve.columns { width: 100%; margin-left: 0; }
75 |
76 | .one-third.column { width: 30.6666666667%; }
77 | .two-thirds.column { width: 65.3333333333%; }
78 |
79 | .one-half.column { width: 48%; }
80 |
81 | /* Offsets */
82 | .offset-by-one.column,
83 | .offset-by-one.columns { margin-left: 8.66666666667%; }
84 | .offset-by-two.column,
85 | .offset-by-two.columns { margin-left: 17.3333333333%; }
86 | .offset-by-three.column,
87 | .offset-by-three.columns { margin-left: 26%; }
88 | .offset-by-four.column,
89 | .offset-by-four.columns { margin-left: 34.6666666667%; }
90 | .offset-by-five.column,
91 | .offset-by-five.columns { margin-left: 43.3333333333%; }
92 | .offset-by-six.column,
93 | .offset-by-six.columns { margin-left: 52%; }
94 | .offset-by-seven.column,
95 | .offset-by-seven.columns { margin-left: 60.6666666667%; }
96 | .offset-by-eight.column,
97 | .offset-by-eight.columns { margin-left: 69.3333333333%; }
98 | .offset-by-nine.column,
99 | .offset-by-nine.columns { margin-left: 78.0%; }
100 | .offset-by-ten.column,
101 | .offset-by-ten.columns { margin-left: 86.6666666667%; }
102 | .offset-by-eleven.column,
103 | .offset-by-eleven.columns { margin-left: 95.3333333333%; }
104 |
105 | .offset-by-one-third.column,
106 | .offset-by-one-third.columns { margin-left: 34.6666666667%; }
107 | .offset-by-two-thirds.column,
108 | .offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
109 |
110 | .offset-by-one-half.column,
111 | .offset-by-one-half.columns { margin-left: 52%; }
112 |
113 | }
114 |
115 |
116 | /* Base Styles
117 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
118 | /* NOTE
119 | html is set to 62.5% so that all the REM measurements throughout Skeleton
120 | are based on 10px sizing. So basically 1.5rem = 15px :) */
121 | html {
122 | font-size: 62.5%; }
123 | body {
124 | font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
125 | line-height: 1.6;
126 | font-weight: 400;
127 | font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
128 | color: #222; }
129 |
130 |
131 | /* Typography
132 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
133 | h1, h2, h3, h4, h5, h6 {
134 | margin-top: 0;
135 | margin-bottom: 2rem;
136 | font-weight: 300; }
137 | h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
138 | h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
139 | h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
140 | h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
141 | h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
142 | h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
143 |
144 | /* Larger than phablet */
145 | @media (min-width: 550px) {
146 | h1 { font-size: 5.0rem; }
147 | h2 { font-size: 4.2rem; }
148 | h3 { font-size: 3.6rem; }
149 | h4 { font-size: 3.0rem; }
150 | h5 { font-size: 2.4rem; }
151 | h6 { font-size: 1.5rem; }
152 | }
153 |
154 | p {
155 | margin-top: 0; }
156 |
157 |
158 | /* Links
159 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
160 | a {
161 | color: #1EAEDB; }
162 | a:hover {
163 | color: #0FA0CE; }
164 |
165 |
166 | /* Buttons
167 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
168 | .button,
169 | button,
170 | input[type="submit"],
171 | input[type="reset"],
172 | input[type="button"] {
173 | display: inline-block;
174 | height: 38px;
175 | padding: 0 30px;
176 | color: #555;
177 | text-align: center;
178 | font-size: 11px;
179 | font-weight: 600;
180 | line-height: 38px;
181 | letter-spacing: .1rem;
182 | text-transform: uppercase;
183 | text-decoration: none;
184 | white-space: nowrap;
185 | background-color: transparent;
186 | border-radius: 4px;
187 | border: 1px solid #bbb;
188 | cursor: pointer;
189 | box-sizing: border-box; }
190 | .button:hover,
191 | button:hover,
192 | input[type="submit"]:hover,
193 | input[type="reset"]:hover,
194 | input[type="button"]:hover,
195 | .button:focus,
196 | button:focus,
197 | input[type="submit"]:focus,
198 | input[type="reset"]:focus,
199 | input[type="button"]:focus {
200 | color: #333;
201 | border-color: #888;
202 | outline: 0; }
203 | .button.button-primary,
204 | button.button-primary,
205 | input[type="submit"].button-primary,
206 | input[type="reset"].button-primary,
207 | input[type="button"].button-primary {
208 | color: #FFF;
209 | background-color: #33C3F0;
210 | border-color: #33C3F0; }
211 | .button.button-primary:hover,
212 | button.button-primary:hover,
213 | input[type="submit"].button-primary:hover,
214 | input[type="reset"].button-primary:hover,
215 | input[type="button"].button-primary:hover,
216 | .button.button-primary:focus,
217 | button.button-primary:focus,
218 | input[type="submit"].button-primary:focus,
219 | input[type="reset"].button-primary:focus,
220 | input[type="button"].button-primary:focus {
221 | color: #FFF;
222 | background-color: #1EAEDB;
223 | border-color: #1EAEDB; }
224 |
225 |
226 | /* Forms
227 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
228 | input[type="email"],
229 | input[type="number"],
230 | input[type="search"],
231 | input[type="text"],
232 | input[type="tel"],
233 | input[type="url"],
234 | input[type="password"],
235 | textarea,
236 | select {
237 | height: 38px;
238 | padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
239 | background-color: #fff;
240 | border: 1px solid #D1D1D1;
241 | border-radius: 4px;
242 | box-shadow: none;
243 | box-sizing: border-box; }
244 | /* Removes awkward default styles on some inputs for iOS */
245 | input[type="email"],
246 | input[type="number"],
247 | input[type="search"],
248 | input[type="text"],
249 | input[type="tel"],
250 | input[type="url"],
251 | input[type="password"],
252 | textarea {
253 | -webkit-appearance: none;
254 | -moz-appearance: none;
255 | appearance: none; }
256 | textarea {
257 | min-height: 65px;
258 | padding-top: 6px;
259 | padding-bottom: 6px; }
260 | input[type="email"]:focus,
261 | input[type="number"]:focus,
262 | input[type="search"]:focus,
263 | input[type="text"]:focus,
264 | input[type="tel"]:focus,
265 | input[type="url"]:focus,
266 | input[type="password"]:focus,
267 | textarea:focus,
268 | select:focus {
269 | border: 1px solid #33C3F0;
270 | outline: 0; }
271 | label,
272 | legend {
273 | display: block;
274 | margin-bottom: .5rem;
275 | font-weight: 600; }
276 | fieldset {
277 | padding: 0;
278 | border-width: 0; }
279 | input[type="checkbox"],
280 | input[type="radio"] {
281 | display: inline; }
282 | label > .label-body {
283 | display: inline-block;
284 | margin-left: .5rem;
285 | font-weight: normal; }
286 |
287 |
288 | /* Lists
289 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
290 | ul {
291 | list-style: circle inside; }
292 | ol {
293 | list-style: decimal inside; }
294 | ol, ul {
295 | padding-left: 0;
296 | margin-top: 0; }
297 | ul ul,
298 | ul ol,
299 | ol ol,
300 | ol ul {
301 | margin: 1.5rem 0 1.5rem 3rem;
302 | font-size: 90%; }
303 | li {
304 | margin-bottom: 1rem; }
305 |
306 |
307 | /* Code
308 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
309 | code {
310 | padding: .2rem .5rem;
311 | margin: 0 .2rem;
312 | font-size: 90%;
313 | white-space: nowrap;
314 | background: #F1F1F1;
315 | border: 1px solid #E1E1E1;
316 | border-radius: 4px; }
317 | pre > code {
318 | display: block;
319 | padding: 1rem 1.5rem;
320 | white-space: pre; }
321 |
322 |
323 | /* Tables
324 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
325 | th,
326 | td {
327 | padding: 12px 15px;
328 | text-align: left;
329 | border-bottom: 1px solid #E1E1E1; }
330 | th:first-child,
331 | td:first-child {
332 | padding-left: 0; }
333 | th:last-child,
334 | td:last-child {
335 | padding-right: 0; }
336 |
337 |
338 | /* Spacing
339 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
340 | button,
341 | .button {
342 | margin-bottom: 1rem; }
343 | input,
344 | textarea,
345 | select,
346 | fieldset {
347 | margin-bottom: 1.5rem; }
348 | pre,
349 | blockquote,
350 | dl,
351 | figure,
352 | table,
353 | p,
354 | ul,
355 | ol,
356 | form {
357 | margin-bottom: 2.5rem; }
358 |
359 |
360 | /* Utilities
361 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
362 | .u-full-width {
363 | width: 100%;
364 | box-sizing: border-box; }
365 | .u-max-full-width {
366 | max-width: 100%;
367 | box-sizing: border-box; }
368 | .u-pull-right {
369 | float: right; }
370 | .u-pull-left {
371 | float: left; }
372 |
373 |
374 | /* Misc
375 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
376 | hr {
377 | margin-top: 3rem;
378 | margin-bottom: 3.5rem;
379 | border-width: 0;
380 | border-top: 1px solid #E1E1E1; }
381 |
382 |
383 | /* Clearing
384 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
385 |
386 | /* Self Clearing Goodness */
387 | .container:after,
388 | .row:after,
389 | .u-cf {
390 | content: "";
391 | display: table;
392 | clear: both; }
393 |
394 |
395 | /* Media Queries
396 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
397 | /*
398 | Note: The best way to structure the use of media queries is to create the queries
399 | near the relevant code. For example, if you wanted to change the styles for buttons
400 | on small devices, paste the mobile query code up in the buttons section and style it
401 | there.
402 | */
403 |
404 |
405 | /* Larger than mobile */
406 | @media (min-width: 400px) {}
407 |
408 | /* Larger than phablet (also point when grid becomes active) */
409 | @media (min-width: 550px) {}
410 |
411 | /* Larger than tablet */
412 | @media (min-width: 750px) {}
413 |
414 | /* Larger than desktop */
415 | @media (min-width: 1000px) {}
416 |
417 | /* Larger than Desktop HD */
418 | @media (min-width: 1200px) {}
419 |
--------------------------------------------------------------------------------
/templates/css/skeleton.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skeleton V2.0.4
3 | * Copyright 2014, Dave Gamache
4 | * www.getskeleton.com
5 | * Free to use under the MIT license.
6 | * http://www.opensource.org/licenses/mit-license.php
7 | * 12/29/2014
8 | */
9 |
10 |
11 | /* Table of contents
12 | ––––––––––––––––––––––––––––––––––––––––––––––––––
13 | - Grid
14 | - Base Styles
15 | - Typography
16 | - Links
17 | - Buttons
18 | - Forms
19 | - Lists
20 | - Code
21 | - Tables
22 | - Spacing
23 | - Utilities
24 | - Clearing
25 | - Media Queries
26 | */
27 |
28 |
29 | /* Grid
30 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
31 | .container {
32 | position: relative;
33 | width: 100%;
34 | max-width: 960px;
35 | margin: 0 auto;
36 | padding: 0 20px;
37 | box-sizing: border-box; }
38 | .column,
39 | .columns {
40 | width: 100%;
41 | float: left;
42 | box-sizing: border-box; }
43 |
44 | /* For devices larger than 400px */
45 | @media (min-width: 400px) {
46 | .container {
47 | width: 85%;
48 | padding: 0; }
49 | }
50 |
51 | /* For devices larger than 550px */
52 | @media (min-width: 550px) {
53 | .container {
54 | width: 80%; }
55 | .column,
56 | .columns {
57 | margin-left: 4%; }
58 | .column:first-child,
59 | .columns:first-child {
60 | margin-left: 0; }
61 |
62 | .one.column,
63 | .one.columns { width: 4.66666666667%; }
64 | .two.columns { width: 13.3333333333%; }
65 | .three.columns { width: 22%; }
66 | .four.columns { width: 30.6666666667%; }
67 | .five.columns { width: 39.3333333333%; }
68 | .six.columns { width: 48%; }
69 | .seven.columns { width: 56.6666666667%; }
70 | .eight.columns { width: 65.3333333333%; }
71 | .nine.columns { width: 74.0%; }
72 | .ten.columns { width: 82.6666666667%; }
73 | .eleven.columns { width: 91.3333333333%; }
74 | .twelve.columns { width: 100%; margin-left: 0; }
75 |
76 | .one-third.column { width: 30.6666666667%; }
77 | .two-thirds.column { width: 65.3333333333%; }
78 |
79 | .one-half.column { width: 48%; }
80 |
81 | /* Offsets */
82 | .offset-by-one.column,
83 | .offset-by-one.columns { margin-left: 8.66666666667%; }
84 | .offset-by-two.column,
85 | .offset-by-two.columns { margin-left: 17.3333333333%; }
86 | .offset-by-three.column,
87 | .offset-by-three.columns { margin-left: 26%; }
88 | .offset-by-four.column,
89 | .offset-by-four.columns { margin-left: 34.6666666667%; }
90 | .offset-by-five.column,
91 | .offset-by-five.columns { margin-left: 43.3333333333%; }
92 | .offset-by-six.column,
93 | .offset-by-six.columns { margin-left: 52%; }
94 | .offset-by-seven.column,
95 | .offset-by-seven.columns { margin-left: 60.6666666667%; }
96 | .offset-by-eight.column,
97 | .offset-by-eight.columns { margin-left: 69.3333333333%; }
98 | .offset-by-nine.column,
99 | .offset-by-nine.columns { margin-left: 78.0%; }
100 | .offset-by-ten.column,
101 | .offset-by-ten.columns { margin-left: 86.6666666667%; }
102 | .offset-by-eleven.column,
103 | .offset-by-eleven.columns { margin-left: 95.3333333333%; }
104 |
105 | .offset-by-one-third.column,
106 | .offset-by-one-third.columns { margin-left: 34.6666666667%; }
107 | .offset-by-two-thirds.column,
108 | .offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
109 |
110 | .offset-by-one-half.column,
111 | .offset-by-one-half.columns { margin-left: 52%; }
112 |
113 | }
114 |
115 |
116 | /* Base Styles
117 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
118 | /* NOTE
119 | html is set to 62.5% so that all the REM measurements throughout Skeleton
120 | are based on 10px sizing. So basically 1.5rem = 15px :) */
121 | html {
122 | font-size: 62.5%; }
123 | body {
124 | font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
125 | line-height: 1.6;
126 | font-weight: 400;
127 | font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
128 | color: #222; }
129 |
130 |
131 | /* Typography
132 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
133 | h1, h2, h3, h4, h5, h6 {
134 | margin-top: 0;
135 | margin-bottom: 2rem;
136 | font-weight: 300; }
137 | h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
138 | h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
139 | h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
140 | h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
141 | h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
142 | h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
143 |
144 | /* Larger than phablet */
145 | @media (min-width: 550px) {
146 | h1 { font-size: 5.0rem; }
147 | h2 { font-size: 4.2rem; }
148 | h3 { font-size: 3.6rem; }
149 | h4 { font-size: 3.0rem; }
150 | h5 { font-size: 2.4rem; }
151 | h6 { font-size: 1.5rem; }
152 | }
153 |
154 | p {
155 | margin-top: 0; }
156 |
157 |
158 | /* Links
159 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
160 | a {
161 | color: #1EAEDB; }
162 | a:hover {
163 | color: #0FA0CE; }
164 |
165 |
166 | /* Buttons
167 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
168 | .button,
169 | button,
170 | input[type="submit"],
171 | input[type="reset"],
172 | input[type="button"] {
173 | display: inline-block;
174 | height: 38px;
175 | padding: 0 30px;
176 | color: #555;
177 | text-align: center;
178 | font-size: 11px;
179 | font-weight: 600;
180 | line-height: 38px;
181 | letter-spacing: .1rem;
182 | text-transform: uppercase;
183 | text-decoration: none;
184 | white-space: nowrap;
185 | background-color: transparent;
186 | border-radius: 4px;
187 | border: 1px solid #bbb;
188 | cursor: pointer;
189 | box-sizing: border-box; }
190 | .button:hover,
191 | button:hover,
192 | input[type="submit"]:hover,
193 | input[type="reset"]:hover,
194 | input[type="button"]:hover,
195 | .button:focus,
196 | button:focus,
197 | input[type="submit"]:focus,
198 | input[type="reset"]:focus,
199 | input[type="button"]:focus {
200 | color: #333;
201 | border-color: #888;
202 | outline: 0; }
203 | .button.button-primary,
204 | button.button-primary,
205 | input[type="submit"].button-primary,
206 | input[type="reset"].button-primary,
207 | input[type="button"].button-primary {
208 | color: #FFF;
209 | background-color: #33C3F0;
210 | border-color: #33C3F0; }
211 | .button.button-primary:hover,
212 | button.button-primary:hover,
213 | input[type="submit"].button-primary:hover,
214 | input[type="reset"].button-primary:hover,
215 | input[type="button"].button-primary:hover,
216 | .button.button-primary:focus,
217 | button.button-primary:focus,
218 | input[type="submit"].button-primary:focus,
219 | input[type="reset"].button-primary:focus,
220 | input[type="button"].button-primary:focus {
221 | color: #FFF;
222 | background-color: #1EAEDB;
223 | border-color: #1EAEDB; }
224 |
225 |
226 | /* Forms
227 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
228 | input[type="email"],
229 | input[type="number"],
230 | input[type="search"],
231 | input[type="text"],
232 | input[type="tel"],
233 | input[type="url"],
234 | input[type="password"],
235 | textarea,
236 | select {
237 | height: 38px;
238 | padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
239 | background-color: #fff;
240 | border: 1px solid #D1D1D1;
241 | border-radius: 4px;
242 | box-shadow: none;
243 | box-sizing: border-box; }
244 | /* Removes awkward default styles on some inputs for iOS */
245 | input[type="email"],
246 | input[type="number"],
247 | input[type="search"],
248 | input[type="text"],
249 | input[type="tel"],
250 | input[type="url"],
251 | input[type="password"],
252 | textarea {
253 | -webkit-appearance: none;
254 | -moz-appearance: none;
255 | appearance: none; }
256 | textarea {
257 | min-height: 65px;
258 | padding-top: 6px;
259 | padding-bottom: 6px; }
260 | input[type="email"]:focus,
261 | input[type="number"]:focus,
262 | input[type="search"]:focus,
263 | input[type="text"]:focus,
264 | input[type="tel"]:focus,
265 | input[type="url"]:focus,
266 | input[type="password"]:focus,
267 | textarea:focus,
268 | select:focus {
269 | border: 1px solid #33C3F0;
270 | outline: 0; }
271 | label,
272 | legend {
273 | display: block;
274 | margin-bottom: .5rem;
275 | font-weight: 600; }
276 | fieldset {
277 | padding: 0;
278 | border-width: 0; }
279 | input[type="checkbox"],
280 | input[type="radio"] {
281 | display: inline; }
282 | label > .label-body {
283 | display: inline-block;
284 | margin-left: .5rem;
285 | font-weight: normal; }
286 |
287 |
288 | /* Lists
289 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
290 | ul {
291 | list-style: circle inside; }
292 | ol {
293 | list-style: decimal inside; }
294 | ol, ul {
295 | padding-left: 0;
296 | margin-top: 0; }
297 | ul ul,
298 | ul ol,
299 | ol ol,
300 | ol ul {
301 | margin: 1.5rem 0 1.5rem 3rem;
302 | font-size: 90%; }
303 | li {
304 | margin-bottom: 1rem; }
305 |
306 |
307 | /* Code
308 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
309 | code {
310 | padding: .2rem .5rem;
311 | margin: 0 .2rem;
312 | font-size: 90%;
313 | white-space: nowrap;
314 | background: #F1F1F1;
315 | border: 1px solid #E1E1E1;
316 | border-radius: 4px; }
317 | pre > code {
318 | display: block;
319 | padding: 1rem 1.5rem;
320 | white-space: pre; }
321 |
322 |
323 | /* Tables
324 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
325 | th,
326 | td {
327 | padding: 12px 15px;
328 | text-align: left;
329 | border-bottom: 1px solid #E1E1E1; }
330 | th:first-child,
331 | td:first-child {
332 | padding-left: 0; }
333 | th:last-child,
334 | td:last-child {
335 | padding-right: 0; }
336 |
337 |
338 | /* Spacing
339 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
340 | button,
341 | .button {
342 | margin-bottom: 1rem; }
343 | input,
344 | textarea,
345 | select,
346 | fieldset {
347 | margin-bottom: 1.5rem; }
348 | pre,
349 | blockquote,
350 | dl,
351 | figure,
352 | table,
353 | p,
354 | ul,
355 | ol,
356 | form {
357 | margin-bottom: 2.5rem; }
358 |
359 |
360 | /* Utilities
361 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
362 | .u-full-width {
363 | width: 100%;
364 | box-sizing: border-box; }
365 | .u-max-full-width {
366 | max-width: 100%;
367 | box-sizing: border-box; }
368 | .u-pull-right {
369 | float: right; }
370 | .u-pull-left {
371 | float: left; }
372 |
373 |
374 | /* Misc
375 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
376 | hr {
377 | margin-top: 3rem;
378 | margin-bottom: 3.5rem;
379 | border-width: 0;
380 | border-top: 1px solid #E1E1E1; }
381 |
382 |
383 | /* Clearing
384 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
385 |
386 | /* Self Clearing Goodness */
387 | .container:after,
388 | .row:after,
389 | .u-cf {
390 | content: "";
391 | display: table;
392 | clear: both; }
393 |
394 |
395 | /* Media Queries
396 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
397 | /*
398 | Note: The best way to structure the use of media queries is to create the queries
399 | near the relevant code. For example, if you wanted to change the styles for buttons
400 | on small devices, paste the mobile query code up in the buttons section and style it
401 | there.
402 | */
403 |
404 |
405 | /* Larger than mobile */
406 | @media (min-width: 400px) {}
407 |
408 | /* Larger than phablet (also point when grid becomes active) */
409 | @media (min-width: 550px) {}
410 |
411 | /* Larger than tablet */
412 | @media (min-width: 750px) {}
413 |
414 | /* Larger than desktop */
415 | @media (min-width: 1000px) {}
416 |
417 | /* Larger than Desktop HD */
418 | @media (min-width: 1200px) {}
419 |
--------------------------------------------------------------------------------
/templates/static/skeleton.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skeleton V2.0.4
3 | * Copyright 2014, Dave Gamache
4 | * www.getskeleton.com
5 | * Free to use under the MIT license.
6 | * http://www.opensource.org/licenses/mit-license.php
7 | * 12/29/2014
8 | */
9 |
10 |
11 | /* Table of contents
12 | ––––––––––––––––––––––––––––––––––––––––––––––––––
13 | - Grid
14 | - Base Styles
15 | - Typography
16 | - Links
17 | - Buttons
18 | - Forms
19 | - Lists
20 | - Code
21 | - Tables
22 | - Spacing
23 | - Utilities
24 | - Clearing
25 | - Media Queries
26 | */
27 |
28 |
29 | /* Grid
30 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
31 | .container {
32 | position: relative;
33 | width: 100%;
34 | max-width: 960px;
35 | margin: 0 auto;
36 | padding: 0 20px;
37 | box-sizing: border-box; }
38 | .column,
39 | .columns {
40 | width: 100%;
41 | float: left;
42 | box-sizing: border-box; }
43 |
44 | /* For devices larger than 400px */
45 | @media (min-width: 400px) {
46 | .container {
47 | width: 85%;
48 | padding: 0; }
49 | }
50 |
51 | /* For devices larger than 550px */
52 | @media (min-width: 550px) {
53 | .container {
54 | width: 80%; }
55 | .column,
56 | .columns {
57 | margin-left: 4%; }
58 | .column:first-child,
59 | .columns:first-child {
60 | margin-left: 0; }
61 |
62 | .one.column,
63 | .one.columns { width: 4.66666666667%; }
64 | .two.columns { width: 13.3333333333%; }
65 | .three.columns { width: 22%; }
66 | .four.columns { width: 30.6666666667%; }
67 | .five.columns { width: 39.3333333333%; }
68 | .six.columns { width: 48%; }
69 | .seven.columns { width: 56.6666666667%; }
70 | .eight.columns { width: 65.3333333333%; }
71 | .nine.columns { width: 74.0%; }
72 | .ten.columns { width: 82.6666666667%; }
73 | .eleven.columns { width: 91.3333333333%; }
74 | .twelve.columns { width: 100%; margin-left: 0; }
75 |
76 | .one-third.column { width: 30.6666666667%; }
77 | .two-thirds.column { width: 65.3333333333%; }
78 |
79 | .one-half.column { width: 48%; }
80 |
81 | /* Offsets */
82 | .offset-by-one.column,
83 | .offset-by-one.columns { margin-left: 8.66666666667%; }
84 | .offset-by-two.column,
85 | .offset-by-two.columns { margin-left: 17.3333333333%; }
86 | .offset-by-three.column,
87 | .offset-by-three.columns { margin-left: 26%; }
88 | .offset-by-four.column,
89 | .offset-by-four.columns { margin-left: 34.6666666667%; }
90 | .offset-by-five.column,
91 | .offset-by-five.columns { margin-left: 43.3333333333%; }
92 | .offset-by-six.column,
93 | .offset-by-six.columns { margin-left: 52%; }
94 | .offset-by-seven.column,
95 | .offset-by-seven.columns { margin-left: 60.6666666667%; }
96 | .offset-by-eight.column,
97 | .offset-by-eight.columns { margin-left: 69.3333333333%; }
98 | .offset-by-nine.column,
99 | .offset-by-nine.columns { margin-left: 78.0%; }
100 | .offset-by-ten.column,
101 | .offset-by-ten.columns { margin-left: 86.6666666667%; }
102 | .offset-by-eleven.column,
103 | .offset-by-eleven.columns { margin-left: 95.3333333333%; }
104 |
105 | .offset-by-one-third.column,
106 | .offset-by-one-third.columns { margin-left: 34.6666666667%; }
107 | .offset-by-two-thirds.column,
108 | .offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
109 |
110 | .offset-by-one-half.column,
111 | .offset-by-one-half.columns { margin-left: 52%; }
112 |
113 | }
114 |
115 |
116 | /* Base Styles
117 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
118 | /* NOTE
119 | html is set to 62.5% so that all the REM measurements throughout Skeleton
120 | are based on 10px sizing. So basically 1.5rem = 15px :) */
121 | html {
122 | font-size: 62.5%; }
123 | body {
124 | font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
125 | line-height: 1.6;
126 | font-weight: 400;
127 | font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
128 | color: #222; }
129 |
130 |
131 | /* Typography
132 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
133 | h1, h2, h3, h4, h5, h6 {
134 | margin-top: 0;
135 | margin-bottom: 2rem;
136 | font-weight: 300; }
137 | h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
138 | h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
139 | h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
140 | h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
141 | h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
142 | h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
143 |
144 | /* Larger than phablet */
145 | @media (min-width: 550px) {
146 | h1 { font-size: 5.0rem; }
147 | h2 { font-size: 4.2rem; }
148 | h3 { font-size: 3.6rem; }
149 | h4 { font-size: 3.0rem; }
150 | h5 { font-size: 2.4rem; }
151 | h6 { font-size: 1.5rem; }
152 | }
153 |
154 | p {
155 | margin-top: 0; }
156 |
157 |
158 | /* Links
159 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
160 | a {
161 | color: #1EAEDB; }
162 | a:hover {
163 | color: #0FA0CE; }
164 |
165 |
166 | /* Buttons
167 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
168 | .button,
169 | button,
170 | input[type="submit"],
171 | input[type="reset"],
172 | input[type="button"] {
173 | display: inline-block;
174 | height: 38px;
175 | padding: 0 30px;
176 | color: #555;
177 | text-align: center;
178 | font-size: 11px;
179 | font-weight: 600;
180 | line-height: 38px;
181 | letter-spacing: .1rem;
182 | text-transform: uppercase;
183 | text-decoration: none;
184 | white-space: nowrap;
185 | background-color: transparent;
186 | border-radius: 4px;
187 | border: 1px solid #bbb;
188 | cursor: pointer;
189 | box-sizing: border-box; }
190 | .button:hover,
191 | button:hover,
192 | input[type="submit"]:hover,
193 | input[type="reset"]:hover,
194 | input[type="button"]:hover,
195 | .button:focus,
196 | button:focus,
197 | input[type="submit"]:focus,
198 | input[type="reset"]:focus,
199 | input[type="button"]:focus {
200 | color: #333;
201 | border-color: #888;
202 | outline: 0; }
203 | .button.button-primary,
204 | button.button-primary,
205 | input[type="submit"].button-primary,
206 | input[type="reset"].button-primary,
207 | input[type="button"].button-primary {
208 | color: #FFF;
209 | background-color: #33C3F0;
210 | border-color: #33C3F0; }
211 | .button.button-primary:hover,
212 | button.button-primary:hover,
213 | input[type="submit"].button-primary:hover,
214 | input[type="reset"].button-primary:hover,
215 | input[type="button"].button-primary:hover,
216 | .button.button-primary:focus,
217 | button.button-primary:focus,
218 | input[type="submit"].button-primary:focus,
219 | input[type="reset"].button-primary:focus,
220 | input[type="button"].button-primary:focus {
221 | color: #FFF;
222 | background-color: #1EAEDB;
223 | border-color: #1EAEDB; }
224 |
225 |
226 | /* Forms
227 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
228 | input[type="email"],
229 | input[type="number"],
230 | input[type="search"],
231 | input[type="text"],
232 | input[type="tel"],
233 | input[type="url"],
234 | input[type="password"],
235 | textarea,
236 | select {
237 | height: 38px;
238 | padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
239 | background-color: #fff;
240 | border: 1px solid #D1D1D1;
241 | border-radius: 4px;
242 | box-shadow: none;
243 | box-sizing: border-box; }
244 | /* Removes awkward default styles on some inputs for iOS */
245 | input[type="email"],
246 | input[type="number"],
247 | input[type="search"],
248 | input[type="text"],
249 | input[type="tel"],
250 | input[type="url"],
251 | input[type="password"],
252 | textarea {
253 | -webkit-appearance: none;
254 | -moz-appearance: none;
255 | appearance: none; }
256 | textarea {
257 | min-height: 65px;
258 | padding-top: 6px;
259 | padding-bottom: 6px; }
260 | input[type="email"]:focus,
261 | input[type="number"]:focus,
262 | input[type="search"]:focus,
263 | input[type="text"]:focus,
264 | input[type="tel"]:focus,
265 | input[type="url"]:focus,
266 | input[type="password"]:focus,
267 | textarea:focus,
268 | select:focus {
269 | border: 1px solid #33C3F0;
270 | outline: 0; }
271 | label,
272 | legend {
273 | display: block;
274 | margin-bottom: .5rem;
275 | font-weight: 600; }
276 | fieldset {
277 | padding: 0;
278 | border-width: 0; }
279 | input[type="checkbox"],
280 | input[type="radio"] {
281 | display: inline; }
282 | label > .label-body {
283 | display: inline-block;
284 | margin-left: .5rem;
285 | font-weight: normal; }
286 |
287 |
288 | /* Lists
289 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
290 | ul {
291 | list-style: circle inside; }
292 | ol {
293 | list-style: decimal inside; }
294 | ol, ul {
295 | padding-left: 0;
296 | margin-top: 0; }
297 | ul ul,
298 | ul ol,
299 | ol ol,
300 | ol ul {
301 | margin: 1.5rem 0 1.5rem 3rem;
302 | font-size: 90%; }
303 | li {
304 | margin-bottom: 1rem; }
305 |
306 |
307 | /* Code
308 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
309 | code {
310 | padding: .2rem .5rem;
311 | margin: 0 .2rem;
312 | font-size: 90%;
313 | white-space: nowrap;
314 | background: #F1F1F1;
315 | border: 1px solid #E1E1E1;
316 | border-radius: 4px; }
317 | pre > code {
318 | display: block;
319 | padding: 1rem 1.5rem;
320 | white-space: pre; }
321 |
322 |
323 | /* Tables
324 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
325 | th,
326 | td {
327 | padding: 12px 15px;
328 | text-align: left;
329 | border-bottom: 1px solid #E1E1E1; }
330 | th:first-child,
331 | td:first-child {
332 | padding-left: 0; }
333 | th:last-child,
334 | td:last-child {
335 | padding-right: 0; }
336 |
337 |
338 | /* Spacing
339 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
340 | button,
341 | .button {
342 | margin-bottom: 1rem; }
343 | input,
344 | textarea,
345 | select,
346 | fieldset {
347 | margin-bottom: 1.5rem; }
348 | pre,
349 | blockquote,
350 | dl,
351 | figure,
352 | table,
353 | p,
354 | ul,
355 | ol,
356 | form {
357 | margin-bottom: 2.5rem; }
358 |
359 |
360 | /* Utilities
361 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
362 | .u-full-width {
363 | width: 100%;
364 | box-sizing: border-box; }
365 | .u-max-full-width {
366 | max-width: 100%;
367 | box-sizing: border-box; }
368 | .u-pull-right {
369 | float: right; }
370 | .u-pull-left {
371 | float: left; }
372 |
373 |
374 | /* Misc
375 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
376 | hr {
377 | margin-top: 3rem;
378 | margin-bottom: 3.5rem;
379 | border-width: 0;
380 | border-top: 1px solid #E1E1E1; }
381 |
382 |
383 | /* Clearing
384 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
385 |
386 | /* Self Clearing Goodness */
387 | .container:after,
388 | .row:after,
389 | .u-cf {
390 | content: "";
391 | display: table;
392 | clear: both; }
393 |
394 |
395 | /* Media Queries
396 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
397 | /*
398 | Note: The best way to structure the use of media queries is to create the queries
399 | near the relevant code. For example, if you wanted to change the styles for buttons
400 | on small devices, paste the mobile query code up in the buttons section and style it
401 | there.
402 | */
403 |
404 |
405 | /* Larger than mobile */
406 | @media (min-width: 400px) {}
407 |
408 | /* Larger than phablet (also point when grid becomes active) */
409 | @media (min-width: 550px) {}
410 |
411 | /* Larger than tablet */
412 | @media (min-width: 750px) {}
413 |
414 | /* Larger than desktop */
415 | @media (min-width: 1000px) {}
416 |
417 | /* Larger than Desktop HD */
418 | @media (min-width: 1200px) {}
419 |
--------------------------------------------------------------------------------
/js/webcam.js:
--------------------------------------------------------------------------------
1 | // WebcamJS v1.0.6
2 | // Webcam library for capturing JPEG/PNG images in JavaScript
3 | // Attempts getUserMedia, falls back to Flash
4 | // Author: Joseph Huckaby: http://github.com/jhuckaby
5 | // Based on JPEGCam: http://code.google.com/p/jpegcam/
6 | // Copyright (c) 2012 - 2015 Joseph Huckaby
7 | // Licensed under the MIT License
8 |
9 | (function(window) {
10 | var _userMedia;
11 |
12 | var Webcam = {
13 | version: '1.0.6',
14 |
15 | // globals
16 | protocol: location.protocol.match(/https/i) ? 'https' : 'http',
17 | loaded: false, // true when webcam movie finishes loading
18 | live: false, // true when webcam is initialized and ready to snap
19 | userMedia: true, // true when getUserMedia is supported natively
20 |
21 | params: {
22 | width: 0,
23 | height: 0,
24 | dest_width: 0, // size of captured image
25 | dest_height: 0, // these default to width/height
26 | image_format: 'jpeg', // image format (may be jpeg or png)
27 | jpeg_quality: 90, // jpeg image quality from 0 (worst) to 100 (best)
28 | force_flash: false, // force flash mode,
29 | flip_horiz: false, // flip image horiz (mirror mode)
30 | fps: 30, // camera frames per second
31 | upload_name: 'webcam', // name of file in upload post data
32 | constraints: null, // custom user media constraints,
33 | swfURL: '', // URI to webcam.swf movie (defaults to the js location)
34 | flashNotDetectedText: 'ERROR: No Adobe Flash Player detected. Webcam.js relies on Flash for browsers that do not support getUserMedia (like yours).'
35 | },
36 |
37 | hooks: {}, // callback hook functions
38 |
39 | init: function() {
40 | // initialize, check for getUserMedia support
41 | var self = this;
42 |
43 | // Setup getUserMedia, with polyfill for older browsers
44 | // Adapted from: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
45 | this.mediaDevices = (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) ?
46 | navigator.mediaDevices : ((navigator.mozGetUserMedia || navigator.webkitGetUserMedia) ? {
47 | getUserMedia: function(c) {
48 | return new Promise(function(y, n) {
49 | (navigator.mozGetUserMedia ||
50 | navigator.webkitGetUserMedia).call(navigator, c, y, n);
51 | });
52 | }
53 | } : null);
54 |
55 | window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
56 | this.userMedia = this.userMedia && !!this.mediaDevices && !!window.URL;
57 |
58 | // Older versions of firefox (< 21) apparently claim support but user media does not actually work
59 | if (navigator.userAgent.match(/Firefox\D+(\d+)/)) {
60 | if (parseInt(RegExp.$1, 10) < 21) this.userMedia = null;
61 | }
62 |
63 | // Make sure media stream is closed when navigating away from page
64 | if (this.userMedia) {
65 | window.addEventListener( 'beforeunload', function(event) {
66 | self.reset();
67 | } );
68 | }
69 | },
70 |
71 | attach: function(elem) {
72 | // create webcam preview and attach to DOM element
73 | // pass in actual DOM reference, ID, or CSS selector
74 | if (typeof(elem) == 'string') {
75 | elem = document.getElementById(elem) || document.querySelector(elem);
76 | }
77 | if (!elem) {
78 | return this.dispatch('error', "Could not locate DOM element to attach to.");
79 | }
80 | this.container = elem;
81 | elem.innerHTML = ''; // start with empty element
82 |
83 | // insert "peg" so we can insert our preview canvas adjacent to it later on
84 | var peg = document.createElement('div');
85 | elem.appendChild( peg );
86 | this.peg = peg;
87 |
88 | // set width/height if not already set
89 | if (!this.params.width) this.params.width = elem.offsetWidth;
90 | if (!this.params.height) this.params.height = elem.offsetHeight;
91 |
92 | // set defaults for dest_width / dest_height if not set
93 | if (!this.params.dest_width) this.params.dest_width = this.params.width;
94 | if (!this.params.dest_height) this.params.dest_height = this.params.height;
95 |
96 | this.userMedia = _userMedia === undefined ? this.userMedia : _userMedia;
97 | // if force_flash is set, disable userMedia
98 | if (this.params.force_flash) {
99 | _userMedia = this.userMedia;
100 | this.userMedia = null
101 | }
102 |
103 | // check for default fps
104 | if (typeof this.params.fps !== "number") this.params.fps = 30;
105 |
106 | // adjust scale if dest_width or dest_height is different
107 | var scaleX = this.params.width / this.params.dest_width;
108 | var scaleY = this.params.height / this.params.dest_height;
109 |
110 | if (this.userMedia) {
111 | // setup webcam video container
112 | var video = document.createElement('video');
113 | video.setAttribute('autoplay', 'autoplay');
114 | video.style.width = '' + this.params.dest_width + 'px';
115 | video.style.height = '' + this.params.dest_height + 'px';
116 |
117 | if ((scaleX != 1.0) || (scaleY != 1.0)) {
118 | elem.style.overflow = 'hidden';
119 | video.style.webkitTransformOrigin = '0px 0px';
120 | video.style.mozTransformOrigin = '0px 0px';
121 | video.style.msTransformOrigin = '0px 0px';
122 | video.style.oTransformOrigin = '0px 0px';
123 | video.style.transformOrigin = '0px 0px';
124 | video.style.webkitTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
125 | video.style.mozTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
126 | video.style.msTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
127 | video.style.oTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
128 | video.style.transform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
129 | }
130 |
131 | // add video element to dom
132 | elem.appendChild( video );
133 | this.video = video;
134 |
135 | // ask user for access to their camera
136 | var self = this;
137 | this.mediaDevices.getUserMedia({
138 | "audio": false,
139 | "video": this.params.constraints || {
140 | mandatory: {
141 | minWidth: this.params.dest_width,
142 | minHeight: this.params.dest_height
143 | }
144 | }
145 | })
146 | .then( function(stream) {
147 | // got access, attach stream to video
148 | video.src = window.URL.createObjectURL( stream ) || stream;
149 | self.stream = stream;
150 | self.loaded = true;
151 | self.live = true;
152 | self.dispatch('load');
153 | self.dispatch('live');
154 | self.flip();
155 | })
156 | .catch( function(err) {
157 | return self.dispatch('error', "Could not access webcam: " + err.name + ": " + err.message, err);
158 | });
159 | }
160 | else {
161 | // flash fallback
162 | window.Webcam = Webcam; // needed for flash-to-js interface
163 | var div = document.createElement('div');
164 | div.innerHTML = this.getSWFHTML();
165 | elem.appendChild( div );
166 | }
167 |
168 | // setup final crop for live preview
169 | if (this.params.crop_width && this.params.crop_height) {
170 | var scaled_crop_width = Math.floor( this.params.crop_width * scaleX );
171 | var scaled_crop_height = Math.floor( this.params.crop_height * scaleY );
172 |
173 | elem.style.width = '' + scaled_crop_width + 'px';
174 | elem.style.height = '' + scaled_crop_height + 'px';
175 | elem.style.overflow = 'hidden';
176 |
177 | elem.scrollLeft = Math.floor( (this.params.width / 2) - (scaled_crop_width / 2) );
178 | elem.scrollTop = Math.floor( (this.params.height / 2) - (scaled_crop_height / 2) );
179 | }
180 | else {
181 | // no crop, set size to desired
182 | elem.style.width = '' + this.params.width + 'px';
183 | elem.style.height = '' + this.params.height + 'px';
184 | }
185 | },
186 |
187 | reset: function() {
188 | // shutdown camera, reset to potentially attach again
189 | if (this.preview_active) this.unfreeze();
190 |
191 | // attempt to fix issue #64
192 | this.unflip();
193 |
194 | if (this.userMedia) {
195 | if (this.stream) {
196 | if (this.stream.getVideoTracks) {
197 | // get video track to call stop on it
198 | var tracks = this.stream.getVideoTracks();
199 | if (tracks && tracks[0] && tracks[0].stop) tracks[0].stop();
200 | }
201 | else if (this.stream.stop) {
202 | // deprecated, may be removed in future
203 | this.stream.stop();
204 | }
205 | }
206 | delete this.stream;
207 | delete this.video;
208 | }
209 |
210 | if (this.userMedia !== true) {
211 | // call for turn off camera in flash
212 | this.getMovie()._releaseCamera();
213 | }
214 |
215 | if (this.container) {
216 | this.container.innerHTML = '';
217 | delete this.container;
218 | }
219 |
220 | this.loaded = false;
221 | this.live = false;
222 | },
223 |
224 | set: function() {
225 | // set one or more params
226 | // variable argument list: 1 param = hash, 2 params = key, value
227 | if (arguments.length == 1) {
228 | for (var key in arguments[0]) {
229 | this.params[key] = arguments[0][key];
230 | }
231 | }
232 | else {
233 | this.params[ arguments[0] ] = arguments[1];
234 | }
235 | },
236 |
237 | on: function(name, callback) {
238 | // set callback hook
239 | name = name.replace(/^on/i, '').toLowerCase();
240 | if (!this.hooks[name]) this.hooks[name] = [];
241 | this.hooks[name].push( callback );
242 | },
243 |
244 | off: function(name, callback) {
245 | // remove callback hook
246 | name = name.replace(/^on/i, '').toLowerCase();
247 | if (this.hooks[name]) {
248 | if (callback) {
249 | // remove one selected callback from list
250 | var idx = this.hooks[name].indexOf(callback);
251 | if (idx > -1) this.hooks[name].splice(idx, 1);
252 | }
253 | else {
254 | // no callback specified, so clear all
255 | this.hooks[name] = [];
256 | }
257 | }
258 | },
259 |
260 | dispatch: function() {
261 | // fire hook callback, passing optional value to it
262 | var name = arguments[0].replace(/^on/i, '').toLowerCase();
263 | var args = Array.prototype.slice.call(arguments, 1);
264 |
265 | if (this.hooks[name] && this.hooks[name].length) {
266 | for (var idx = 0, len = this.hooks[name].length; idx < len; idx++) {
267 | var hook = this.hooks[name][idx];
268 |
269 | if (typeof(hook) == 'function') {
270 | // callback is function reference, call directly
271 | hook.apply(this, args);
272 | }
273 | else if ((typeof(hook) == 'object') && (hook.length == 2)) {
274 | // callback is PHP-style object instance method
275 | hook[0][hook[1]].apply(hook[0], args);
276 | }
277 | else if (window[hook]) {
278 | // callback is global function name
279 | window[ hook ].apply(window, args);
280 | }
281 | } // loop
282 | return true;
283 | }
284 | else if (name == 'error') {
285 | // default error handler if no custom one specified
286 | alert("Webcam.js Error: " + args[0]);
287 | }
288 |
289 | return false; // no hook defined
290 | },
291 |
292 | setSWFLocation: function(value) {
293 | // for backward compatibility.
294 | this.set('swfURL', value);
295 | },
296 |
297 |
298 | detectFlash: function() {
299 | // return true if browser supports flash, false otherwise
300 | // Code snippet borrowed from: https://github.com/swfobject/swfobject
301 | var SHOCKWAVE_FLASH = "Shockwave Flash",
302 | SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
303 | FLASH_MIME_TYPE = "application/x-shockwave-flash",
304 | win = window,
305 | nav = navigator,
306 | hasFlash = false;
307 |
308 | if (typeof nav.plugins !== "undefined" && typeof nav.plugins[SHOCKWAVE_FLASH] === "object") {
309 | var desc = nav.plugins[SHOCKWAVE_FLASH].description;
310 | if (desc && (typeof nav.mimeTypes !== "undefined" && nav.mimeTypes[FLASH_MIME_TYPE] && nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) {
311 | hasFlash = true;
312 | }
313 | }
314 | else if (typeof win.ActiveXObject !== "undefined") {
315 | try {
316 | var ax = new ActiveXObject(SHOCKWAVE_FLASH_AX);
317 | if (ax) {
318 | var ver = ax.GetVariable("$version");
319 | if (ver) hasFlash = true;
320 | }
321 | }
322 | catch (e) {;}
323 | }
324 |
325 | return hasFlash;
326 | },
327 |
328 | getSWFHTML: function() {
329 | // Return HTML for embedding flash based webcam capture movie
330 | var html = '',
331 | swfURL = this.params.swfURL;
332 |
333 | // make sure we aren't running locally (flash doesn't work)
334 | if (location.protocol.match(/file/)) {
335 | this.dispatch('error', "Flash does not work from local disk. Please run from a web server.");
336 | return 'ERROR: the Webcam.js Flash fallback does not work from local disk. Please run it from a web server. ';
337 | }
338 |
339 | // make sure we have flash
340 | if (!this.detectFlash()) {
341 | this.dispatch('error', "Adobe Flash Player not found. Please install from get.adobe.com/flashplayer and try again.");
342 | return '' + this.params.flashNotDetectedText + ' ';
343 | }
344 |
345 | // set default swfURL if not explicitly set
346 | if (!swfURL) {
347 | // find our script tag, and use that base URL
348 | var base_url = '';
349 | var scpts = document.getElementsByTagName('script');
350 | for (var idx = 0, len = scpts.length; idx < len; idx++) {
351 | var src = scpts[idx].getAttribute('src');
352 | if (src && src.match(/\/webcam(\.min)?\.js/)) {
353 | base_url = src.replace(/\/webcam(\.min)?\.js.*$/, '');
354 | idx = len;
355 | }
356 | }
357 | if (base_url) swfURL = base_url + '/webcam.swf';
358 | else swfURL = 'webcam.swf';
359 | }
360 |
361 | // if this is the user's first visit, set flashvar so flash privacy settings panel is shown first
362 | if (window.localStorage && !localStorage.getItem('visited')) {
363 | this.params.new_user = 1;
364 | localStorage.setItem('visited', 1);
365 | }
366 |
367 | // construct flashvars string
368 | var flashvars = '';
369 | for (var key in this.params) {
370 | if (flashvars) flashvars += '&';
371 | flashvars += key + '=' + escape(this.params[key]);
372 | }
373 |
374 | // construct object/embed tag
375 | html += ' ';
376 |
377 | return html;
378 | },
379 |
380 | getMovie: function() {
381 | // get reference to movie object/embed in DOM
382 | if (!this.loaded) return this.dispatch('error', "Flash Movie is not loaded yet");
383 | var movie = document.getElementById('webcam_movie_obj');
384 | if (!movie || !movie._snap) movie = document.getElementById('webcam_movie_embed');
385 | if (!movie) this.dispatch('error', "Cannot locate Flash movie in DOM");
386 | return movie;
387 | },
388 |
389 | freeze: function() {
390 | // show preview, freeze camera
391 | var self = this;
392 | var params = this.params;
393 |
394 | // kill preview if already active
395 | if (this.preview_active) this.unfreeze();
396 |
397 | // determine scale factor
398 | var scaleX = this.params.width / this.params.dest_width;
399 | var scaleY = this.params.height / this.params.dest_height;
400 |
401 | // must unflip container as preview canvas will be pre-flipped
402 | this.unflip();
403 |
404 | // calc final size of image
405 | var final_width = params.crop_width || params.dest_width;
406 | var final_height = params.crop_height || params.dest_height;
407 |
408 | // create canvas for holding preview
409 | var preview_canvas = document.createElement('canvas');
410 | preview_canvas.width = final_width;
411 | preview_canvas.height = final_height;
412 | var preview_context = preview_canvas.getContext('2d');
413 |
414 | // save for later use
415 | this.preview_canvas = preview_canvas;
416 | this.preview_context = preview_context;
417 |
418 | // scale for preview size
419 | if ((scaleX != 1.0) || (scaleY != 1.0)) {
420 | preview_canvas.style.webkitTransformOrigin = '0px 0px';
421 | preview_canvas.style.mozTransformOrigin = '0px 0px';
422 | preview_canvas.style.msTransformOrigin = '0px 0px';
423 | preview_canvas.style.oTransformOrigin = '0px 0px';
424 | preview_canvas.style.transformOrigin = '0px 0px';
425 | preview_canvas.style.webkitTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
426 | preview_canvas.style.mozTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
427 | preview_canvas.style.msTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
428 | preview_canvas.style.oTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
429 | preview_canvas.style.transform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
430 | }
431 |
432 | // take snapshot, but fire our own callback
433 | this.snap( function() {
434 | // add preview image to dom, adjust for crop
435 | preview_canvas.style.position = 'relative';
436 | preview_canvas.style.left = '' + self.container.scrollLeft + 'px';
437 | preview_canvas.style.top = '' + self.container.scrollTop + 'px';
438 |
439 | self.container.insertBefore( preview_canvas, self.peg );
440 | self.container.style.overflow = 'hidden';
441 |
442 | // set flag for user capture (use preview)
443 | self.preview_active = true;
444 |
445 | }, preview_canvas );
446 | },
447 |
448 | unfreeze: function() {
449 | // cancel preview and resume live video feed
450 | if (this.preview_active) {
451 | // remove preview canvas
452 | this.container.removeChild( this.preview_canvas );
453 | delete this.preview_context;
454 | delete this.preview_canvas;
455 |
456 | // unflag
457 | this.preview_active = false;
458 |
459 | // re-flip if we unflipped before
460 | this.flip();
461 | }
462 | },
463 |
464 | flip: function() {
465 | // flip container horiz (mirror mode) if desired
466 | if (this.params.flip_horiz) {
467 | var sty = this.container.style;
468 | sty.webkitTransform = 'scaleX(-1)';
469 | sty.mozTransform = 'scaleX(-1)';
470 | sty.msTransform = 'scaleX(-1)';
471 | sty.oTransform = 'scaleX(-1)';
472 | sty.transform = 'scaleX(-1)';
473 | sty.filter = 'FlipH';
474 | sty.msFilter = 'FlipH';
475 | }
476 | },
477 |
478 | unflip: function() {
479 | // unflip container horiz (mirror mode) if desired
480 | if (this.params.flip_horiz) {
481 | var sty = this.container.style;
482 | sty.webkitTransform = 'scaleX(1)';
483 | sty.mozTransform = 'scaleX(1)';
484 | sty.msTransform = 'scaleX(1)';
485 | sty.oTransform = 'scaleX(1)';
486 | sty.transform = 'scaleX(1)';
487 | sty.filter = '';
488 | sty.msFilter = '';
489 | }
490 | },
491 |
492 | savePreview: function(user_callback, user_canvas) {
493 | // save preview freeze and fire user callback
494 | var params = this.params;
495 | var canvas = this.preview_canvas;
496 | var context = this.preview_context;
497 |
498 | // render to user canvas if desired
499 | if (user_canvas) {
500 | var user_context = user_canvas.getContext('2d');
501 | user_context.drawImage( canvas, 0, 0 );
502 | }
503 |
504 | // fire user callback if desired
505 | user_callback(
506 | user_canvas ? null : canvas.toDataURL('image/' + params.image_format, params.jpeg_quality / 100 ),
507 | canvas,
508 | context
509 | );
510 |
511 | // remove preview
512 | this.unfreeze();
513 | },
514 |
515 | snap: function(user_callback, user_canvas) {
516 | // take snapshot and return image data uri
517 | var self = this;
518 | var params = this.params;
519 |
520 | if (!this.loaded) return this.dispatch('error', "Webcam is not loaded yet");
521 | // if (!this.live) return this.dispatch('error', "Webcam is not live yet");
522 | if (!user_callback) return this.dispatch('error', "Please provide a callback function or canvas to snap()");
523 |
524 | // if we have an active preview freeze, use that
525 | if (this.preview_active) {
526 | this.savePreview( user_callback, user_canvas );
527 | return null;
528 | }
529 |
530 | // create offscreen canvas element to hold pixels
531 | var canvas = document.createElement('canvas');
532 | canvas.width = this.params.dest_width;
533 | canvas.height = this.params.dest_height;
534 | var context = canvas.getContext('2d');
535 |
536 | // flip canvas horizontally if desired
537 | if (this.params.flip_horiz) {
538 | context.translate( params.dest_width, 0 );
539 | context.scale( -1, 1 );
540 | }
541 |
542 | // create inline function, called after image load (flash) or immediately (native)
543 | var func = function() {
544 | // render image if needed (flash)
545 | if (this.src && this.width && this.height) {
546 | context.drawImage(this, 0, 0, params.dest_width, params.dest_height);
547 | }
548 |
549 | // crop if desired
550 | if (params.crop_width && params.crop_height) {
551 | var crop_canvas = document.createElement('canvas');
552 | crop_canvas.width = params.crop_width;
553 | crop_canvas.height = params.crop_height;
554 | var crop_context = crop_canvas.getContext('2d');
555 |
556 | crop_context.drawImage( canvas,
557 | Math.floor( (params.dest_width / 2) - (params.crop_width / 2) ),
558 | Math.floor( (params.dest_height / 2) - (params.crop_height / 2) ),
559 | params.crop_width,
560 | params.crop_height,
561 | 0,
562 | 0,
563 | params.crop_width,
564 | params.crop_height
565 | );
566 |
567 | // swap canvases
568 | context = crop_context;
569 | canvas = crop_canvas;
570 | }
571 |
572 | // render to user canvas if desired
573 | if (user_canvas) {
574 | var user_context = user_canvas.getContext('2d');
575 | user_context.drawImage( canvas, 0, 0 );
576 | }
577 |
578 | // fire user callback if desired
579 | user_callback(
580 | user_canvas ? null : canvas.toDataURL('image/' + params.image_format, params.jpeg_quality / 100 ),
581 | canvas,
582 | context
583 | );
584 | };
585 |
586 | // grab image frame from userMedia or flash movie
587 | if (this.userMedia) {
588 | // native implementation
589 | context.drawImage(this.video, 0, 0, this.params.dest_width, this.params.dest_height);
590 |
591 | // fire callback right away
592 | func();
593 | }
594 | else {
595 | // flash fallback
596 | var raw_data = this.getMovie()._snap();
597 |
598 | // render to image, fire callback when complete
599 | var img = new Image();
600 | img.onload = func;
601 | img.src = 'data:image/'+this.params.image_format+';base64,' + raw_data;
602 | }
603 |
604 | return null;
605 | },
606 |
607 | configure: function(panel) {
608 | // open flash configuration panel -- specify tab name:
609 | // "camera", "privacy", "default", "localStorage", "microphone", "settingsManager"
610 | if (!panel) panel = "camera";
611 | this.getMovie()._configure(panel);
612 | },
613 |
614 | flashNotify: function(type, msg) {
615 | // receive notification from flash about event
616 | switch (type) {
617 | case 'flashLoadComplete':
618 | // movie loaded successfully
619 | this.loaded = true;
620 | this.dispatch('load');
621 | break;
622 |
623 | case 'cameraLive':
624 | // camera is live and ready to snap
625 | this.live = true;
626 | this.dispatch('live');
627 | this.flip();
628 | break;
629 |
630 | case 'error':
631 | // Flash error
632 | this.dispatch('error', msg);
633 | break;
634 |
635 | default:
636 | // catch-all event, just in case
637 | // console.log("webcam flash_notify: " + type + ": " + msg);
638 | break;
639 | }
640 | },
641 |
642 | b64ToUint6: function(nChr) {
643 | // convert base64 encoded character to 6-bit integer
644 | // from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
645 | return nChr > 64 && nChr < 91 ? nChr - 65
646 | : nChr > 96 && nChr < 123 ? nChr - 71
647 | : nChr > 47 && nChr < 58 ? nChr + 4
648 | : nChr === 43 ? 62 : nChr === 47 ? 63 : 0;
649 | },
650 |
651 | base64DecToArr: function(sBase64, nBlocksSize) {
652 | // convert base64 encoded string to Uintarray
653 | // from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
654 | var sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length,
655 | nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2,
656 | taBytes = new Uint8Array(nOutLen);
657 |
658 | for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
659 | nMod4 = nInIdx & 3;
660 | nUint24 |= this.b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4;
661 | if (nMod4 === 3 || nInLen - nInIdx === 1) {
662 | for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
663 | taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
664 | }
665 | nUint24 = 0;
666 | }
667 | }
668 | return taBytes;
669 | },
670 |
671 | upload: function(image_data_uri, target_url, callback) {
672 | // submit image data to server using binary AJAX
673 | var form_elem_name = this.params.upload_name || 'webcam';
674 |
675 | // detect image format from within image_data_uri
676 | var image_fmt = '';
677 | if (image_data_uri.match(/^data\:image\/(\w+)/))
678 | image_fmt = RegExp.$1;
679 | else
680 | throw "Cannot locate image format in Data URI";
681 |
682 | // extract raw base64 data from Data URI
683 | var raw_image_data = image_data_uri.replace(/^data\:image\/\w+\;base64\,/, '');
684 |
685 | // contruct use AJAX object
686 | var http = new XMLHttpRequest();
687 | http.open("POST", target_url, true);
688 |
689 | // setup progress events
690 | if (http.upload && http.upload.addEventListener) {
691 | http.upload.addEventListener( 'progress', function(e) {
692 | if (e.lengthComputable) {
693 | var progress = e.loaded / e.total;
694 | Webcam.dispatch('uploadProgress', progress, e);
695 | }
696 | }, false );
697 | }
698 |
699 | // completion handler
700 | var self = this;
701 | http.onload = function() {
702 | if (callback) callback.apply( self, [http.status, http.responseText, http.statusText] );
703 | Webcam.dispatch('uploadComplete', http.status, http.responseText, http.statusText);
704 | };
705 |
706 | // create a blob and decode our base64 to binary
707 | var blob = new Blob( [ this.base64DecToArr(raw_image_data) ], {type: 'image/'+image_fmt} );
708 |
709 | // stuff into a form, so servers can easily receive it as a standard file upload
710 | var form = new FormData();
711 | form.append( form_elem_name, blob, form_elem_name+"."+image_fmt.replace(/e/, '') );
712 |
713 | // send data to server
714 | http.send(form);
715 | }
716 |
717 | };
718 |
719 | Webcam.init();
720 |
721 | if (typeof define === 'function' && define.amd) {
722 | define( function() { return Webcam; } );
723 | }
724 | else if (typeof module === 'object' && module.exports) {
725 | module.exports = Webcam;
726 | }
727 | else {
728 | window.Webcam = Webcam;
729 | }
730 |
731 | }(window));
732 |
--------------------------------------------------------------------------------
/gnu_0001.gcode:
--------------------------------------------------------------------------------
1 | M05 S0
2 |
3 | G90
4 | G21
5 | G1 F3000
6 | G1 X31.9278 Y73.97
7 | G4 P0
8 | M03 S256
9 | G4 P0
10 | G1 F100.000000
11 | G3 X30.5159 Y73.5895 I0.2554 J-3.7572
12 | G3 X28.6712 Y71.8353 I1.8968 J-3.8417
13 | G2 X26.8042 Y70.4886 I-2.3743 J1.3241
14 | G2 X25.4271 Y70.5791 I-0.5137 J2.7047
15 | G3 X23.4279 Y70.9451 I-2.3164 J-7.01
16 | G3 X20.7422 Y70.1493 I-0.1851 J-4.305
17 | G2 X18.6105 Y70.0241 I-1.1656 J1.6362
18 | G2 X17.6236 Y72.0052 I0.933 J1.7011
19 | G2 X18.5423 Y74.8973 I9.2669 J-1.3516
20 | G2 X20.7639 Y77.237 I5.0422 J-2.5631
21 | G3 X23.2182 Y81.1184 I-2.4563 J4.2698
22 | G2 X24.5943 Y84.2037 I5.041 J-0.3988
23 | G3 X26.1872 Y87.4303 I-4.3912 J4.1744
24 | G3 X26.4343 Y91.1173 I-20.2701 J3.2105
25 | G2 X16.2813 Y94.5179 I4.5916 J30.5652
26 | G2 X8.0944 Y101.3656 I12.8607 J23.6939
27 | G2 X2.5664 Y111.0016 I28.2507 J22.6105
28 | G2 X0.2252 Y121.6512 I33.9837 J13.0532
29 | G2 X0.6388 Y132.5369 I52.3265 J3.4625
30 | G2 X3.7236 Y142.1349 I29.6776 J-4.2437
31 | G2 X9.768 Y150.1438 I26.8378 J-13.9692
32 | G2 X17.5709 Y155.7247 I24.1679 J-25.5449
33 | G2 X27.7287 Y159.1913 I16.1641 J-30.7487
34 | G2 X36.3725 Y159.8706 I7.873 J-44.8495
35 | G2 X44.5641 Y159.1728 I-1.0197 J-60.4048
36 | G2 X49.5404 Y157.4361 I-2.2115 J-14.3349
37 | G2 X54.9282 Y154.0517 I-37.2304 J-65.2485
38 | G3 X57.8694 Y153.1223 I2.9878 J4.3371
39 | G3 X60.5924 Y153.5495 I0.0745 J8.4187
40 | G3 X62.0832 Y154.3387 I-1.5973 J4.8197
41 | G2 X58.1786 Y148.5238 I-5.9343 J-0.2337
42 | G2 X51.4099 Y147.2394 I-7.3319 J20.1619
43 | G2 X44.6219 Y148.0943 I-0.5938 J22.6631
44 | G3 X38.3286 Y148.4445 I-3.9256 J-13.8211
45 | G3 X30.8345 Y146.4179 I6.4998 J-38.9043
46 | G3 X22.0068 Y138.8913 I6.1133 J-16.1102
47 | G3 X18.8916 Y130.7677 I24.3899 J-14.0121
48 | G3 X18.4026 Y124.4302 I23.2811 J-4.9842
49 | G3 X22.1555 Y116.3599 I12.0259 J0.6846
50 | G3 X26.1671 Y114.7254 I4.1115 J4.351
51 | G3 X29.0518 Y115.3954 I0.102 J6.1063
52 | G3 X31.8073 Y116.9934 I-13.85 J27.0575
53 | G3 X38.4073 Y123.5783 I-12.4342 J19.0628
54 | G2 X50.2697 Y136.7365 I48.4878 J-31.7863
55 | G2 X56.7406 Y140.2075 I12.1925 J-14.963
56 | G2 X62.78 Y141.1612 I6.3004 J-20.2987
57 | G2 X67.6773 Y140.7888 I0.3424 J-27.8871
58 | G2 X71.7852 Y139.6231 I-3.1072 J-18.7696
59 | G2 X76.4443 Y136.6952 I-6.0905 J-14.8629
60 | G3 X80.3114 Y133.8965 I14.9973 J16.6512
61 | G3 X82.2061 Y135.414 I-4.3097 J7.3224
62 | G2 X83.9964 Y136.9998 I9.3279 J-8.7273
63 | G2 X90.2367 Y140.1647 I12.8151 J-17.5339
64 | G2 X96.8954 Y140.8683 I5.0447 J-15.8817
65 | G2 X102.1464 Y139.4748 I-1.6276 J-16.7239
66 | G2 X106.6998 Y136.5644 I-7.5534 J-16.8343
67 | G2 X112.9065 Y129.8507 I-27.5925 J-31.7348
68 | G2 X117.5698 Y123.4896 I-681.0399 J-504.1634
69 | G3 X121.3047 Y118.7496 I61.8831 J44.9199
70 | G3 X126.3088 Y115.4654 I8.145 J6.956
71 | G3 X132.1647 Y117.5993 I1.5155 J4.9431
72 | G3 X134.0519 Y122.5602 I-10.6418 J6.8876
73 | G2 X134.436 Y124.9654 I208.9384 J-32.1336
74 | G3 X134.6544 Y127.597 I-16.0396 J2.6563
75 | G3 X134.5118 Y130.538 I-29.4662 J0.0447
76 | G3 X133.9302 Y133.6603 I-18.4649 J-1.8238
77 | G3 X132.8608 Y136.5732 I-18.2502 J-5.0475
78 | G3 X131.4783 Y139.1337 I-21.5849 J-10.001
79 | G3 X128.4284 Y142.9789 I-18.2729 J-11.3614
80 | G3 X124.4476 Y145.8706 I-11.0828 J-11.071
81 | G3 X121.3291 Y147.2681 I-15.754 J-30.9772
82 | G3 X116.9605 Y148.14 I-4.6482 J-11.9097
83 | G3 X113.0352 Y147.6751 I-0.3078 J-14.2041
84 | G2 X109.4023 Y147.0786 I-4.956 J18.8228
85 | G3 X103.6108 Y146.6276 I20.6068 J-302.0886
86 | G2 X98.1614 Y148.5884 I-0.6021 J6.8796
87 | G2 X96.7273 Y150.7927 I4.3077 J4.3713
88 | G2 X96.1246 Y153.1875 I10.125 J3.8213
89 | G3 X97.3336 Y152.4755 I2.8549 J3.465
90 | G3 X98.653 Y152.1667 I1.7136 J4.3487
91 | G3 X101.5553 Y152.9421 I0.3734 J4.4216
92 | G2 X104.0621 Y154.5428 I22.2326 J-32.0556
93 | G3 X106.2173 Y155.9118 I-18.0846 J30.8494
94 | G2 X108.9513 Y157.3785 I8.0526 J-11.7291
95 | G2 X116.1489 Y158.8921 I7.8551 J-19.4836
96 | G2 X123.4801 Y158.633 I1.7242 J-55.0637
97 | G2 X129.6094 Y157.3 I-2.8468 J-27.8463
98 | G2 X135.36 Y154.7271 I-10.7318 J-31.6994
99 | G2 X140.1533 Y151.169 I-11.9084 J-21.0505
100 | G2 X144.1656 Y146.7484 I-28.8524 J-30.2184
101 | G2 X147.596 Y141.2787 I-24.1639 J-18.9653
102 | G2 X149.757 Y135.1595 I-25.317 J-12.3818
103 | G2 X151.0984 Y124.7514 I-53.3018 J-12.1601
104 | G2 X149.8496 Y114.4249 I-34.2411 J-1.0979
105 | G2 X146.3769 Y106.4019 I-31.1112 J8.7031
106 | G2 X140.6155 Y99.2337 I-29.7105 J17.9801
107 | G2 X134.7256 Y95.3025 I-14.2267 J14.9372
108 | G2 X128.1255 Y93.2418 I-12.3449 J27.94
109 | G2 X128.3394 Y91.8076 I-16.3387 J-3.1692
110 | G3 X128.5858 Y90.6146 I6.1102 J0.6404
111 | G3 X129.3538 Y89.1706 I4.2325 J1.3248
112 | G3 X130.9644 Y88.6571 I1.1905 J0.9514
113 | G2 X131.585 Y88.7174 I0.4736 J-1.6528
114 | G2 X132.5189 Y88.3202 I-0.1394 J-1.6243
115 | G2 X132.9582 Y86.9984 I-0.906 J-1.035
116 | G2 X130.843 Y84.176 I-4.1092 J0.8757
117 | G2 X129.345 Y83.6701 I-2.2324 J4.1396
118 | G2 X127.0976 Y83.471 I-2.5766 J16.2998
119 | G2 X124.2411 Y83.4563 I-1.924 J96.4011
120 | G2 X121.1165 Y83.7431 I0.1856 J19.1892
121 | G2 X118.8265 Y84.7113 I0.9531 J5.4464
122 | G3 X116.3001 Y85.689 I-3.1194 J-4.3074
123 | G2 X112.1097 Y87.3157 I0.976 J8.725
124 | G3 X108.4749 Y89.8066 I-45.7189 J-62.8148
125 | G3 X107.2288 Y90.4593 I-4.2337 J-6.5678
126 | G2 X106.5236 Y90.8029 I2.4554 J5.9343
127 | G3 X107.0497 Y89.3069 I33.6131 J10.9799
128 | G2 X107.4756 Y87.887 I-10.0313 J-3.7824
129 | G2 X107.6291 Y86.4673 I-6.0674 J-1.3744
130 | G3 X107.7093 Y85.3391 I7.2419 J-0.0527
131 | G3 X107.9396 Y84.2729 I8.3923 J1.255
132 | G2 X108.1492 Y83.4044 I-10.6911 J-3.0405
133 | G2 X108.7313 Y82.7265 I-2.2673 J-2.5356
134 | G3 X109.6137 Y82.0949 I1.2508 J0.8154
135 | G3 X111.0778 Y82.0667 I0.7923 J3.1177
136 | G2 X112.559 Y82.3241 I4.0927 J-19.1659
137 | G3 X113.7118 Y82.6583 I-0.5403 J4.0185
138 | G2 X114.62 Y82.7691 I0.6274 J-1.3653
139 | G2 X115.5679 Y82.381 I-0.4775 J-2.5178
140 | G2 X116.4562 Y81.73 I-7.1787 J-10.7256
141 | G3 X117.1121 Y81.209 I67.0731 J83.7664
142 | G2 X117.9302 Y80.1196 I-1.6446 J-2.0871
143 | G2 X118.5411 Y78.0169 I-9.947 J-4.0297
144 | G2 X118.8486 Y75.2459 I-19.6063 J-3.5784
145 | G2 X118.7487 Y73.0081 I-13.1657 J-0.5338
146 | G2 X118.2929 Y71.1735 I-8.2498 J1.0759
147 | G2 X117.5715 Y69.8145 I-5.5334 J2.0664
148 | G2 X116.2397 Y68.2564 I-9.4336 J6.7152
149 | G2 X114.1693 Y66.3616 I-28.9732 J29.5792
150 | G2 X111.0841 Y64.1134 I-16.013 J18.7339
151 | G2 X111.5344 Y63.3713 I-7.4185 J-5.0093
152 | G3 X112.1732 Y62.5019 I3.4785 J1.8864
153 | G3 X113.3281 Y61.5899 I4.0067 J3.8865
154 | G2 X114.4425 Y60.6505 I-2.2786 J-3.8341
155 | G2 X115.0296 Y59.7675 I-3.3965 J-2.8946
156 | G2 X115.2401 Y58.9047 I-1.7515 J-0.8844
157 | G2 X115.1772 Y57.8538 I-7.3587 J-0.0874
158 | G2 X114.6548 Y56.5671 I-2.7353 J0.3612
159 | G2 X112.291 Y54.6709 I-4.8263 J3.5952
160 | G2 X109.6055 Y53.4793 I-153.488 J342.2709
161 | G2 X109.9449 Y50.6302 I-35.2244 J-5.641
162 | G2 X109.7305 Y47.766 I-9.3912 J-0.7373
163 | G2 X109.3366 Y46.079 I-675.5423 J156.87
164 | G2 X108.0327 Y44.4679 I-2.3206 J0.545
165 | G2 X106.0084 Y44.0983 I-1.7071 J3.6212
166 | G3 X103.6467 Y44.0059 I-0.7927 J-9.9734
167 | G3 X101.9531 Y43.6843 I4.5129 J-28.3808
168 | G2 X100.6283 Y43.4062 I-13.5423 J61.2237
169 | G2 X99.5242 Y41.9705 I-14.7878 J10.2301
170 | G3 X98.795 Y40.7556 I3.2743 J-2.7914
171 | G3 X98.6528 Y39.8175 I1.9759 J-0.7793
172 | G3 X98.839 Y38.8706 I4.0426 J0.3032
173 | G3 X99.5136 Y37.5141 I4.8873 J1.5842
174 | G2 X100.2467 Y35.9369 I-4.1127 J-2.8709
175 | G2 X100.4647 Y34.479 I-6.344 J-1.6937
176 | G2 X100.3128 Y33.0204 I-5.2617 J-0.1891
177 | G2 X99.8153 Y31.799 I-4.4989 J1.1204
178 | G2 X98.8624 Y30.5383 I-5.8071 J3.3985
179 | G2 X97.2094 Y29.3496 I-4.0408 J3.8759
180 | G3 X95.6683 Y28.3488 I2.9026 J-6.1565
181 | G2 X94.7083 Y27.5527 I-21.5807 J25.0454
182 | G3 X94.3012 Y26.4514 I0.7085 J-0.8879
183 | G3 X95.6713 Y23.6951 I5.6262 J1.078
184 | G3 X98.5119 Y21.7773 I5.2783 J4.7552
185 | G3 X100.0844 Y21.5636 I1.2743 J3.486
186 | G3 X102.0132 Y22.0355 I-0.5022 J6.2312
187 | G2 X101.2364 Y20.2628 I-2.8012 J0.1709
188 | G3 X100.0331 Y18.9322 I21.6742 J-20.8092
189 | G3 X103.0091 Y20.1925 I-3.6478 J12.7577
190 | G3 X105.3993 Y22.1004 I-5.0747 J8.8085
191 | G2 X104.4225 Y20.213 I-6.3838 J2.1073
192 | G2 X101.3463 Y16.9583 I-14.9299 J11.03
193 | G2 X99.15 Y15.4461 I-9.5084 J11.4586
194 | G3 X98.1024 Y14.8041 I8.2755 J-14.6797
195 | G3 X101.1123 Y14.5483 I2.6267 J13.0718
196 | G3 X103.4392 Y14.7894 I-0.4517 J15.7074
197 | G2 X102.1124 Y14.1592 I-5.8661 J10.6393
198 | G2 X99.4083 Y13.4867 I-3.7532 J9.318
199 | G2 X97.012 Y13.4682 I-1.2932 J12.3328
200 | G2 X94.8272 Y13.829 I1.3217 J14.7994
201 | G2 X92.5627 Y14.9198 I1.4202 J5.8446
202 | G3 X89.7032 Y16.7458 I-11.4282 J-14.7442
203 | G3 X90.0136 Y15.6884 I18.573 J4.8779
204 | G3 X90.8702 Y14.3641 I2.9182 J0.9484
205 | G3 X92.2753 Y13.4782 I3.2199 J3.5495
206 | G2 X94.3141 Y12.565 I-12.9227 J-31.5836
207 | G3 X91.7079 Y12.8096 I-7.6056 J-67.0137
208 | G2 X89.1244 Y13.1884 I1.3571 J18.257
209 | G2 X87.4285 Y13.6648 I3.3486 J15.1771
210 | G2 X86.1328 Y14.2052 I3.528 J10.2815
211 | G2 X84.8741 Y15.0072 I3.0953 J6.2469
212 | G3 X83.7136 Y15.8684 I-12.4857 J-15.6135
213 | G2 X84.1855 Y14.7353 I-6.2139 J-3.2531
214 | G3 X84.8721 Y13.6538 I2.3881 J0.7572
215 | G3 X86.062 Y12.9599 I2.1558 J2.3298
216 | G2 X87.4629 Y12.4007 I-3.2549 J-10.1885
217 | G3 X86.1457 Y12.3536 I-0.2507 J-11.4417
218 | G2 X84.7592 Y12.46 I-0.3833 J4.095
219 | G2 X83.4595 Y12.9122 I1.8952 J7.5399
220 | G2 X81.9745 Y13.7808 I3.3496 J7.4309
221 | G2 X80.5222 Y14.9544 I12.3892 J16.8167
222 | G2 X79.1698 Y16.2807 I12.2436 J13.8371
223 | G2 X77.7694 Y17.8742 I34.6692 J31.8804
224 | G2 X77.0069 Y19.1828 I3.411 J2.8641
225 | G2 X77.0285 Y20.3437 I1.4818 J0.5531
226 | G3 X77.2863 Y21.302 I-3.4905 J1.4529
227 | G2 X76.3832 Y20.8039 I-3.6701 J5.5864
228 | G3 X75.5692 Y20.1725 I0.9239 J-2.0316
229 | G3 X75.0794 Y19.3898 I3.0285 J-2.44
230 | G3 X74.9339 Y18.1758 I1.7529 J-0.8257
231 | G3 X75.5456 Y16.7207 I3.9729 J0.8139
232 | G2 X76.6287 Y15.0014 I-26.6293 J-17.976
233 | G2 X74.4107 Y16.9794 I21.992 J26.8933
234 | G2 X73.2988 Y18.9293 I2.8154 J2.8974
235 | G2 X73.6024 Y21.4497 I3.5348 J0.8525
236 | G2 X74.766 Y23.4898 I24.9441 J-12.8752
237 | G2 X75.4767 Y24.439 I6.1033 J-3.8286
238 | G3 X76.1498 Y25.3516 I-4.7458 J4.2048
239 | G3 X74.8507 Y26.5357 I-17.3902 J-17.7736
240 | G2 X73.6377 Y27.8095 I5.378 J6.336
241 | G2 X72.7648 Y29.3792 I4.8486 J3.7236
242 | G3 X71.8865 Y30.9018 I-5.0622 J-1.9057
243 | G3 X70.636 Y32.0642 I-4.891 J-4.0079
244 | G2 X69.3101 Y33.0907 I10.6527 J15.1291
245 | G3 X70.7673 Y30.3066 I30.646 J14.2662
246 | G2 X71.5735 Y28.2283 I-6.0935 J-3.5595
247 | G2 X71.3815 Y26.5245 I-2.6373 J-0.5656
248 | G2 X70.8268 Y25.5294 I-7.0872 J3.2991
249 | G2 X69.9842 Y24.8128 I-1.6476 J1.0837
250 | G3 X68.9813 Y24.2854 I3.6289 J-8.1162
251 | G2 X67.7702 Y24.0179 I-0.9947 J1.6286
252 | G3 X66.8336 Y23.5795 I-0.1119 J-0.9805
253 | G3 X66.4507 Y22.4923 I2.003 J-1.3164
254 | G3 X66.7069 Y21.4211 I1.6893 J-0.1623
255 | G1 X68.2986 Y18.9087
256 | G2 X67.2477 Y19.6075 I2.3888 J4.7321
257 | G2 X66.2463 Y20.6766 I4.2555 J4.9899
258 | G3 X65.5014 Y21.5749 I-9.0854 J-6.7762
259 | G2 X64.9963 Y22.6773 I1.4434 J1.3281
260 | G2 X64.9728 Y23.8201 I5.9974 J0.6951
261 | G2 X65.3889 Y24.9548 I2.2016 J-0.1637
262 | G2 X66.6812 Y25.8098 I1.7919 J-1.3042
263 | G3 X68.0443 Y26.5014 I-0.7188 J3.1061
264 | G3 X68.7838 Y27.3155 I-2.9546 J3.4267
265 | G3 X69.0301 Y28.1654 I-1.1037 J0.7805
266 | G3 X68.5821 Y29.118 I-1.387 J-0.0707
267 | G3 X67.6656 Y29.8793 I-8.182 J-8.9172
268 | G3 X64.6146 Y31.9655 I-25.3502 J-33.7985
269 | G2 X61.799 Y34.2721 I7.391 J11.8939
270 | G2 X60.6705 Y35.7665 I6.376 J5.9886
271 | G2 X60.2886 Y36.6614 I3.0728 J1.8402
272 | G2 X60.2899 Y37.5279 I1.5763 J0.4308
273 | G2 X60.7455 Y38.6476 I5.012 J-1.3866
274 | G2 X61.9699 Y40.0084 I3.5188 J-1.9349
275 | G3 X62.9093 Y41.4256 I-1.3186 J1.8941
276 | G3 X62.5227 Y42.3311 I-0.8392 J0.177
277 | G3 X61.6241 Y42.8076 I-3.929 J-6.3239
278 | G3 X60.3006 Y42.9022 I-0.7922 J-1.7777
279 | G2 X58.9531 Y43.1892 I-0.4023 J1.418
280 | G2 X58.6983 Y44.2627 I0.5914 J0.7074
281 | G3 X58.4138 Y45.4904 I-0.9737 J0.4212
282 | G3 X56.9022 Y45.9492 I-1.2799 J-1.4971
283 | G2 X55.1536 Y46.4364 I-0.2811 J2.3729
284 | G2 X54.1846 Y47.5912 I2.2096 J2.838
285 | G2 X53.6389 Y48.9129 I6.6312 J3.5114
286 | G2 X53.3705 Y50.5061 I5.9933 J1.8286
287 | G2 X53.5096 Y51.6567 I3.6836 J0.1385
288 | G2 X54.1038 Y52.4113 I1.2181 J-0.3478
289 | G3 X54.68 Y52.8499 I-1.3195 J2.3314
290 | G3 X55.0038 Y53.3454 I-1.0251 J1.0236
291 | G3 X54.875 Y54.0626 I-0.6483 J0.2538
292 | G3 X53.7675 Y54.3799 I-0.8051 J-0.7187
293 | G2 X51.8809 Y54.7312 I-0.5959 J2.0417
294 | G2 X51.2784 Y56.3522 I0.9835 J1.288
295 | G3 X50.8785 Y57.8105 I-1.6193 J0.3399
296 | G3 X49.525 Y58.3287 I-1.1955 J-1.0961
297 | G2 X48.4567 Y58.4656 I-0.2351 J2.4019
298 | G3 X47.93 Y58.5827 I-0.6978 J-1.896
299 | G2 X47.2276 Y59.1536 I0.0681 J0.8012
300 | G2 X46.8535 Y62.1726 I8.7689 J2.6195
301 | G3 X46.3358 Y65.5629 I-8.8334 J0.3859
302 | G3 X45.339 Y66.3083 I-1.0648 J-0.3847
303 | G2 X44.3758 Y67.0488 I0.065 J1.0813
304 | G2 X44.1291 Y69.3589 I5.1986 J1.7234
305 | G3 X44.1441 Y72.7658 I-16.4823 J1.776
306 | G1 X43.2029 Y78.4828
307 | G2 X38.6794 Y76.1684 I-11.9729 J17.8237
308 | G2 X34.2245 Y74.9615 I-8.935 J24.154
309 | G3 X34.1122 Y64.0507 I229.1533 J-7.8153
310 | G3 X36.0488 Y51.6725 I44.3546 J0.5989
311 | G3 X42.4423 Y39.8684 I32.3869 J9.9085
312 | G3 X52.9048 Y28.3471 I144.4171 J120.6333
313 | G2 X40.0814 Y40.6721 I43.6013 J58.1978
314 | G2 X34.159 Y50.9164 I29.0963 J23.655
315 | G2 X31.8215 Y62.859 I33.1129 J12.6814
316 | G2 X31.9278 Y73.97 I182.6939 J3.8075
317 | G1 X31.9278 Y73.97
318 | G4 P0
319 | M05 S0
320 | G1 F3000
321 | G1 X65.3161 Y74.101
322 | G4 P0
323 | M03 S256
324 | G4 P0
325 | G1 F100.000000
326 | G2 X66.8516 Y74.4802 I1.1723 J-1.448
327 | G3 X69.5695 Y74.1142 I4.2887 J21.5725
328 | G1 X66.3318 Y73.2851
329 | G3 X66.2367 Y72.7208 I2.763 J-0.7561
330 | G2 X66.0304 Y72.1841 I-0.9707 J0.0651
331 | G2 X65.5442 Y71.826 I-0.8928 J0.703
332 | G3 X64.958 Y71.5406 I1.3409 J-3.4998
333 | G3 X64.8748 Y72.9578 I-7.4662 J0.273
334 | G2 X65.3161 Y74.101 I1.2141 J0.1881
335 | G1 X65.3161 Y74.101
336 | G4 P0
337 | M05 S0
338 | G1 F3000
339 | G1 X77.8273 Y79.155
340 | G4 P0
341 | M03 S256
342 | G4 P0
343 | G1 F100.000000
344 | G2 X78.5538 Y81.9339 I6.9922 J-0.3437
345 | G2 X80.5349 Y83.9926 I4.2731 J-2.1295
346 | G2 X82.1653 Y84.7821 I8.7689 J-16.0308
347 | G2 X84.3356 Y85.3574 I3.0942 J-7.2907
348 | G2 X86.8631 Y85.4522 I1.8606 J-15.8612
349 | G2 X90.7313 Y84.5263 I-0.4326 J-10.3499
350 | G2 X92.7074 Y83.2954 I-3.7612 J-8.2401
351 | G3 X94.488 Y82.0509 I9.0699 J11.0807
352 | G2 X96.2254 Y81.0174 I-228.6815 J-386.4396
353 | G2 X97.9204 Y79.9221 I-14.8436 J-24.8279
354 | G2 X100.4633 Y77.7553 I-9.8533 J-14.1391
355 | G3 X102.2138 Y76.2978 I7.5657 J7.3069
356 | G3 X103.2632 Y75.9353 I1.2262 J1.8497
357 | G2 X104.5588 Y75.6888 I-0.4862 J-6.0819
358 | G2 X103.5048 Y75.4354 I-2.9249 J9.8511
359 | G2 X102.364 Y75.5076 I-0.4269 J2.3057
360 | G2 X100.8804 Y76.2065 I1.9147 J5.9884
361 | G2 X99.5962 Y77.1552 I6.6225 J10.3078
362 | G3 X98.0569 Y78.3753 I-20.3518 J-24.0945
363 | G3 X96.4763 Y79.4194 I-10.2159 J-13.7469
364 | G3 X95.0979 Y80.1268 I-7.3056 J-12.5395
365 | G2 X93.5586 Y80.9663 I4.5611 J10.1936
366 | G2 X91.92 Y82.1685 I10.0227 J15.3785
367 | G3 X90.3924 Y83.164 I-5.2353 J-6.3644
368 | G3 X88.3962 Y83.8113 I-3.1 J-6.1585
369 | G3 X86.2979 Y83.9494 I-1.7736 J-10.9357
370 | G3 X83.5891 Y83.6936 I0.6114 J-20.9426
371 | G3 X81.1287 Y82.5112 I0.7594 J-4.7312
372 | G3 X79.9012 Y80.7848 I3.3275 J-3.6655
373 | G3 X79.7049 Y78.9518 I2.9097 J-1.2387
374 | G3 X80.3431 Y79.8397 I-4.5067 J3.9125
375 | G2 X80.9442 Y80.5571 I2.4419 J-1.4355
376 | G2 X82.5161 Y81.2602 I1.9799 J-2.3178
377 | G2 X84.2145 Y81.2643 I0.8649 J-6.4048
378 | G2 X85.7514 Y80.5129 I-0.3456 J-2.6543
379 | G2 X86.6868 Y79.0303 I-2.7278 J-2.7573
380 | G2 X86.1391 Y79.4632 I5.8422 J7.9544
381 | G3 X85.4013 Y79.8837 I-1.485 J-1.748
382 | G3 X84.0071 Y80.0374 I-1.0369 J-3.0052
383 | G3 X82.6524 Y79.6147 I0.4227 J-3.7366
384 | G3 X81.8401 Y78.4045 I0.7359 J-1.3717
385 | G2 X81.6681 Y77.1159 I-22.3743 J2.3322
386 | G2 X81.4959 Y76.4662 I-3.3776 J0.5474
387 | G3 X81.2961 Y75.8708 I8.7278 J-3.2597
388 | G2 X80.6933 Y76.0964 I0.8289 J3.1322
389 | G2 X80.1579 Y76.4781 I0.9026 J1.8324
390 | G2 X80.1507 Y75.8236 I-8.2805 J-0.2359
391 | G3 X80.1988 Y75.0814 I3.2268 J-0.1633
392 | G3 X80.4202 Y74.2668 I4.8257 J0.8741
393 | G2 X80.7235 Y73.3632 I-16.1464 J-5.9219
394 | G2 X79.5776 Y74.5392 I45.339 J45.3227
395 | G2 X78.6254 Y75.8967 I4.0789 J3.8738
396 | G2 X78.0113 Y77.4951 I7.8915 J3.9491
397 | G2 X77.8273 Y79.155 I5.0765 J1.403
398 | G1 X77.8273 Y79.155
399 | G4 P0
400 | M05 S0
401 | G1 F3000
402 | G1 X88.0076 Y77.4391
403 | G4 P0
404 | M03 S256
405 | G4 P0
406 | G1 F100.000000
407 | G2 X89.347 Y77.2599 I-0.3436 J-7.663
408 | G2 X90.3763 Y76.8264 I-0.6942 J-3.0871
409 | G3 X91.2239 Y76.2953 I16.949 J26.1082
410 | G2 X92.0696 Y75.6267 I-2.2307 J-3.6906
411 | G2 X93.7299 Y73.4631 I-8.0109 J-7.8665
412 | G2 X94.7578 Y70.9028 I-7.8971 J-4.6568
413 | G2 X95.0288 Y69.0434 I-10.6499 J-2.5015
414 | G3 X95.1707 Y66.8865 I154.4579 J9.0801
415 | G2 X94.6226 Y68.8113 I41.2473 J12.7859
416 | G3 X93.9602 Y70.5921 I-9.0433 J-2.35
417 | G3 X92.2371 Y73.1252 I-9.8878 J-4.8734
418 | G3 X89.7385 Y74.9129 I-5.3818 J-4.882
419 | G3 X88.8521 Y75.1083 I-0.9463 J-2.1852
420 | G3 X88.383 Y75.0817 I-0.0724 J-2.8755
421 | G3 X88.6234 Y74.7291 I2.9875 J1.7791
422 | G2 X88.7964 Y74.2474 I-0.6524 J-0.5062
423 | G2 X88.7373 Y73.6515 I-2.3338 J-0.0694
424 | G2 X88.0974 Y72.8493 I-1.1591 J0.2683
425 | G2 X86.5229 Y72.6868 I-1.0106 J2.0828
426 | G2 X85.1803 Y73.3943 I0.7808 J3.1095
427 | G2 X84.4062 Y74.7016 I1.636 J1.8516
428 | G2 X84.5366 Y76.2794 I2.5751 J0.5816
429 | G2 X86.0886 Y77.4096 I1.6887 J-0.6882
430 | G2 X88.0076 Y77.4391 I1.2061 J-16.0484
431 | G1 X88.0076 Y77.4391
432 | G4 P0
433 | M05 S0
434 | G1 F3000
435 | G1 X79.1876 Y94.2426
436 | G4 P0
437 | M03 S256
438 | G4 P0
439 | G1 F100.000000
440 | G3 X79.8222 Y95.7464 I-3.5178 J2.3702
441 | G2 X80.2939 Y97.4941 I15.2985 J-3.192
442 | G3 X80.2358 Y95.359 I13.711 J-1.4415
443 | G2 X79.7625 Y93.6581 I-2.7881 J-0.1404
444 | G2 X78.411 Y92.8468 I-1.5443 J1.041
445 | G3 X76.9696 Y92.5606 I0.8252 J-7.9287
446 | G2 X78.1103 Y93.283 I4.7199 J-6.1907
447 | G3 X79.1876 Y94.2426 I-1.3407 J2.5896
448 | G1 X79.1876 Y94.2426
449 | G4 P0
450 | M05 S0
451 | G1 F3000
452 | G1 X71.0706 Y104.1438
453 | G4 P0
454 | M03 S256
455 | G4 P0
456 | G1 F100.000000
457 | G2 X72.4559 Y104.0987 I0.5055 J-5.7673
458 | G3 X73.7517 Y104.0366 I0.9436 J6.1375
459 | G3 X74.8415 Y104.2048 I-0.3249 J5.7188
460 | G2 X75.7826 Y104.4114 I3.5548 J-13.9476
461 | G2 X75.6767 Y106.6052 I19.1962 J2.0262
462 | G3 X74.6777 Y108.5818 I-2.4135 J0.021
463 | G3 X72.4708 Y109.0294 I-1.5967 J-2.208
464 | G2 X70.2759 Y108.5405 I-37.7453 J164.2973
465 | G3 X67.5187 Y107.619 I2.7849 J-12.917
466 | G2 X64.7909 Y106.464 I-19.2572 J41.6813
467 | G2 X67.1456 Y108.0351 I37.9472 J-54.3237
468 | G2 X69.7636 Y109.2342 I5.6423 J-8.8607
469 | G2 X72.2834 Y109.8331 I6.3482 J-21.1114
470 | G2 X74.8733 Y109.7174 I1.0354 J-5.8713
471 | G2 X75.4352 Y109.3899 I-0.3243 J-1.2023
472 | G2 X75.8706 Y108.873 I-3.0507 J-3.0115
473 | G2 X76.8825 Y106.5035 I-4.8433 J-3.469
474 | G2 X77.3153 Y104.0103 I-90.6614 J-17.0249
475 | G3 X77.7598 Y103.3947 I5.8374 J3.7461
476 | G2 X78.1586 Y102.7773 I-2.6873 J-2.1735
477 | G2 X78.4416 Y101.9571 I-2.9047 J-1.4611
478 | G2 X78.5963 Y100.9581 I-11.086 J-2.2288
479 | G2 X78.3174 Y101.5391 I1.7071 J1.1771
480 | G3 X77.6461 Y102.2665 I-1.0812 J-0.3245
481 | G3 X76.242 Y102.4147 I-0.9737 J-2.4998
482 | G2 X74.4118 Y102.1705 I-5.1972 J31.9773
483 | G2 X75.2524 Y101.2405 I-1.7525 J-2.4287
484 | G2 X75.6691 Y99.7609 I-2.695 J-1.5576
485 | G2 X74.8786 Y97.8865 I-2.4708 J-0.0618
486 | G2 X73.167 Y97.1376 I-1.9311 J2.0831
487 | G2 X71.0839 Y97.5377 I-0.3108 J4.0049
488 | G2 X69.7103 Y98.932 I1.3098 J2.6642
489 | G2 X69.543 Y100.0439 I1.7617 J0.8337
490 | G3 X69.596 Y101.0738 I-5.5674 J0.803
491 | G3 X67.5768 Y100.6463 I0.516 J-7.4201
492 | G3 X65.887 Y99.6757 I1.9226 J-5.303
493 | G3 X67.1006 Y98.1657 I10.2597 J7.0031
494 | G3 X68.7078 Y96.9395 I4.5076 J4.242
495 | G3 X69.9433 Y96.3565 I6.7989 J12.808
496 | G3 X71.3929 Y95.9379 I2.5756 J6.1995
497 | G3 X73.171 Y95.7078 I3.7812 J22.2294
498 | G3 X75.0361 Y95.7669 I0.6887 J7.7223
499 | G3 X76.3206 Y96.1712 I-0.6718 J4.3773
500 | G3 X77.4296 Y96.933 I-2.0655 J4.1947
501 | G3 X78.1925 Y98.2339 I-1.766 J1.9097
502 | G2 X78.5695 Y99.4674 I10.3864 J-2.5006
503 | G2 X78.4329 Y98.1536 I-41.8174 J3.6866
504 | G2 X78.1248 Y97.1441 I-2.9788 J0.3574
505 | G2 X76.313 Y95.4318 I-3.3241 J1.7024
506 | G2 X73.9304 Y94.9239 I-2.4011 J5.4218
507 | G2 X71.1403 Y95.1808 I-0.048 J14.7572
508 | G2 X68.4383 Y95.987 I2.5459 J13.4631
509 | G2 X66.0984 Y97.2883 I4.4811 J10.8124
510 | G2 X64.503 Y99.3505 I2.6551 J3.7023
511 | G2 X64.3258 Y100.7969 I2.7863 J1.0755
512 | G3 X64.3944 Y102.3525 I-9.6157 J1.2033
513 | G2 X66.4781 Y103.199 I3.1194 J-4.6909
514 | G2 X68.7352 Y103.5957 I19.3326 J-103.3729
515 | G3 X69.9329 Y103.9001 I-1.1756 J7.1359
516 | G2 X71.0706 Y104.1438 I1.5523 J-4.4683
517 | G1 X71.0706 Y104.1438
518 | G4 P0
519 | M05 S0
520 | G1 F3000
521 | G1 X75.8969 Y115.9319
522 | G4 P0
523 | M03 S256
524 | G4 P0
525 | G1 F100.000000
526 | G3 X77.4407 Y115.119 I44.7705 J83.1526
527 | G3 X78.7225 Y114.7915 I1.3557 J2.6333
528 | G3 X79.617 Y115.1507 I0.0304 J1.2178
529 | G2 X80.187 Y115.6192 I2.608 J-2.5912
530 | G3 X81.3979 Y111.9435 I89.522 J27.4541
531 | G3 X83.008 Y108.4375 I19.8819 J7.0084
532 | G3 X83.675 Y107.7324 I1.8033 J1.0378
533 | G2 X84.2614 Y107.0388 I-0.8639 J-1.325
534 | G2 X84.7332 Y105.2928 I-5.6877 J-2.4735
535 | G3 X85.2111 Y103.1038 I11.4404 J1.3511
536 | G3 X85.8616 Y101.4915 I11.7073 J3.7862
537 | G2 X86.5141 Y100.0682 I-28.887 J-14.1043
538 | G2 X84.6144 Y102.7778 I430.8 J304.0575
539 | G2 X83.3715 Y104.9239 I12.2152 J8.5071
540 | G2 X82.9801 Y106.291 I3.9759 J1.8779
541 | G3 X82.6533 Y107.5756 I-4.9752 J-0.5819
542 | G3 X81.7153 Y109.6455 I-24.1779 J-9.7086
543 | G2 X80.3995 Y112.3288 I101.2908 J51.3364
544 | G2 X79.4905 Y112.2186 I-5.3286 J40.1433
545 | G2 X78.7866 Y112.2856 I-0.1902 J1.7324
546 | G2 X78.4285 Y112.6433 I0.1598 J0.518
547 | G3 X78.0898 Y113.1278 I-0.9253 J-0.2864
548 | G3 X77.4715 Y113.3684 I-0.7298 J-0.9606
549 | G2 X76.5799 Y113.7487 I0.1466 J1.5791
550 | G2 X76.0604 Y114.6431 I1.0407 J1.2025
551 | G2 X75.8969 Y115.9319 I9.2786 J1.8319
552 | G1 X75.8969 Y115.9319
553 | G4 P0
554 | M05 S0
555 | G1 F3000
556 | G1 X78.8433 Y127.807
557 | G4 P0
558 | M03 S256
559 | G4 P0
560 | G1 F100.000000
561 | G3 X78.856 Y125.2571 I13.13 J-1.2094
562 | G3 X79.25 Y122.7383 I23.8009 J2.4323
563 | G3 X79.9681 Y120.7468 I7.5583 J1.6002
564 | G3 X81.3077 Y119.1815 I4.1001 J2.1529
565 | G3 X84.7646 Y117.5657 I5.6858 J7.6591
566 | G2 X87.3077 Y116.5706 I-2.3334 J-9.7102
567 | G2 X88.7819 Y115.5819 I-5.3894 J-9.6289
568 | G2 X89.7131 Y114.2999 I-1.8389 J-2.3148
569 | G2 X89.6339 Y112.8959 I-1.6404 J-0.6116
570 | G2 X88.7987 Y112.0271 I-1.8418 J0.9347
571 | G3 X90.4317 Y112.6022 I0.2726 J1.832
572 | G3 X90.7991 Y114.6114 I-1.401 J1.2943
573 | G3 X89.8796 Y115.4462 I-1.3255 J-0.5363
574 | G2 X88.786 Y116.3031 I0.5363 J1.8108
575 | G2 X88.4622 Y117.384 I2.0687 J1.2086
576 | G2 X88.5721 Y118.42 I3.2858 J0.1754
577 | G2 X90.1593 Y120.2692 I2.7368 J-0.7434
578 | G3 X92.3259 Y121.8555 I-2.555 J5.7623
579 | G3 X93.5632 Y124.1098 I-4.3711 J3.866
580 | G3 X93.4455 Y126.6928 I-3.8869 J1.1169
581 | G3 X90.086 Y130.5985 I-7.2086 J-2.8028
582 | G3 X85.6305 Y132.8407 I-22.7173 J-39.5934
583 | G3 X84.0991 Y133.3428 I-3.4103 J-7.8152
584 | G2 X82.9313 Y133.6493 I3.8588 J17.0811
585 | G2 X85.4784 Y132.0349 I-21.904 J-37.3755
586 | G2 X87.6458 Y129.298 I-3.3203 J-4.8562
587 | G2 X87.9158 Y126.8379 I-4.5052 J-1.7392
588 | G3 X87.7759 Y124.7697 I12.4642 J-1.8816
589 | G3 X88.4003 Y123.7525 I1.1692 J0.0174
590 | G2 X89.3346 Y123.0358 I-1.6234 J-3.0834
591 | G2 X89.5784 Y122.4149 I-0.6709 J-0.6217
592 | G2 X89.3843 Y121.6407 I-1.6345 J-0.0015
593 | G3 X89.1659 Y122.3779 I-1.7376 J-0.1137
594 | G3 X88.6833 Y122.9144 I-1.429 J-0.8004
595 | G3 X87.7259 Y123.4304 I-2.5757 J-3.6331
596 | G2 X86.8432 Y124.3314 I0.5574 J1.429
597 | G2 X86.6903 Y126.4906 I3.6763 J1.3453
598 | G3 X86.1325 Y129.114 I-3.2246 J0.6854
599 | G3 X84.4889 Y130.9876 I-10.9993 J-7.9915
600 | G3 X82.211 Y131.9258 I-2.3548 J-2.483
601 | G3 X81.122 Y131.8446 I-0.1279 J-5.6316
602 | G3 X79.9341 Y131.5671 I1.7931 J-10.3548
603 | G1 X78.7843 Y132.9508
604 | G1 X78.7578 Y132.9689
605 | G3 X75.573 Y135.7799 I-86.2093 J-94.462
606 | G3 X71.538 Y138.3294 I-10.869 J-12.7343
607 | G3 X67.4044 Y139.5929 I-7.1465 J-15.9857
608 | G3 X62.8785 Y139.9347 I-4.0086 J-22.9498
609 | G3 X57.8158 Y139.2713 I0.5233 J-23.6443
610 | G3 X51.0266 Y135.7795 I3.8467 J-15.8253
611 | G3 X39.5957 Y122.7491 I40.8411 J-47.357
612 | G2 X32.718 Y115.814 I-20.53 J13.4819
613 | G2 X29.5722 Y114.1091 I-10.7316 J16.0475
614 | G2 X25.9896 Y113.3753 I-3.5849 J8.3894
615 | G2 X20.9617 Y115.4155 I-0.0018 J7.2108
616 | G2 X17.0688 Y124.2019 I8.9732 J9.2313
617 | G2 X17.6427 Y130.9076 I28.0966 J0.9729
618 | G2 X20.9581 Y139.6008 I28.7645 J-5.9915
619 | G2 X30.0473 Y147.5868 I16.3346 J-9.4257
620 | G2 X38.3345 Y149.8234 I12.6498 J-30.3989
621 | G2 X45.9103 Y149.3301 I2.5578 J-19.1353
622 | G3 X51.4897 Y148.5859 I5.6279 J20.9076
623 | G3 X57.5501 Y149.4258 I0.0506 J21.9203
624 | G3 X60.9671 Y152.6002 I-1.4092 J4.943
625 | G2 X60.1604 Y152.2603 I-1.6246 J2.7284
626 | G2 X57.3456 Y151.9664 I-2.3393 J8.776
627 | G2 X54.0069 Y153.1267 I0.3324 J6.3399
628 | G3 X48.5292 Y156.4032 I-23.8286 J-33.6197
629 | G3 X43.2775 Y157.9593 I-7.0672 J-14.2116
630 | G3 X36.1933 Y158.4329 I-8.4857 J-73.7003
631 | G3 X28.7245 Y158.0157 I-0.9469 J-50.1109
632 | G3 X18.8651 Y154.8275 I3.7197 J-28.3418
633 | G3 X11.1339 Y149.342 I18.4902 J-34.2512
634 | G3 X4.9536 Y141.4903 I20.5168 J-22.5074
635 | G3 X1.8344 Y132.2706 I24.3925 J-13.3899
636 | G3 X1.4295 Y121.8239 I46.3665 J-7.0284
637 | G3 X3.8935 Y111.1958 I35.2723 J2.5779
638 | G3 X9.1014 Y102.3511 I31.9688 J12.8682
639 | G3 X16.4383 Y96.1612 I19.905 J16.1502
640 | G3 X26.8582 Y92.7299 I13.927 J24.7556
641 | G1 X28.6303 Y100.5463
642 | G1 X25.4669 Y96.0065
643 | G1 X25.5451 Y101.0557
644 | G1 X22.6836 Y97.5051
645 | G1 X21.4286 Y102.3204
646 | G1 X19.1104 Y98.4599
647 | G1 X17.9589 Y103.8362
648 | G1 X14.5996 Y101.1192
649 | G1 X15.663 Y105.5555
650 | G1 X11.218 Y105.0636
651 | G1 X13.2599 Y108.1471
652 | G1 X9.2069 Y108.0977
653 | G1 X11.5652 Y112.2145
654 | G1 X7.9691 Y112.7855
655 | G1 X10.8365 Y116.5297
656 | G1 X6.4338 Y117.835
657 | G1 X10.079 Y121.3255
658 | G1 X6.4798 Y124.2586
659 | G1 X9.295 Y126.4481
660 | G1 X6.6624 Y129.9511
661 | G1 X9.4705 Y133.22
662 | G1 X8.4224 Y137.5369
663 | G1 X10.8069 Y139.6155
664 | G1 X11.5166 Y144.549
665 | G1 X14.1927 Y145.8929
666 | G1 X16.495 Y149.7441
667 | G1 X20.7507 Y150.196
668 | G1 X22.8504 Y153.66
669 | G1 X27.1247 Y153.4424
670 | G1 X31.1638 Y155.6378
671 | G1 X35.3528 Y154.6621
672 | G1 X40.1111 Y156.0992
673 | G1 X43.6352 Y155.2734
674 | G1 X48.2343 Y154.5975
675 | G1 X52.6745 Y151.0472
676 | G1 X45.8636 Y153.4246
677 | G1 X42.4375 Y151.7818
678 | G1 X39.6054 Y153.5104
679 | G1 X37.6555 Y152.1859
680 | G1 X34.2053 Y151.8405
681 | G1 X31.1113 Y152.0403
682 | G1 X28.8558 Y149.2869
683 | G1 X24.2581 Y149.2395
684 | G1 X22.6181 Y145.5303
685 | G1 X18.5299 Y144.096
686 | G1 X18.1475 Y139.8325
687 | G1 X15.2157 Y137.5358
688 | G1 X16.1925 Y133.5237
689 | G1 X13.6607 Y129.3567
690 | G1 X15.6029 Y125.7118
691 | G1 X13.6914 Y122.3759
692 | G1 X16.2345 Y120.7165
693 | G1 X15.6577 Y115.3548
694 | G1 X19.1945 Y114.4635
695 | G1 X19.9912 Y110.4862
696 | G1 X23.8452 Y110.8867
697 | G1 X26.2396 Y108.1615
698 | G1 X29.199 Y111.0512
699 | G3 X35.4301 Y114.8298 I-19.7152 J39.5379
700 | G3 X41.0202 Y119.7936 I-22.3371 J30.7851
701 | G3 X47.3758 Y127.0413 I-134.5873 J124.4325
702 | G2 X54.925 Y133.301 I20.5097 J-17.0524
703 | G2 X61.4605 Y135.7436 I11.362 J-20.436
704 | G2 X68.3635 Y135.8707 I3.7827 J-17.9306
705 | G2 X73.822 Y133.1562 I-1.812 J-10.4892
706 | G3 X78.3528 Y129.0973 I97.1312 J103.8664
707 | G2 X78.8185 Y129.825 I5.853 J-3.2331
708 | G2 X79.4261 Y130.4613 I2.7692 J-2.0359
709 | G2 X79.0844 Y129.1019 I-23.0678 J5.0755
710 | G3 X78.8433 Y127.807 I6.9094 J-1.9564
711 | G1 X78.8433 Y127.807
712 | G4 P0
713 | M05 S0
714 | G1 F3000
715 | G1 X60.6676 Y112.1874
716 | G4 P0
717 | M03 S256
718 | G4 P0
719 | G1 F100.000000
720 | G2 X60.7837 Y112.887 I3.7687 J-0.2661
721 | G3 X60.8612 Y113.2319 I-4.5585 J1.2052
722 | G3 X59.1469 Y112.7753 I-0.4599 J-1.7196
723 | G3 X57.6278 Y110.6513 I5.5032 J-5.5412
724 | G3 X57.4479 Y109.6843 I1.6637 J-0.8097
725 | G2 X57.2412 Y108.9983 I-0.9676 J-0.0825
726 | G2 X56.5665 Y108.5653 I-0.9686 J0.767
727 | G3 X55.6212 Y108.1195 I0.6241 J-2.5482
728 | G3 X54.6897 Y107.2038 I2.883 J-3.8645
729 | G2 X53.8037 Y106.2884 I-4.5496 J3.5171
730 | G2 X51.7804 Y105.0364 I-5.5642 J6.731
731 | G3 X49.6186 Y104.0388 I32.5127 J-73.2988
732 | G2 X51.4698 Y105.2717 I13.7218 J-18.5978
733 | G3 X52.9872 Y106.8038 I-2.2312 J3.7273
734 | G3 X53.2881 Y107.8142 I-1.9079 J1.1181
735 | G2 X53.7444 Y108.8343 I1.5354 J-0.0748
736 | G2 X54.3562 Y109.4246 I26.6265 J-26.9847
737 | G2 X55.0364 Y109.7739 I0.9431 J-0.9996
738 | G3 X55.4833 Y110.3344 I-0.1057 J0.5427
739 | G2 X55.6178 Y111.2109 I2.4152 J0.078
740 | G2 X56.0338 Y111.9693 I2.4868 J-0.8707
741 | G3 X56.6592 Y112.7874 I-29.163 J22.9425
742 | G2 X57.3593 Y113.72 I92.1832 J-68.4662
743 | G2 X58.4883 Y114.5587 I2.0066 J-1.5222
744 | G2 X60.1068 Y114.6764 I1.0113 J-2.7181
745 | G3 X61.3159 Y114.7156 I0.5256 J2.4548
746 | G3 X61.7431 Y115.1886 I-0.1633 J0.5768
747 | G2 X62.0593 Y115.6489 I0.6628 J-0.1165
748 | G2 X62.9324 Y115.8723 I0.811 J-1.3514
749 | G3 X64.0678 Y116.1075 I0.0947 J2.4016
750 | G3 X65.3946 Y117.168 I-1.6413 J3.4135
751 | G3 X66.3787 Y118.4883 I-21.6474 J17.1618
752 | G2 X66.3284 Y115.7172 I-21.204 J-1.0017
753 | G2 X65.7135 Y113.02 I-9.8282 J0.8221
754 | G2 X64.2613 Y110.4502 I-9.2668 J3.5416
755 | G2 X61.6783 Y108.2236 I-6.9085 J5.4028
756 | G2 X60.3993 Y107.6881 I-2.8794 J5.0818
757 | G3 X59.3812 Y107.3609 I4.3831 J-15.3838
758 | G2 X59.9769 Y108.0178 I3.4496 J-2.5291
759 | G3 X60.5609 Y108.9695 I-1.303 J1.4547
760 | G3 X60.6947 Y110.7243 I-4.6579 J1.2376
761 | G2 X60.6676 Y112.1874 I8.1856 J0.8835
762 | G1 X60.6676 Y112.1874
763 | G4 P0
764 | M05 S0
765 | G1 F3000
766 | G1 X95.8376 Y103.2531
767 | G4 P0
768 | M03 S256
769 | G4 P0
770 | G1 F100.000000
771 | G2 X98.0873 Y104.1025 I11.3127 J-26.5602
772 | G2 X100.4375 Y104.5567 I2.934 J-8.8734
773 | G2 X101.6393 Y104.5429 I0.5081 J-8.0831
774 | G3 X102.8525 Y104.4633 I2.5752 J29.9585
775 | G2 X103.771 Y105.6822 I12.8431 J-8.7225
776 | G3 X104.451 Y106.9787 I-2.673 J2.2284
777 | G3 X104.7145 Y108.9743 I-6.9808 J1.9369
778 | G3 X104.2233 Y111.4285 I-6.6449 J-0.0538
779 | G3 X102.6304 Y113.6682 I-5.5615 J-2.2691
780 | G2 X101.1095 Y115.1096 I18.8251 J21.3871
781 | G2 X100.2693 Y116.755 I2.2054 J2.1633
782 | G3 X99.866 Y119.114 I-1316.1435 J-223.7875
783 | G3 X99.6189 Y120.0748 I-5.9882 J-1.0279
784 | G2 X99.3363 Y121.0709 I8.5863 J2.9743
785 | G3 X96.8181 Y121.3472 I-3.6505 J-21.6616
786 | G3 X93.9394 Y121.3495 I-1.4621 J-28.3295
787 | G3 X95.2117 Y122.6961 I-13.0427 J13.5978
788 | G3 X96.0428 Y124.4065 I-2.8575 J2.4455
789 | G3 X96.0963 Y126.54 I-6.1434 J1.2217
790 | G3 X95.3285 Y128.608 I-5.2478 J-0.7721
791 | G3 X93.9318 Y130.2961 I-7.3528 J-4.6614
792 | G3 X92.224 Y131.8448 I-46.7582 J-49.8469
793 | G3 X90.2493 Y133.2475 I-7.852 J-8.9624
794 | G2 X88.4355 Y134.4404 I8.1275 J14.3338
795 | G3 X90.5498 Y135.2861 I-10.4688 J29.2373
796 | G2 X92.579 Y135.9234 I3.826 J-8.6328
797 | G2 X97.4734 Y135.7125 I2.006 J-10.3416
798 | G2 X102.5378 Y133.5068 I-5.7096 J-20.0264
799 | G2 X105.1586 Y131.7327 I-16.0332 J-26.5088
800 | G2 X108.2142 Y129.0135 I-15.2077 J-20.165
801 | G2 X111.5325 Y124.8929 I-22.6742 J-21.6562
802 | G3 X114.8407 Y120.5322 I40.8958 J27.5898
803 | G3 X117.8221 Y117.1487 I96.556 J82.0755
804 | G3 X120.199 Y114.9165 I15.7135 J14.3507
805 | G3 X122.8315 Y113.344 I6.9411 J8.6303
806 | G2 X125.1842 Y112.2125 I-10.4321 J-24.7031
807 | G1 X127.7739 Y109.4626
808 | G1 X129.8696 Y112.0559
809 | G1 X133.2419 Y111.6746
810 | G1 X133.9387 Y115.4598
811 | G1 X137.0338 Y116.3079
812 | G1 X136.5289 Y121.4104
813 | G1 X138.7543 Y122.9898
814 | G1 X137.0818 Y126.1645
815 | G1 X138.7811 Y129.6336
816 | G1 X136.5656 Y133.5991
817 | G1 X137.4199 Y137.4172
818 | G1 X134.8551 Y139.6031
819 | G1 X134.5204 Y143.6606
820 | G1 X130.9424 Y145.0254
821 | G1 X129.507 Y148.5554
822 | G1 X125.4842 Y148.6006
823 | G1 X123.5109 Y151.221
824 | G1 X120.8027 Y151.0314
825 | G1 X117.7837 Y151.3601
826 | G1 X116.0766 Y152.6206
827 | G1 X113.599 Y150.9758
828 | G1 X110.6009 Y152.539
829 | G1 X104.6412 Y150.2764
830 | G1 X108.5263 Y153.6552
831 | G1 X112.5513 Y154.2981
832 | G1 X115.6349 Y155.0841
833 | G1 X119.7994 Y153.7164
834 | G1 X123.4649 Y154.6449
835 | G1 X126.9992 Y152.5556
836 | G1 X130.7392 Y152.7625
837 | G1 X132.5764 Y149.4659
838 | G1 X136.3003 Y149.036
839 | G1 X138.3151 Y145.3708
840 | G1 X140.6573 Y144.0921
841 | G1 X141.279 Y139.3967
842 | G1 X143.3649 Y137.4184
843 | G1 X142.4477 Y133.3101
844 | G1 X144.905 Y130.1988
845 | G1 X142.601 Y126.8652
846 | G1 X145.0648 Y124.7816
847 | G1 X141.9152 Y121.9901
848 | G1 X145.1051 Y118.6681
849 | G1 X141.2528 Y117.4257
850 | G1 X143.762 Y113.8627
851 | G1 X140.6152 Y113.3197
852 | G1 X142.6789 Y109.4019
853 | G1 X139.1324 Y109.449
854 | G1 X140.9189 Y106.5145
855 | G1 X137.029 Y106.9827
856 | G1 X137.9595 Y102.7609
857 | G1 X135.0199 Y105.3469
858 | G1 X134.0129 Y100.2302
859 | G1 X131.9843 Y103.9042
860 | G1 X130.8856 Y99.3218
861 | G1 X128.3815 Y102.7008
862 | G1 X128.4498 Y97.8957
863 | G1 X125.682 Y102.2162
864 | G2 X126.3281 Y98.55 I-30.5522 J-7.274
865 | G3 X127.7589 Y94.7695 I8.2222 J0.9508
866 | G3 X134.0979 Y96.5474 I-3.1875 J23.5545
867 | G3 X139.8298 Y100.3792 I-7.8517 J17.9481
868 | G3 X145.3718 Y107.3618 I-23.1723 J24.0822
869 | G3 X148.5979 Y115.1417 I-25.2095 J15.0125
870 | G3 X149.828 Y124.8077 I-38.6502 J9.8298
871 | G3 X148.6569 Y134.6388 I-40.4554 J0.1662
872 | G3 X146.329 Y140.6586 I-24.5834 J-6.0464
873 | G3 X143.0246 Y146.0033 I-48.5429 J-26.3184
874 | G3 X138.9129 Y150.2771 I-200.5246 J-188.8032
875 | G3 X134.2266 Y153.9594 I-16.6527 J-16.3699
876 | G3 X125.8296 Y157.0333 I-12.3178 J-20.6426
877 | G3 X116.9822 Y157.6991 I-8.166 J-49.3941
878 | G3 X112.5217 Y157.1648 I0.2914 J-21.3183
879 | G3 X109.7706 Y156.3535 I5.1576 J-22.5588
880 | G3 X105.1349 Y153.8335 I6.067 J-16.6843
881 | G2 X100.4065 Y151.2038 I-11.7258 J15.5182
882 | G2 X98.8306 Y150.91 I-1.5794 J4.0991
883 | G2 X97.5524 Y151.2295 I-0.0022 J2.7084
884 | G3 X99.0239 Y149.4078 I4.8877 J2.443
885 | G3 X101.4473 Y148.147 I4.3922 J5.4831
886 | G3 X104.3993 Y147.8294 I2.3648 J8.1024
887 | G3 X109.1593 Y148.2151 I-14.8071 J212.3469
888 | G3 X112.4649 Y148.7431 I-2.3239 J25.161
889 | G2 X116.9546 Y149.2184 I4.2291 J-18.5055
890 | G2 X122.4154 Y148.1353 I-0.2112 J-15.374
891 | G2 X124.9545 Y146.9132 I-7.3492 J-18.5163
892 | G2 X129.113 Y143.8715 I-11.4336 J-19.9956
893 | G2 X132.4737 Y139.8091 I-13.1549 J-14.3039
894 | G2 X133.8861 Y137.012 I-15.2343 J-9.4481
895 | G2 X134.8859 Y133.9945 I-24.5359 J-9.8031
896 | G2 X135.496 Y130.7709 I-21.8347 J-5.8021
897 | G2 X135.7006 Y127.6684 I-31.8528 J-3.6593
898 | G2 X135.5836 Y124.7559 I-25.3468 J-0.4403
899 | G2 X135.0938 Y122.0878 I-16.1154 J1.5791
900 | G2 X132.3064 Y116.6701 I-14.1005 J3.829
901 | G2 X126.2473 Y114.2553 I-5.207 J4.2559
902 | G2 X120.3955 Y117.7238 I1.0871 J8.5047
903 | G3 X116.6963 Y122.7947 I-1049.1076 J-761.4179
904 | G3 X111.7105 Y129.5513 I-1067.9793 J-782.8747
905 | G3 X106.0842 Y135.7465 I-34.189 J-25.3969
906 | G3 X101.8208 Y138.5324 I-10.9798 J-12.1477
907 | G3 X96.8945 Y139.8269 I-6.3337 J-14.0829
908 | G3 X90.011 Y138.832 I-1.3622 J-14.8853
909 | G3 X84.1031 Y135.3398 I8.1838 J-20.5887
910 | G3 X85.5037 Y134.9386 I7.4557 J23.382
911 | G2 X86.9716 Y134.4254 I-2.2072 J-8.6693
912 | G2 X90.0865 Y132.7292 I-9.6848 J-21.4929
913 | G2 X92.868 Y130.5559 I-10.7455 J-16.6196
914 | G2 X94.7684 Y128.1618 I-7.125 J-7.6071
915 | G2 X95.5652 Y125.3393 I-5.1602 J-2.9805
916 | G2 X94.8108 Y123.1456 I-3.3113 J-0.0878
917 | G2 X93.056 Y121.2558 I-16.7762 J13.8181
918 | G2 X91.7571 Y120.1774 I-8.2668 J8.6356
919 | G3 X90.7161 Y119.3316 I6.5132 J-9.0801
920 | G3 X89.8093 Y118.2444 I3.6227 J-3.9434
921 | G3 X89.929 Y116.6169 I1.162 J-0.7327
922 | G3 X90.6184 Y116.0351 I2.1463 J1.844
923 | G2 X91.5199 Y115.4318 I-5.7102 J-9.5079
924 | G2 X92.2282 Y113.6791 I-1.0809 J-1.4563
925 | G2 X90.8375 Y111.7062 I-2.7384 J0.4537
926 | G2 X88.482 Y111.1792 I-2.0726 J3.7359
927 | G2 X86.3566 Y112.0771 I0.2334 J3.517
928 | G3 X88.1698 Y112.6497 I-0.8979 J6.0004
929 | G3 X88.8421 Y113.7766 I-0.5436 J1.0884
930 | G3 X88.3528 Y114.7167 I-1.2219 J-0.0386
931 | G3 X86.9741 Y115.534 I-4.4791 J-5.9845
932 | G3 X84.0278 Y116.5452 I-6.6622 J-14.6137
933 | G2 X80.9123 Y117.9687 I2.0439 J8.5944
934 | G2 X79.0092 Y120.2394 I3.5076 J4.8725
935 | G2 X78.0491 Y122.9407 I12.1259 J5.8312
936 | G3 X76.5801 Y122.7776 I12.1539 J-116.168
937 | G3 X74.569 Y122.3313 I1.1862 J-10.1009
938 | G3 X72.2986 Y121.2723 I3.3769 J-10.2032
939 | G2 X70.2654 Y120.4546 I-3.3867 J5.4838
940 | G2 X66.5854 Y120.1286 I-3.1516 J14.6468
941 | G2 X64.5614 Y120.4227 I0.3316 J9.3958
942 | G3 X59.6508 Y120.41 I-2.4311 J-9.3925
943 | G3 X53.2471 Y118.5408 I33.3385 J-126.1187
944 | G2 X51.84 Y118.3804 I-1.1076 J3.4627
945 | G3 X47.9905 Y117.8869 I-0.7671 J-9.278
946 | G3 X43.1784 Y115.6254 I8.6526 J-24.6617
947 | G3 X38.8451 Y112.5281 I17.3106 J-28.7983
948 | G3 X34.2356 Y106.7251 I12.0437 J-14.299
949 | G3 X28.1635 Y90.666 I69.4872 J-35.4509
950 | G3 X28.0498 Y86.6177 I33.4212 J-2.9646
951 | G2 X26.8289 Y84.0208 I-3.1554 J-0.102
952 | G3 X24.9234 Y79.9862 I3.0183 J-3.8928
953 | G2 X24.29 Y77.5952 I-4.356 J-0.1255
954 | G2 X23.2884 Y76.7408 I-1.7996 J1.0955
955 | G3 X21.4605 Y75.4788 I1.9643 J-4.7999
956 | G3 X20.1695 Y73.9063 I11.7506 J-10.9624
957 | G3 X19.3635 Y71.3533 I3.4721 J-2.4999
958 | G2 X21.4601 Y72.5369 I9.7824 J-14.8788
959 | G2 X23.9158 Y73.1408 I2.6791 J-5.599
960 | G3 X25.1244 Y73.2016 I-1.5573 J43.0421
961 | G3 X28.8547 Y74.8762 I-0.375 J5.8272
962 | G2 X32.6268 Y76.6907 I4.5216 J-4.572
963 | G3 X36.9169 Y77.6344 I-2.5715 J21.9126
964 | G3 X40.5806 Y79.1476 I-8.173 J24.9793
965 | G3 X48.5555 Y85.262 I-12.1759 J24.1389
966 | G3 X53.5092 Y93.1453 I-20.6628 J18.4824
967 | G3 X56.1811 Y103.4843 I-35.503 J14.6897
968 | G2 X56.295 Y101.7003 I-23.243 J-2.3796
969 | G2 X55.9774 Y96.7628 I-27.5926 J-0.7037
970 | G3 X55.289 Y91.3319 I96.914 J-15.0435
971 | G3 X56.7933 Y83.6017 I13.6868 J-1.348
972 | G1 X58.4595 Y80.4213
973 | G3 X56.5116 Y82.8863 I-34.8281 J-25.5203
974 | G2 X54.9464 Y85.5572 I6.767 J5.7596
975 | G1 X53.6008 Y89.1874
976 | G2 X49.9387 Y84.2959 I-34.1579 J21.7555
977 | G2 X45.7163 Y80.2289 I-25.7003 J22.4568
978 | G3 X45.6335 Y77.0498 I29.9029 J-2.3701
979 | G3 X46.1955 Y73.9266 I10.5384 J0.2843
980 | G2 X46.2328 Y70.5313 I-5.1347 J-1.7541
981 | G3 X46.3101 Y68.2756 I3.2115 J-1.019
982 | G3 X47.4171 Y67.3233 I1.458 J0.5753
983 | G2 X48.4353 Y66.365 I-0.31 J-1.3494
984 | G2 X48.5367 Y63.7219 I-5.1699 J-1.5219
985 | G3 X48.8411 Y61.0685 I4.1054 J-0.8732
986 | G3 X50.4482 Y60.306 I1.2657 J0.5928
987 | G2 X51.6817 Y60.1329 I0.4039 J-1.6034
988 | G2 X52.5075 Y59.3539 I-1.2471 J-2.1491
989 | G3 X53.0363 Y58.5771 I28.5908 J18.8965
990 | G2 X53.2016 Y57.4684 I-1.0268 J-0.7197
991 | G3 X53.6756 Y56.2846 I0.9451 J-0.3084
992 | G3 X55.0778 Y56.039 I1.0706 J1.9873
993 | G2 X56.524 Y55.8104 I0.3591 J-2.4171
994 | G2 X57.2786 Y54.8427 I-0.6309 J-1.27
995 | G2 X57.275 Y53.5377 I-2.9534 J-0.6444
996 | G2 X56.632 Y52.47 I-1.9248 J0.4317
997 | G3 X55.8114 Y51.3572 I1.9865 J-2.3238
998 | G3 X55.5987 Y50.1528 I2.441 J-1.0521
999 | G3 X55.9325 Y49.0156 I2.6155 J0.1502
1000 | G3 X56.9222 Y48.0436 I2.1792 J1.229
1001 | G3 X58.4477 Y47.3249 I7.2744 J13.4601
1002 | G3 X60.155 Y47.0098 I1.6203 J3.9961
1003 | G2 X61.967 Y46.5688 I0.0736 J-3.6408
1004 | G2 X63.5127 Y45.3386 I-2.7149 J-4.9974
1005 | G2 X64.5312 Y44.0195 I-9.3972 J-8.309
1006 | G2 X65.0764 Y42.8479 I-3.4601 J-2.3228
1007 | G2 X65.2156 Y41.7278 I-3.4856 J-1.0019
1008 | G2 X64.9743 Y40.3875 I-4.7031 J0.1549
1009 | G2 X64.3659 Y39.0032 I-7.9092 J2.6505
1010 | G3 X63.8931 Y37.8955 I5.1998 J-2.8737
1011 | G3 X64.4771 Y35.5198 I2.261 J-0.7039
1012 | G3 X66.0251 Y34.3183 I5.4834 J5.4671
1013 | G2 X66.9454 Y33.5572 I-1.9301 J-3.2706
1014 | G3 X66.5248 Y36.1648 I-12.6347 J-0.6998
1015 | G2 X66.6442 Y38.2012 I3.1014 J0.8398
1016 | G2 X68.1982 Y39.6574 I2.3394 J-0.9392
1017 | G3 X69.697 Y40.4121 I-1.7539 J5.349
1018 | G3 X70.8006 Y41.4793 I-2.9235 J4.1274
1019 | G2 X71.742 Y42.5934 I11.2187 J-8.5249
1020 | G3 X71.7781 Y41.0877 I21.8235 J-0.2304
1021 | G2 X71.7259 Y39.9476 I-5.4777 J-0.3206
1022 | G3 X71.7684 Y38.3341 I4.545 J-0.6878
1023 | G3 X73.2209 Y37.0141 I1.6307 J0.3352
1024 | G3 X74.607 Y37.2615 I0.2688 J2.5018
1025 | G2 X76.1071 Y37.9085 I6.8552 J-13.8312
1026 | G2 X75.1787 Y36.5711 I-7.2967 J4.0747
1027 | G3 X74.5168 Y35.0603 I2.1866 J-1.8583
1028 | G3 X74.5662 Y33.3862 I5.5287 J-0.6748
1029 | G3 X75.331 Y31.5506 I4.5975 J0.8385
1030 | G3 X76.8759 Y30.0098 I5.0766 J3.5451
1031 | G3 X78.4708 Y28.9257 I55.3431 J79.6987
1032 | G3 X79.7916 Y28.2564 I3.4728 J5.2159
1033 | G2 X80.7632 Y27.8521 I-4.1304 J-11.2959
1034 | G2 X80.6986 Y26.1299 I-12.1185 J-0.4074
1035 | G3 X80.7082 Y24.5024 I7.0776 J-0.772
1036 | G3 X81.0661 Y23.0107 I6.6353 J0.8031
1037 | G3 X81.7747 Y21.6508 I5.5589 J2.0322
1038 | G3 X82.8918 Y20.573 I3.3203 J2.3235
1039 | G2 X84.2778 Y19.6397 I-25.4759 J-39.3277
1040 | G3 X83.3083 Y21.3899 I-9.1835 J-3.9434
1041 | G2 X82.7659 Y23.1593 I2.5035 J1.7353
1042 | G2 X83.1172 Y24.6894 I3.6875 J-0.0414
1043 | G2 X84.3523 Y26.3605 I4.8209 J-2.2708
1044 | G2 X86.9331 Y27.9166 I5.2155 J-5.7319
1045 | G3 X89.699 Y29.4681 I-3.2955 J9.1161
1046 | G3 X91.1929 Y30.994 I-5.5625 J6.9402
1047 | G3 X91.9319 Y32.2175 I-5.1136 J3.9236
1048 | G3 X92.319 Y34.1698 I-3.8564 J1.7792
1049 | G2 X92.364 Y35.8441 I12.3767 J0.5051
1050 | G2 X92.7696 Y34.3268 I-11.8338 J-3.9763
1051 | G2 X93.0055 Y32.7774 I-16.2907 J-3.273
1052 | G2 X92.606 Y30.3525 I-4.6184 J-0.4844
1053 | G3 X91.8159 Y28.4987 I32.4115 J-14.9076
1054 | G3 X93.9597 Y30.1154 I-2.9953 J6.2016
1055 | G3 X95.0273 Y31.7992 I-4.5726 J4.0794
1056 | G2 X95.2573 Y31.3878 I-0.2395 J-0.4038
1057 | G3 X95.3316 Y29.9143 I11.0996 J-0.1793
1058 | G2 X96.256 Y30.7212 I6.6247 J-6.6568
1059 | G3 X97.1716 Y31.4947 I-7.3895 J9.6756
1060 | G3 X98.0418 Y32.3101 I-130.0156 J139.6365
1061 | G3 X98.7002 Y33.2939 I-1.8191 J1.9294
1062 | G3 X98.8663 Y34.45 I-2.4867 J0.9473
1063 | G3 X98.655 Y35.767 I-8.2704 J-0.6512
1064 | G3 X97.9688 Y37.1176 I-3.2201 J-0.7864
1065 | G2 X96.9055 Y38.6657 I7.2767 J6.1371
1066 | G2 X96.7497 Y40.1251 I1.6657 J0.9158
1067 | G3 X96.9639 Y41.7704 I-4.9752 J1.4845
1068 | G2 X95.4657 Y42.1576 I1.5853 J9.228
1069 | G3 X93.7472 Y42.3236 I-1.1995 J-3.4391
1070 | G3 X91.8105 Y41.4678 I0.5576 J-3.8809
1071 | G2 X89.8401 Y40.746 I-2.0108 J2.4387
1072 | G2 X88.2051 Y41.409 I-0.029 J2.2757
1073 | G3 X86.8381 Y42.2355 I-2.3758 J-2.3857
1074 | G3 X85.2684 Y42.5198 I-1.9146 J-6.0967
1075 | G2 X83.7198 Y42.669 I0.9978 J18.4617
1076 | G2 X86.7791 Y44.1206 I3.713 J-3.8759
1077 | G3 X93.6394 Y45.1004 I-21.3428 J173.9419
1078 | G2 X98.2449 Y45.6886 I10.7863 J-66.1321
1079 | G2 X102.881 Y45.9355 I5.4684 J-59.0308
1080 | G2 X105.3079 Y45.7067 I0.1602 J-11.285
1081 | G3 X107.0266 Y45.7735 I0.7235 J3.5289
1082 | G3 X107.7761 Y46.5344 I-0.2994 J1.0445
1083 | G2 X108.0739 Y47.4267 I7.8329 J-2.1181
1084 | G3 X108.493 Y50.361 I-5.8253 J2.3291
1085 | G3 X108.0443 Y53.2394 I-24.987 J-2.4214
1086 | G3 X103.7917 Y53.7021 I-29.9044 J-255.0369
1087 | G3 X99.5152 Y53.7522 I-2.4206 J-24.1099
1088 | G3 X95.1515 Y52.9071 I1.4885 J-19.3744
1089 | G2 X90.656 Y52.1421 I-5.0145 J15.877
1090 | G2 X86.3843 Y52.4284 I-0.6796 J21.8733
1091 | G2 X82.4055 Y53.9085 I1.8328 J11.0144
1092 | G2 X78.4224 Y57.8777 I6.2514 J10.2564
1093 | G3 X77.0952 Y59.9721 I-75.6581 J-46.4778
1094 | G2 X75.1505 Y63.6195 I19.4878 J12.7326
1095 | G3 X73.5827 Y66.821 I-30.1588 J-12.7842
1096 | G3 X72.4973 Y68.6461 I-34.3789 J-19.2098
1097 | G3 X71.7567 Y69.523 I-3.5307 J-2.2307
1098 | G3 X70.4749 Y70.1784 I-1.8786 J-2.0932
1099 | G2 X69.1255 Y70.5969 I1.7252 J7.9461
1100 | G3 X70.6612 Y70.601 I0.7481 J7.3212
1101 | G2 X72.1586 Y70.287 I0.2651 J-2.4629
1102 | G2 X74.3097 Y67.9101 I-2.5801 J-4.4969
1103 | G3 X75.9412 Y64.7865 I26.7917 J12.0053
1104 | G2 X77.1263 Y68.1535 I35.2541 J-10.5168
1105 | G2 X79.2706 Y70.7538 I5.237 J-2.1342
1106 | G3 X77.3874 Y67.295 I6.4475 J-5.7525
1107 | G3 X76.5796 Y63.7764 I40.4756 J-11.1442
1108 | G2 X79.6457 Y58.7012 I-673.053 J-410.0781
1109 | G3 X84.0046 Y54.9903 I7.671 J4.595
1110 | G3 X86.1571 Y54.3991 I3.7126 J9.303
1111 | G3 X88.4072 Y54.0827 I10.6084 J67.2808
1112 | G3 X94.1732 Y54.3974 I2.0068 J16.2072
1113 | G3 X99.8985 Y55.7814 I-138.1684 J584.1297
1114 | G2 X104.0114 Y56.2164 I3.6373 J-14.7273
1115 | G2 X108.944 Y55.9942 I-5.6638 J-180.5389
1116 | G3 X111.413 Y56.2065 I0.5039 J8.5994
1117 | G3 X113.3901 Y57.7911 I-0.6708 J2.8628
1118 | G3 X113.5872 Y58.769 I-1.8066 J0.873
1119 | G3 X113.2346 Y59.8521 I-2.1924 J-0.1148
1120 | G3 X112.2256 Y60.6715 I-1.7789 J-1.1598
1121 | G2 X111.0034 Y61.4546 I1.3322 J3.4246
1122 | G2 X110.2067 Y62.4405 I3.6064 J3.7291
1123 | G3 X109.5251 Y63.4397 I-12.3992 J-7.7252
1124 | G2 X105.6821 Y62.8778 I-8.2489 J42.994
1125 | G2 X102.8548 Y62.6967 I-3.8736 J38.2935
1126 | G2 X104.8941 Y63.4236 I8.5301 J-20.707
1127 | G3 X107.0088 Y64.156 I-8.2369 J27.1998
1128 | G3 X109.2979 Y65.2311 I-6.9561 J17.7857
1129 | G3 X111.2492 Y66.4124 I-14.1504 J25.5764
1130 | G3 X112.7743 Y67.456 I-30.7774 J46.6128
1131 | G3 X113.9963 Y68.5192 I-4.7229 J6.6626
1132 | G2 X115.3447 Y69.8874 I30.0949 J-28.309
1133 | G3 X116.5363 Y71.4269 I-4.7652 J4.9195
1134 | G3 X117.1206 Y73.1312 I-4.2308 J2.4028
1135 | G3 X117.2876 Y75.0944 I-16.4802 J2.3904
1136 | G3 X117.253 Y77.4406 I-29.0171 J0.745
1137 | G3 X116.7423 Y79.4333 I-5.2823 J-0.2918
1138 | G3 X115.563 Y80.6385 I-2.3584 J-1.1282
1139 | G3 X114.4095 Y81.1105 I-3.5419 J-7.01
1140 | G3 X113.3199 Y80.9912 I-0.4105 J-1.2863
1141 | G2 X112.2096 Y80.6285 I-1.4008 J2.4072
1142 | G3 X111.0811 Y80.4236 I0.796 J-7.5951
1143 | G2 X109.3699 Y80.5822 I-0.6365 J2.4441
1144 | G2 X107.6598 Y81.6801 I3.3061 J7.0303
1145 | G2 X105.487 Y84.042 I8.298 J9.8139
1146 | G2 X103.874 Y87.0712 I10.8762 J7.7357
1147 | G3 X102.1297 Y90.7594 I-23.4838 J-8.8495
1148 | G3 X98.5765 Y96.2151 I-52.0944 J-30.0439
1149 | G3 X94.7121 Y101.4618 I-778.0107 J-568.9816
1150 | G2 X94.3786 Y102.828 I208.6587 J51.6653
1151 | G2 X94.0765 Y104.6577 I12.431 J2.9918
1152 | G2 X93.9744 Y107.7074 I26.3815 J2.4097
1153 | G2 X94.4843 Y110.7475 I10.8863 J-0.2631
1154 | G2 X95.432 Y112.9046 I10.6495 J-3.3918
1155 | G2 X97.2442 Y114.4695 I3.1252 J-1.7875
1156 | G2 X98.3005 Y114.7256 I1.4661 J-3.7404
1157 | G2 X99.2412 Y114.6061 I0.2134 J-2.0817
1158 | G2 X99.9563 Y114.0699 I-0.5434 J-1.4697
1159 | G2 X100.1392 Y113.0217 I-0.9521 J-0.7062
1160 | G2 X99.5099 Y112.2249 I-1.3237 J0.3987
1161 | G3 X98.9519 Y111.7799 I1.2231 J-2.1058
1162 | G3 X98.2376 Y110.7866 I3.5254 J-3.2889
1163 | G3 X97.8004 Y109.7106 I4.6355 J-2.5099
1164 | G3 X99.0105 Y109.739 I-1.337 J82.8926
1165 | G2 X100.0212 Y109.624 I0.1089 J-3.5424
1166 | G2 X100.971 Y109.1313 I-0.6214 J-2.3597
1167 | G2 X101.8506 Y107.8663 I-1.9035 J-2.2619
1168 | G3 X100.6686 Y108.7044 I-4.4304 J-4.9959
1169 | G3 X99.3933 Y109.0528 I-1.3451 J-2.4158
1170 | G3 X98.5883 Y108.9695 I-0.0787 J-3.1708
1171 | G2 X97.6929 Y108.7971 I-2.5569 J10.8692
1172 | G3 X97.4021 Y107.6566 I11.5858 J-3.5612
1173 | G2 X97.0579 Y106.7312 I-3.1321 J0.6384
1174 | G2 X96.4971 Y106.2518 I-0.9326 J0.5231
1175 | G3 X95.9587 Y105.7036 I0.3143 J-0.8473
1176 | G3 X95.762 Y104.6299 I3.2957 J-1.1584
1177 | G3 X95.8376 Y103.2531 I8.725 J-0.2116
1178 | G1 X95.8376 Y103.2531
1179 | G4 P0
1180 | M05 S0
1181 | G1 F3000
1182 | G1 X98.7783 Y102.1666
1183 | G4 P0
1184 | M03 S256
1185 | G4 P0
1186 | G1 F100.000000
1187 | G3 X97.5673 Y102.0379 I0.9698 J-14.8921
1188 | G3 X96.4918 Y101.6078 I0.3654 J-2.4734
1189 | G2 X97.2219 Y100.4714 I-4308.5646 J-2769.1449
1190 | G2 X97.9514 Y99.3353 I-4306.4129 J-2766.075
1191 | G2 X98.1737 Y100.9373 I4.8766 J0.1399
1192 | G2 X98.7783 Y102.1666 I4.2941 J-1.3489
1193 | G1 X98.7783 Y102.1666
1194 | G4 P0
1195 | M05 S0
1196 | G1 F3000
1197 | G1 X103.6594 Y104.1864
1198 | G4 P0
1199 | M03 S256
1200 | G4 P0
1201 | G1 F100.000000
1202 | G2 X104.0422 Y104.0166 I-1.8316 J-4.6459
1203 | G2 X104.5673 Y103.6911 I-1.4363 J-2.9033
1204 | G2 X105.1983 Y103.2046 I-37.546 J-49.3452
1205 | G2 X105.9448 Y102.2411 I-1.5268 J-1.9539
1206 | G2 X106.2699 Y100.6785 I-3.572 J-1.5582
1207 | G2 X106.1999 Y99.7321 I-6.5367 J0.0073
1208 | G3 X105.728 Y99.8102 I-0.5561 J-1.895
1209 | G2 X105.1729 Y100.0287 I0.039 J0.9133
1210 | G2 X104.7714 Y100.5736 I0.9786 J1.1416
1211 | G3 X104.2732 Y101.1627 I-1.2222 J-0.5284
1212 | G3 X103.6874 Y101.3607 I-0.6843 J-1.0588
1213 | G2 X103.0941 Y101.4215 I0.974 J12.4336
1214 | G2 X103.3407 Y100.4235 I-5.0721 J-1.7827
1215 | G2 X103.3266 Y99.5377 I-2.7112 J-0.4
1216 | G2 X102.5353 Y98.1038 I-2.5088 J0.4493
1217 | G2 X101.1219 Y97.4518 I-1.7346 J1.9019
1218 | G2 X100.138 Y97.4839 I-0.3908 J3.1146
1219 | G3 X99.2782 Y97.6448 I-16.2356 J-84.3797
1220 | G3 X99.6754 Y96.9541 I3.6071 J1.6149
1221 | G2 X100.0729 Y96.2633 I-3.2184 J-2.3118
1222 | G2 X101.5783 Y96.4289 I3.1825 J-22.0065
1223 | G3 X102.4255 Y96.6511 I-0.1835 J2.4257
1224 | G3 X103.2502 Y97.165 I-1.723 J3.6839
1225 | G2 X104.2882 Y97.7388 I2.1705 J-2.7006
1226 | G2 X105.3163 Y97.9634 I1.4638 J-4.2337
1227 | G3 X106.4158 Y98.1028 I-1.8785 J19.224
1228 | G3 X105.6002 Y97.3088 I6.1191 J-7.1014
1229 | G2 X104.7854 Y96.5151 I-6.9685 J6.3381
1230 | G3 X105.4602 Y94.5538 R89514.514375
1231 | G2 X106.1347 Y92.593 I-13090.8083 J-4498.7551
1232 | G3 X107.4864 Y91.8584 I6.6689 J10.6595
1233 | G2 X109.1847 Y90.9454 I-7.2023 J-15.4336
1234 | G2 X111.0441 Y89.6308 I-9.0833 J-14.82
1235 | G3 X113.3938 Y88.1717 I6.9691 J8.6013
1236 | G3 X115.4554 Y87.3232 I11.6353 J25.34
1237 | G3 X117.5272 Y86.7533 I4.5013 J12.3131
1238 | G2 X119.823 Y85.7844 I-1.0928 J-5.794
1239 | G3 X122.0735 Y84.9047 I2.9256 J4.1658
1240 | G3 X125.3838 Y84.6609 I3.7018 J27.6692
1241 | G3 X127.9296 Y84.767 I0.3212 J22.8969
1242 | G3 X130.081 Y85.3813 I-0.6041 J6.1899
1243 | G3 X131.3318 Y87.1752 I-1.0052 J2.0339
1244 | G2 X129.685 Y87.2479 I-0.6998 J2.8372
1245 | G2 X127.4369 Y89.3672 I1.2119 J3.5375
1246 | G2 X127.1146 Y91.1613 I4.0264 J1.6493
1247 | G3 X126.6122 Y93.335 I-4.3299 J0.1442
1248 | G3 X125.5939 Y94.6427 I-4.221 J-2.2366
1249 | G2 X124.1016 Y96.3141 I7.0258 J7.775
1250 | G2 X122.3293 Y98.7878 I29508.2284 J21143.5088
1251 | G2 X120.4403 Y101.9456 I18.1365 J12.9931
1252 | G2 X119.3816 Y105.0301 I11.6736 J5.7307
1253 | G3 X118.4724 Y107.7788 I-12.4018 J-2.5775
1254 | G3 X116.9895 Y110.237 I-11.9978 J-5.5613
1255 | G2 X115.5311 Y112.2283 I50.5087 J38.5216
1256 | G3 X112.4764 Y115.8637 I-22.4836 J-15.7909
1257 | G3 X108.4794 Y118.5882 I-9.1916 J-9.1903
1258 | G3 X105.9354 Y119.3548 I-4.4923 J-10.304
1259 | G2 X103.2902 Y119.9282 I5.9734 J33.9428
1260 | G3 X102.1828 Y119.3995 I10.3019 J-23.0017
1261 | G3 X101.4499 Y118.4415 I0.6304 J-1.2418
1262 | G3 X101.4939 Y117.0322 I2.9472 J-0.6133
1263 | G3 X102.2051 Y115.7843 I2.7948 J0.7663
1264 | G3 X103.8132 Y114.208 I30.6824 J29.6935
1265 | G2 X105.2692 Y111.9921 I-3.7906 J-4.0769
1266 | G2 X105.8184 Y109.0847 I-9.0578 J-3.2165
1267 | G2 X105.4278 Y106.4467 I-7.4783 J-0.2406
1268 | G2 X104.6275 Y105.1616 I-3.1315 J1.0583
1269 | G3 X103.6594 Y104.1864 I77.5543 J-77.96
1270 | G1 X103.6594 Y104.1864
1271 | G4 P0
1272 | M05 S0
1273 | G1 F3000
1274 | G1 X103.9851 Y95.8245
1275 | G4 P0
1276 | M03 S256
1277 | G4 P0
1278 | G1 F100.000000
1279 | G3 X103.5589 Y95.4547 I63.9405 J-74.1174
1280 | G2 X102.9318 Y95.0543 I-1.6441 J1.8837
1281 | G2 X102.121 Y94.816 I-1.2921 J2.8987
1282 | G3 X101.0776 Y94.6061 I1.7426 J-11.3584
1283 | G3 X102.4891 Y92.421 I435.6963 J279.8972
1284 | G2 X103.8888 Y90.1524 I-48.1102 J-31.2492
1285 | G2 X105.1605 Y87.7919 I-32.3327 J-18.9413
1286 | G3 X106.4156 Y85.3475 I77.0425 J38.0138
1287 | G2 X106.3919 Y86.7673 I25.9756 J1.1422
1288 | G3 X106.2959 Y88.1014 I-8.1114 J0.0866
1289 | G3 X105.9881 Y89.2484 I-5.455 J-0.8493
1290 | G2 X105.3885 Y90.9965 I21.767 J8.4419
1291 | G2 X104.8051 Y93.0154 I111.2852 J33.2562
1292 | G3 X103.9851 Y95.8245 I-120.1862 J-33.5599
1293 | G1 X103.9851 Y95.8245
1294 | G4 P0
1295 | M05 S0
1296 | G1 F3000
1297 | G1 X0 Y0
1298 | M18
1299 |
--------------------------------------------------------------------------------