Compare commits

...

65 commits

Author SHA1 Message Date
Mario Lukas
c310830a32 Merge branch 'master' of https://github.com/mariolukas/FabScanPi-Server 2019-02-21 22:30:40 +01:00
Mario Lukas
7eeecdb05d o changed changelog.md 2019-02-21 19:22:26 +01:00
Mario Lukas
3cbae54896 o added current release date to changelog 2019-02-21 19:21:04 +01:00
Mario Lukas
c20789ba87 o modified cam driver 2019-02-21 06:01:07 +01:00
Mario Lukas
6d61e87c7b replaced frontend by newer one 2019-02-17 20:32:10 +01:00
Mario Lukas
c75da674d0 moved alignment settinsg to hardware tab 2019-02-17 11:46:23 +01:00
Mario Lukas
56b6c023ee added caching to frontend 2019-02-15 23:29:26 +01:00
Mario Lukas
0a110535d3 Merge branch 'develop' of https://github.com/mariolukas/FabScanPi-Server into develop 2019-02-15 22:46:33 +01:00
Mario Lukas
2398db8a97 modified config 2019-02-15 22:46:14 +01:00
Mario Lukas
2e19b9e6d5 changed key permissions in travis.yml 2019-02-14 08:27:58 +01:00
Mario Lukas
9e461f80d0 removed travis_wait for deployment 2019-02-14 08:24:21 +01:00
Mario Lukas
c3ded5a351 switched build env to trusty 2019-02-14 08:14:31 +01:00
Mario Lukas
cc889a4979 fixed scp -o StrictHostKeyChecking=no 2019-02-14 08:06:41 +01:00
Mario Lukas
d3b1bea82b changed private key 2019-02-14 08:01:59 +01:00
Mario Lukas
b6708996cf changed private key 2019-02-14 08:01:07 +01:00
Mario Lukas
d94d395eba changed private key 2019-02-14 08:00:20 +01:00
Mario Lukas
42a3df99b1 added encrypted deployment key 2019-02-14 07:54:33 +01:00
Mario Lukas
7dd643e9b3 added new deployment method 2019-02-14 07:53:56 +01:00
Mario Lukas
979a2e9801 removed container flag in travis.yml cause it is deprecated 2019-02-14 05:42:34 +01:00
Mario Lukas
f5223780e3 updated travis.yml 2019-02-13 23:35:12 +01:00
Mario Lukas
212f4c0c38 changed sudo env 2019-02-13 23:10:26 +01:00
Mario Lukas
ffa6b74139 testing tavis container based 2019-02-13 23:02:02 +01:00
Mario Lukas
c8922988f1 testing tavis container based 2019-02-13 23:00:05 +01:00
Mario Lukas
b89aa4b2ca upload test 2019-02-13 22:32:29 +01:00
Mario Lukas
72b80eeade upload test 2019-02-13 22:26:27 +01:00
Mario Lukas
fb24e3b47b upload test 2019-02-13 22:25:50 +01:00
Mario Lukas
e542b34150 changed key file 2019-02-13 22:15:53 +01:00
Mario Lukas
d836f3504a sftp added 2019-02-13 22:09:36 +01:00
Mario Lukas
0438b98578 sftp added 2019-02-13 21:59:36 +01:00
Mario Lukas
c9b62c6d85 changed travis.yml 2019-02-13 21:08:16 +01:00
Mario Lukas
6decebf705 changed travis.yml 2019-02-13 21:00:33 +01:00
Mario Lukas
8b3d6f08a4 added encrypted deployment key file 2019-02-13 20:11:09 +01:00
Mario Lukas
c56635a3ae added encrypted deployment key file 2019-02-13 20:01:28 +01:00
Mario Lukas
e60b38548e added encrypted deployment key file 2019-02-13 19:55:42 +01:00
Mario Lukas
427623d418 Merge branch 'develop' of https://github.com/mariolukas/FabScanPi-Server into develop 2019-02-13 19:52:06 +01:00
Mario Lukas
46b4ae656e changed password username option for sftp deployment 2019-02-13 19:51:48 +01:00
Mario Lukas
d2e5fdca8c
Update .travis.yml 2019-02-13 07:47:23 +01:00
Mario Lukas
f404506bcd changed sftp configuration 2019-02-12 21:09:25 +01:00
Mario Lukas
49125c8bfb o changed ftp to sftp deployment 2019-02-12 20:51:03 +01:00
Mario Lukas
50749dd69d o remved docu build from travis due its build by readthedocs 2019-02-12 20:22:34 +01:00
Mario Lukas
cbb01478f1 o remved docu build from travis due its build by readthedocs 2019-02-12 19:57:06 +01:00
Mario Lukas
c0ffdb1c6f o added new frontend version 2019-02-12 19:23:42 +01:00
Mario Lukas
904d5c71f6
Update main.js 2019-02-12 08:33:08 +01:00
Mario Lukas
af2c535d6c o changed changelog 2019-02-11 23:38:39 +01:00
Mario Lukas
20616ad7bf o added new firmware, added new camera options and settings 2019-02-11 23:36:44 +01:00
Mario Lukas
ebd0c56260
Merge pull request #127 from renebohne/patch-2
updated link to Watterott PDF
2019-02-11 08:47:25 +01:00
René Bohne
c090ee441c
updated link to Watterott PDF
The link was broken in paragraph
"For the DC/DC converter option you can find further instructions and pictures on the [Watterott electronic website]"
2019-02-09 22:18:38 +01:00
Mario Lukas
847c9fdcad fixed hardware controller api endpoint 2019-02-01 23:15:24 +01:00
Mario Lukas
e8801b078b added call test function 2019-02-01 22:14:26 +01:00
Mario Lukas
4549f77aa2 added new firmware version 2019-01-30 07:43:24 +01:00
Mario Lukas
883483a6da added workaround for blocking motor problem 2019-01-30 07:39:19 +01:00
Mario Lukas
4be2c1f869 fixed typo in folder name 2019-01-28 22:46:59 +01:00
Mario Lukas
1e4d88c14b changed script file installation files 2019-01-28 22:43:09 +01:00
Mario Lukas
d3c52abea6 added additional requirements file for docs 2019-01-28 22:40:56 +01:00
Mario Lukas
eaba7ae5d6 added avrdude scripts to setup.py 2019-01-28 22:34:44 +01:00
Mario Lukas
2932ff971c refactored install script 2019-01-28 22:12:40 +01:00
Mario Lukas
ec8f7421dc added job scheduler
added avrdude scripts
added new package dependencies
2019-01-28 21:55:26 +01:00
Mario Lukas
6c57b5af94 added missing discovery file 2019-01-28 06:06:23 +01:00
Mario Lukas
bf2f95a567 merged 2019-01-27 22:43:49 +01:00
Mario Lukas
aed4d7bc7e changed changelog 2019-01-27 22:42:55 +01:00
Mario Lukas
15cebc43d8 added discovery service
removed not needed fw version
modiefied FSUpdate to work also with different stages
2019-01-27 22:41:58 +01:00
Mario Lukas
4a8a18d119 added api points for log stream and zip download 2019-01-16 23:24:24 +01:00
Mario Lukas
2a8798d08a
Update CHANGELOG.md 2019-01-07 16:52:49 +01:00
Mario Lukas
bb447bc71e fixed merge conflict 2018-11-26 00:01:56 +01:00
Mario Lukas
17b7ddadd6 changed requirements.txt 2018-09-09 15:15:40 +02:00
41 changed files with 2614 additions and 268 deletions

View file

@ -1,14 +1,13 @@
dist: trusty
group: edge
language: python
#virtualenv:
# system_site_packages: true
python:
- "2.7.13"
- 2.7.15
before_install:
- openssl aes-256-cbc -K $encrypted_f5913d2a38b3_key -iv $encrypted_f5913d2a38b3_iv -in fabscan.key.enc -out fabscan.key -d
- sudo apt-get -qq update
- sudo apt-get install -y build-essential python-setuptools debhelper cdbs dh-python fakeroot
python-pip rsync
- sudo apt-get install -y libcurl3 build-essential python-setuptools debhelper cdbs
dh-python fakeroot python-pip rsync
before_script:
- CURRENT_DATE=$(date +%Y%m%d%H%M)
- pip install mkdocs
@ -18,28 +17,14 @@ before_script:
- echo $TRAVIS_TAG
script: sudo make deb
after_success:
- ls -alh ../*.deb
- travis_wait curl -T ../*.deb -u $FTPUSER:$FTPPASSWORD ftp://mariolukas.de/release/
- NOW=`date +%Y-%m-%d-%H-%M`
- mkdocs build
- cd ..
- mkdir tmp
- cd tmp
- git clone -b gh-pages https://github.com/mariolukas/FabScanPi-Server.git
- cd FabScanPi-Server
- git config --global user.email "dev@fabscan.org"
- git config --global user.name "Travis CI"
- git config credential.helper "store --file=.git/credentials"
- echo "https://${GITHUB_TOKEN}:@github.com" > .git/credentials
- rsync -a -v ../../FabScanPi-Server/site/ .
- git commit -am "travis doc update ${NOW}"
- git push
- cd ../../FabScanPi-Server/
- FILE_NAME=$(ls -a ../*.deb)
#- travis_wait curl -T $FILE_NAME -u $FTPUSER:$FTPPASSWORD ftp://mariolukas.de/release/
- chmod 600 fabscan.key
- scp -o StrictHostKeyChecking=no -i fabscan.key $FILE_NAME $DEPLOY_USER@mariolukas.de:/var/deploy/release/.
env:
global:
- secure: m+zIuupfcmWS8Sby7CB6gAG9cdPLS6DzS+ZjA+9JispYr1rQRYJMPPgP54/XE1UNp8wCU9cPLDHTcllkzKh2PBUXcDy0BOqA+2n1pz3sXloQKM+4uIpBywru4VLCIymw3f2AhfV//50X95w8p/9lH7/K0kUWHNpAkFeMfiVpYN9Fcj5V2NhJ1EYjU5fgwdJ9GACMyiwkxt/GQiiLSLcffHBvN+HOSU19xGBEQx7LEKMJzVs48DT9ZCsjOH4O+rYFyZUW2qzRqJFidSg8SbJAzxiXSiJpgexBji6PkheGAu3DzPLXQAjacW7V0gwqeyuEl9ETcnAt3ZN0UrsYh6zCSLJUBDdJjsypcxgAtz+RddgUCTLIM/TaLSDw6YaOhUsT5CtdDRIflK7LdHhK0oGzVrG8rA2VfKGEKlSC10ZyhenazM6MLTjErGqAcdg6QtN5JXVkubTSytJbs1vEqRTdwo9DI8p2RFa5o4wUobHleFN9GFWwdeKDob86bYna886q5fq6mCLNoOf/KCCMCAcy/hEaOyFb3JYRxhrTCa4lQQ1JNe3YveuiY2P5d+DF7liRpXXpMqBK6RfwmLVn3JfYS6Y33b6h9pYRtu6Cjcm+nc6UhTaM1qxqyJkd2X/yPByJYyt4JjKJkkyVzrN5jzxn3CTPXnNHyYF6uIs4Eoq7m+Q=
- secure: Aimc+MrAZvmd+0XxaO5e8GcEFI9tLiAS/mC9cf+cB8hJfZqKPgVqZ5kfrG4GEC4ymQkZ+Uhbitc51+ml/8I5/3rkc7+cRDG7zn7e6k+E1TLPM/UYett8Qu60hK+QUA7ZgUIXbTOVIKzR/mluTfY38MOxNlLeLV6cSqyRj+OnXZw5H4rR/s/sKRscgS3oedj5lWQiwLED4PhqCnbLFTncC0FPIr8C3o3UKFK3jRlVGm1gAMJWDkFu/EM5K6HAP2SRBQBfC9wACjsqLyRw9jjIeoVD4vFsK9KJdvfgKh/w+UZR3vySrd2pn3L3/7B/+TNEdex3UpzePmHsfGkWPsqULO/OahpEmxS9BUpiqgTQkousaWEG5F9Zv+oJHvFgcAmMSXUGCWepiWhtNDYROnQwj2mNb1+GZv58bhzMLU6l2BXBxIs2Kju8RMLnFi+0vzUyo8pIQT0a0Up/rI40ljkuEzuw683TeryThUAwfFuqMHE/RalWkdujLpigJZS5E/5nNX+MZsCUv7v34PdMFWrkxr/6K/JnwamgNcmU1WKweYwGxIsorDqGEEGkjpbOt1ynZg3KEiLMlEkCMQpLJ1oAptItw8CnGJufHndoZIGktMffYSa+Xe4Gi7ficU25K4ckMRsAJzr9Zzub2Sr4wx8hswafos3xhgpXKOQk8EiUnRo=
- secure: iKV7rjdri+dxUlyr0C01195QFREbfIt0nL1ocdMrxDZdp8hb25pDl3UPrbC8pBSHIfOvbucfN7BMukS4EsD3Jxw0YCInwwUR5hZRZkiegU5TuUdzKHpbSCHl8+gtv9IcQKSYryHeFGAtCnW+52XIlNkLH8pzjKJyLkMB/uIVDdcQn1az7t8MR21ucTJdyGf/oJBmabmq9nwqEgumA+Ei+6J+/jdzK+M3do1iON1yHFJS2yGU21QdRIRxvEIat8Ss6JV/nfWFMbWQH/YRHKTrMXkgscqgDB/hJtfDgIvlObgsssrScRSoOm3a7vKEn4OoefUV0oFsPBrCKYEjWMqyEutz/nX25bV2gytrKbzyurI8Qr1QMJhcFZiobLkhMWTyAS/lJqQl45/Ffxj2pJFiUXvKCz+dwKYaQ/zjAu2ZUhxFw4f7KR7yTz3ifQFHy6imZ/1P/J7LLLiMXENN2xQCP80nsuLdRVFFms3z/nSbm/dLosudWHWu+x0tdbMd9XswfRqcaAr2WePNbGLAzb3mivKoP1hIG7yMVgc6dnLWoH2QPtcSdwSsBkkUZPMMRrk4Hy1GqYGPrqJ+CuHhffRKlnL+Irj3uMO0Uxxl0w/YK6h4UJu6bnvIsLIKNR84ZeoQqm8q10tXOZrlInAYYfYthRumBzNNNeCfneTHeqRL/PI=
- secure: k0Ms4zQL6KTWInxaS2G578OxmG2aJSicezcGESsDHg3RLI7zgyx4jn+3IdoGfZucXmMxjwPFpBvoVBYfJ4GY5ZrgV8ftvnReO7xn8obADtOmSupTy5eUX5S/K+b8VdjD/QQRO9Bn9lz7ekTauMqtv2usw93X3RTDFtEAtLwtBEuGMU4dhU1lHC/1HDxa0BGfhuEOsp9eedA641dwq3kVpw/6WRlpdyNLEL6l7HJ2ednOH+DXb5hTwSF+Wbg/Oe/pobn8xpFvYc8ZmlRVpiE0kL3lA4HZ5gdBCHAs9HuNsK8e3pKn9l71zqEFdZdbUylp/fFeN5uLYMnZSMKBOg03lRhtsICm6IN7d91Hazcd+vox5Jh0EBgKsEgrAoDSMjiMRj1ROnZXWgs/DYZh8nV+y23hY3BlvyD2AjwyxCHRLG4sIkGmhxe3EoaW1vBwZ4/QUp7AL6x9povUsJM4kU6sBu0+QaoKk1NKs+2xW4mpktS5i2WHuR/sJcmf8AWDkuTejSKBzmKJoSb2dluRYKHa7EpobA7hiCz+6Und13sGJDvF46QprCkuVmDeQc1wImpVj2Evn0KLRRq4z33mEtoMMbROJ1Pg7pXdaTvl9AxDHn60NIbfr7lWjcYIvaOpPSax5vCD6w2lDToDbwj/4K5mh80/bhOyWVCrfcJxQOYqxxQ=
- secure: mtixe+yGZ0+mDmcvcFhlETHbmS0umal53U8rh+gvn0+QuuVY0WilLUf5eE3tLZtifyrC0XHkGXpOiaRKS0k5sWuryhEHc5nU7h85uw209hHMNuR2wsMFTln6vUpjZkXxCUuY1qBS9SRK6JrBro0j8aDm7/hj/ESyjp+eexA6hjX/EuYHT5TjuPgrgx8V6kJAWLM56H7pQqFX2sYlCfqSPm4HntA50JP84FcJ6DOczV3RgwKJLXftYWRfcw4ANtcM+5uoaNXkNzdRmqB91W+A+k/lKmtAdpldJhVpsLt43nk+m75+EUjqinuvwzVlz2xPxUC3L/t8HAxqudmg+41MSDhUUcDnPN0AkIE6lzYsBkSZ6fR36xgPVnGHnsTTiN+j7aOpnxjrGzofb0KGOCbfn8TWiw013F7fM5gVL94FkIWpDrfgBgU/tdkmjhnMEnNqyYXsrtRIG+PexZV4PFg5GtStIZsy/BVZRvroHBnmQs7AS19w6NnsdvLHM6P3U+K37shpZgWSXKKKLyqV/NRi/iSa8dbPRISoZCn8x84vEU8bsTIUqT+n9cN75RbcSOIdvj4cDE+GJqWJh+afBfacuiYtgMMrh0/w3ad2ldCkF6uzBSsvPnuc+NBBp0M2uKiKhhqLz/uB8iYS0Gzmso6defDGgocnut++cRW2f3IfdAE=
before_deploy:
- export RELEASE_FILE_NAME=$(ls ../*.deb)
after_deploy:
@ -56,7 +41,7 @@ deploy:
skip_cleanup: true
file_glob: true
api_key:
secure: dmGlVHwZYiYEucvDsT4dVAkXRhD0DNM9Xrt5ALpwMdhH2nyu38E8aDXzMpRg4dR0DFAmhOIajOxBl4m+WhTAagZr4djND282+8u7YgTKKWaSCXdUmp7tJDvj7YtReJ2DpcLq/ydEwrvO5Ayt2RVZb1yiw8TXNw6hRaVwfcqNcQ0LFFgz8UwBXgrVaasJACQWU1T0kfG74Q3NuPU/CwKhPvaciMClw29n6eMBtNBV8lGLFFw5g/JnmMQrm4BcqeeuNEM3w4vWVUcETIhsOi69iotkWKcWNwXed48A/YvzK+UFefq/ErKmdiDVe6yseEUuF2d+04mSegqTOAho9QTMonmJcMnnyC3kYmcAcMYPTjDgJjot7AsBmCQvn9dppDeI4EUmdA4bMhQ/Gtg0W/dfpj3zQymrOhSIp/WiA1LLAuNegsTmBWXz8wQnize9c5GDKlpnIWhSm9aj3JVXVcY0HREUJ0uM/vCvXen5j48/aVvBU4R/KUlWRLKVn8XpKa4jVzcFI6gGF9yXMhyQ86mgLsM/v8n+4poBYud6nUL6hQHGd+COZ8vVG3NV+eHQrL/yXMMxMQHBajktLhL5+N6R89nvaVYDKPFHAV94vpSt35sTEmuLy9p08fyDxA8HdW/hxljzUCPWNXyRF95qHteRhd54d536X/JaIMOgV938k6A=
secure: k0Ms4zQL6KTWInxaS2G578OxmG2aJSicezcGESsDHg3RLI7zgyx4jn+3IdoGfZucXmMxjwPFpBvoVBYfJ4GY5ZrgV8ftvnReO7xn8obADtOmSupTy5eUX5S/K+b8VdjD/QQRO9Bn9lz7ekTauMqtv2usw93X3RTDFtEAtLwtBEuGMU4dhU1lHC/1HDxa0BGfhuEOsp9eedA641dwq3kVpw/6WRlpdyNLEL6l7HJ2ednOH+DXb5hTwSF+Wbg/Oe/pobn8xpFvYc8ZmlRVpiE0kL3lA4HZ5gdBCHAs9HuNsK8e3pKn9l71zqEFdZdbUylp/fFeN5uLYMnZSMKBOg03lRhtsICm6IN7d91Hazcd+vox5Jh0EBgKsEgrAoDSMjiMRj1ROnZXWgs/DYZh8nV+y23hY3BlvyD2AjwyxCHRLG4sIkGmhxe3EoaW1vBwZ4/QUp7AL6x9povUsJM4kU6sBu0+QaoKk1NKs+2xW4mpktS5i2WHuR/sJcmf8AWDkuTejSKBzmKJoSb2dluRYKHa7EpobA7hiCz+6Und13sGJDvF46QprCkuVmDeQc1wImpVj2Evn0KLRRq4z33mEtoMMbROJ1Pg7pXdaTvl9AxDHn60NIbfr7lWjcYIvaOpPSax5vCD6w2lDToDbwj/4K5mh80/bhOyWVCrfcJxQOYqxxQ=
file: "${RELEASE_FILE_NAME}"
on:
tags: true

View file

@ -4,13 +4,35 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [Unreleased] - dev
## [0.8.0] - unreleased
### Added
### Changed
### Fixed
## [0.7.0] - 2019-02-21
### Added
- new settings dialog options for hardware contolling
- moved calibration button to settings dialog
- added new configuraitons in general settings tab
- prepared platform independet firmware setup (aka cyclop compatible mode)
- api route for live log stream
- api route for debug log zip download
- new firmware version
- made fabscan discoverable in find.fabscan.org
- apscheduler library for registery servcie and future scheduling tasks
- added meshmixer to package dependencies
- added avrdude config to package dependencies
### Changed
- replaced old image build script by a new one, based on official raspbian build scripts
- FSUpdate is working for different stages now
### Fixed
- fixed camera driver (pi and usb)
- fixed random artifacts at the beginning of object scan
## [0.6.0] - 2018-11-23
### Added
- introduced Tornado Web Framework

15
debian/changelog vendored
View file

@ -1,3 +1,18 @@
fabscanpi-server (0.7.0) UNRELEASED; urgency=medium
* api route for live log stream
* api route for debug log zip download
* new firmware version
* made fabscan discoverable in find.fabscan.org
* apscheduler library for registery servcie and future scheduling tasks
* added meshmixer to package dependencies
* added avrdude config to package dependencies
* replaced old image build script by a new one, based on official raspbian build scripts
* FSUpdate is working for different stages now
* fixed camera driver (pi and usb)
* fixed random artifacts at the beginning of object scan
-- Mario Lukas <info@fabscan.org> Thu, 21 Feb 2019 22:47:00 +0100
fabscanpi-server (0.6.0) UNRELEASED; urgency=medium
* refactored webserver backend code
* introduced Tornado web framework

2
debian/control vendored
View file

@ -10,6 +10,6 @@ Package: fabscanpi-server
Architecture: all
Homepage: http://fabscan.org
X-Python-Version: ${python:Versions}
Depends: ${misc:Depends}, ${python:Depends}, python-opencv, python-tornado, libtbb2, python-pil, python-serial, python-pykka, python-picamera, python-rpi.gpio, python-semver, xvfb, meshlab, strace, avrdude, python-scipy
Depends: ${misc:Depends}, ${python:Depends}, meshlab, xvfb, avrdude, strace, python-opencv, python-funcsigs, python-apscheduler, python-tornado, libtbb2, python-pil, python-serial, python-pykka, python-picamera, python-requests, python-rpi.gpio, python-semver, xvfb, meshlab, strace, avrdude, python-scipy
Description:
FabScanPi Server ist the backend of the Stand-alone, Web-enabled, Open Source 3D laser scanner.

3
debian/postinst vendored
View file

@ -11,6 +11,9 @@ LOG_DIR=/var/log/fabscanpi
SCANS_DIR=/var/scans
PID_DIR=/var/run/fabscanpi
chmod 777 /usr/bin/autoreset
chmod 777 /usr/bin/avrdude-autoreset
# Allow $FABSCAN_USER to change the config and setting files
chown -R $FABSCAN_USER:nogroup $CONF_DIR

8
debian/preinst vendored
View file

@ -10,6 +10,12 @@ SERVICE=fabscanpi-server
INIT_SCRIPT=/etc/init.d/$SERVICE
SCANS_DIR=/var/scans
echo "KERNEL=="ttyAMA0", SYMLINK+="ttyS0",GROUP="dialout",MODE:=0666" > /etc/udev/rules.d/80-arduinopi.rules
if [ -f /etc/inittab ]; then
sed -i -e 's/T0:23:respawn:/#T0:23:respawn:/g' /etc/inittab
fi
if ps ax | grep -v grep | grep -v $0 | grep $SERVICE > /dev/null
then
if [ -f $INIT_SCRIPT ];then
@ -21,4 +27,6 @@ fi
adduser --system $FABSCAN_USER --home $SCANS_DIR --no-create-home > /dev/null 2>&1 || true
usermod -a -G dialout -G pi -G sudo -G tty $FABSCAN_USER
usermod -a -G dialout -G pi -G sudo -G tty pi
exit 0

View file

@ -239,7 +239,8 @@ for 1 turntable stepper motor, 1 PiCam and 1 laser.
| (white square) | Ground (GND) |
| 5V | 5V output from regulator to FabScanPi HAT |
For the DC/DC converter option you can find further instructions and pictures on the [Watterott electronic website](https://github.com/watterott/RPi-FabScan-HAT/blob/master/hardware/RPi-FabScan-HAT_Assembly.pdf).
For the DC/DC converter option you can find further instructions and pictures on the [Watterott electronic website](https://learn.watterott.com/fabscan/hat_assembly.pdf).
NOTE: For the final stage of constuction a more powerful power supply is needed. At the moment there are no technical specifications available.

View file

@ -1,15 +1,19 @@
var _paq = _paq || [];
_paq.push(["setCookieDomain", "*.fabscan.org"]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="http://analytics.mariolukas.de/";
_paq.push(['setTrackerUrl', u+'piwik.php']);
_paq.push(['setSiteId', 3]);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
var _paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
_paq.push(["setCookieDomain", "*.fabscan.org"]);
_paq.push(["setDomains", ["*.fabscan.org","*.www.fabscan.org"]]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//analytics.mariolukas.de/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '3']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
$.get('https://api.github.com/repos/mariolukas/FabScanPi-Build-Raspbian/releases/latest', function (data) {
var asset = data.assets[0];
var downloadCount = 0;

BIN
fabscan.key.enc Normal file

Binary file not shown.

1
mkdocs-requirements.txt Normal file
View file

@ -0,0 +1 @@
mkdocs<=0.16.1

View file

@ -1,7 +1,10 @@
pyserial >=3.0
pillow ==2.7
Pykka >=1.2
numpy >=1.9
semver >=2.0
pyserial
pillow
Pykka
numpy
semver
tornado
mock
mock
requests
apscheduler
funcsigs

View file

@ -113,6 +113,7 @@ def params():
('/usr/share/fabscanpi/js/',['src/www/js/app.js', 'src/www/js/lib.js']),
('/usr/share/fabscanpi/js/locales/en/',['src/www/js/locales/en/i18n.js']),
('/usr/share/fabscanpi/locales/de/',['src/www/js/locales/de/i18n.js']),
('/usr/bin/', ['src/avrdude/autoreset','src/avrdude/avrdude-autoreset']),
('/usr/share/fabscanpi/icons/', ['src/www/icons/icon_mesh.svg','src/www/icons/icon_scan.svg','src/www/icons/icon_pointcloud.svg','src/www/icons/favicon.png', 'src/www/icons/spinner.gif', 'src/www/icons/logo.png']),
('/usr/share/fabscanpi/fonts/', ['src/www/fonts/fontawesome-webfont.woff2', 'src/www/fonts/fontawesome-webfont.woff', 'src/www/fonts/fontawesome-webfont.ttf']),
('/usr/share/fabscanpi/style/fonts/', ['src/www/style/fonts/slick.woff', 'src/www/style/fonts/slick.ttf'])

BIN
src/.DS_Store vendored

Binary file not shown.

41
src/avrdude/autoreset Normal file
View file

@ -0,0 +1,41 @@
#!/usr/bin/python
# from https://github.com/mharizanov/avrdude-rpi
import RPi.GPIO as GPIO
import sys, os, re, time, fcntl
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
dtr = re.compile('.+TIOCM_DTR.+')
start = time.time()
pin = 7 # 7 = GPIO4
def reset():
GPIO.setup(pin, GPIO.OUT)
GPIO.output(pin, GPIO.HIGH)
time.sleep(0.12)
GPIO.output(pin, GPIO.LOW)
def process():
while True:
try:
duration = time.time() - start
input = sys.stdin.readline().strip()
if dtr.match(input):
reset()
return
elif duration > 2.0:
return
except:
continue
print "avrdude-original: Using autoreset DTR on GPIO Pin " +str(pin)
reset()
process()
GPIO.cleanup()
exit

View file

@ -0,0 +1,8 @@
#!/bin/bash
if [[ $@ == */dev/ttyS0* || $@ == */dev/ttyAMA0* ]];
then
sudo strace -o "| tail -n +1 | autoreset" -eioctl sudo /usr/bin/avrdude $@;
else
sudo /usr/bin/avrdude $@;
fi

View file

@ -8,8 +8,10 @@ import time
import threading
import logging
import multiprocessing
from apscheduler.schedulers.background import BackgroundScheduler
from fabscan.FSVersion import __version__
from fabscan.FSEvents import FSEventManagerInterface, FSEvents
from fabscan.worker.FSMeshlab import FSMeshlabTask
from fabscan.FSConfig import ConfigInterface
@ -17,6 +19,7 @@ from fabscan.FSSettings import SettingsInterface
from fabscan.scanner.interfaces.FSScanProcessor import FSScanProcessorCommand, FSScanProcessorInterface
from fabscan.lib.util.FSInject import inject, singleton
from fabscan.lib.util.FSUpdate import upgrade_is_available, do_upgrade
from fabscan.lib.util.FSDiscovery import register_to_discovery
class FSState(object):
IDLE = "IDLE"
@ -46,6 +49,7 @@ class FSCommand(object):
UPDATE_CONFIG = "UPDATE_CONFIG"
@inject(
settings=SettingsInterface,
config=ConfigInterface,
@ -71,9 +75,18 @@ class FSScanner(threading.Thread):
self.eventManager.subscribe(FSEvents.ON_CLIENT_CONNECTED, self.on_client_connected)
self.eventManager.subscribe(FSEvents.COMMAND, self.on_command)
self.scheduler = BackgroundScheduler()
self.scheduler.start()
self._logger.info("Job scheduler started.")
self._logger.info("Scanner initialized...")
self._logger.info("Number of cpu cores: " + str(multiprocessing.cpu_count()))
self.config = config
if bool(self.config.discoverable):
self.run_discovery_service()
self.scheduler.add_job(self.run_discovery_service, 'interval', minutes=30, id='register_discovery_service')
self._logger.info("Added discovery scheduling job.")
def run(self):
while not self.exit:
@ -148,6 +161,11 @@ class FSScanner(threading.Thread):
meshlab_task = FSMeshlabTask(event.scan_id, event.filter, event.format)
meshlab_task.start()
elif command == FSCommand.HARDWARE_TEST_FUNCTION:
self._logger.debug("Hardware Device Function called...")
self.scanProcessor.ask({FSEvents.COMMAND: FSScanProcessorCommand.CALL_HARDWARE_TEST_FUNCTION, 'DEVICE_TEST': event.device})
return
# Upgrade server
elif command == FSCommand.UPGRADE_SERVER:
if self._upgrade_available:
@ -178,6 +196,7 @@ class FSScanner(threading.Thread):
}
}
eventManager.send_client_message(FSEvents.ON_CLIENT_INIT, message)
self.scanProcessor.tell({FSEvents.COMMAND: FSScanProcessorCommand.NOTIFY_HARDWARE_STATE})
#self.scanProcessor.tell({FSEvents.COMMAND: FSScanProcessorCommand.NOTIFY_IF_NOT_CALIBRATED})
@ -190,4 +209,13 @@ class FSScanner(threading.Thread):
self.eventManager.broadcast_client_message(FSEvents.ON_STATE_CHANGED, {'state': state})
def get_state(self):
return self._state
return self._state
def run_discovery_service(self):
try:
hardware_info = self.scanProcessor.ask({FSEvents.COMMAND: FSScanProcessorCommand.GET_HARDWARE_INFO})
except:
hardware_info = "undefined"
register_to_discovery(str(__version__), str(hardware_info))

View file

@ -62,6 +62,8 @@ class Settings(SettingsInterface):
self.led.blue = settings.led.blue
self.led.green = settings.led.green
self.led.red = settings.led.red
self.show_laser_overlay = settings.show_laser_overlay
self.show_calibration_pattern = settings.show_calibration_pattern
def todict(self, obj, classkey=None):

View file

@ -42,8 +42,8 @@
"height": 1232
},
"preview_resolution": {
"width": 320,
"height": 240
"width": 800,
"height": 600
},
"rotate": "True",
"hflip": "True",
@ -51,10 +51,12 @@
"type": "PICAM"
},
"serial": {
"baudrate": 115200,
"plattform_type": "fabscanpi",
"baudrate": 57600,
"autoflash": "True",
"port": "/dev/ttyAMA0"
},
"texture_illumination": 140,
"keep_raw_images": "True"
"keep_raw_images": "True",
"discoverable": "True"
}

View file

@ -11,7 +11,9 @@
"contrast": 10,
"saturation": 0
},
"resolution": 8,
"resolution": 4,
"laser_positions": 1,
"color" : "True"
"color" : "True",
"show_laser_overlay": "True",
"show_calibration_pattern": "True"
}

View file

@ -19,6 +19,11 @@
"camera_matrix": [],
"distortion_vector": [],
"laser_planes": [
{
"deviation": 0,
"distance": 0,
"normal": []
},
{
"deviation": 0,
"distance": 0,
@ -42,19 +47,22 @@
"height": 1232
},
"preview_resolution": {
"width": 320,
"height": 240
"width": 800,
"height": 600
},
"rotate": "True",
"hflip": "True",
"vflip": "False",
"type": "PICAM"
"type": "PICAM",
"undistort": "False"
},
"serial": {
"baudrate": 115200,
"plattform_type": "fabscanpi",
"baudrate": 57600,
"autoflash": "True",
"port": "/dev/ttyAMA0"
},
"texture_illumination": 140,
"keep_raw_images": "True"
"keep_raw_images": "True",
"discoverable": "True"
}

View file

@ -0,0 +1,798 @@
:100000000C9443010C946B010C946B010C946B01E8
:100010000C946B010C946B010C946B010C946B01B0
:100020000C946B010C946B010C946B010C946B01A0
:100030000C946B010C946B010C946B010C946B0190
:100040000C9429080C946B010C9499080C94730877
:100050000C946B010C946B010C946B010C946B0170
:100060000C946B010C946B01CC01D201D801DE0120
:10007000E401EA01F0012B03320339034003470393
:100080005E034E035E0355034E414E494E4954599B
:10009000494E46CDCCCC3D0AD7233C17B7D1387753
:1000A000CC2B329595E6241FB14F0A000020410069
:1000B00000C84200401C4620BCBE4CCA1B0E5AAEB3
:1000C000C59D744D3131343B202D207265706F72A7
:1000D0007420706F736974696F6E20616E6420663E
:1000E00065656472617465004D3130303B202D20B0
:1000F000746869732068656C70206D6573736167DF
:1001000065004D32323B202D207475726E2072696D
:10011000676874206C61736572206F6666004D328B
:10012000313B202D207475726E20726967687420CF
:100130006C61736572206F6E004D32303B202D2054
:100140007475726E206C656674206C6173657220C4
:100150006F6666004D31393B202D207475726E201C
:100160006C656674206C61736572206F6E004D3132
:10017000383B202D2064697361626C65206D6F745B
:100180006F7273004D31373B202D20656E61626CBC
:1001900065206D6F746F727300473031205B542897
:1001A0007374657073295D205B4C2873746570737C
:1001B000295D205B46286665656472617465295D0A
:1001C0003B202D206D6F766500473030205B542832
:1001D0007374657073295D3B202D206C696E6561B9
:1001E00072206D6F766500436F6D6D616E64733A5A
:1001F000004661625363616E20472D434F4444457E
:1002000020496E74657270726574657220566572ED
:1002100073696F6E3A2000424144434845434B5353
:10022000554D20004241444C494E454E554D20000D
:100230003E0000000000240027002A000000000803
:10024000000201000003040700000000000000009D
:10025000010204081020408001020408102001025D
:100260000408102000000000250028002B000404D2
:10027000040404040404020202020202030303034E
:1002800003034C11BF0D11241FBECFEFD8E0DEBF1A
:10029000CDBF22E0A4E5B1E001C01D92A03AB207B3
:1002A000E1F711E0A0E0B1E0E6E4FFE202C0059072
:1002B0000D92A435B107D9F711E0C2E4D1E004C032
:1002C0002197FE010E945F16C134D107C9F70E9431
:1002D000CF0D0C9496170C940000FC01538D448DA7
:1002E000252F30E0842F90E0821B930B541710F0E1
:1002F000CF96089501970895FC01918D828D9817EE
:1003000061F0828DDF01A80FB11D5D968C91928DF9
:100310009F5F9F73928F90E008958FEF9FEF0895F6
:10032000FC01918D828D981731F0828DE80FF11DBF
:10033000858D90E008958FEF9FEF0895FC01918DDA
:10034000228D892F90E0805C9F4F821B91098F73D3
:100350009927089580E090E0892B29F00E941D08DC
:1003600081110C9400000895CF93DF9347705527B7
:1003700066277727FA013197EC01A881B981E73028
:10038000F10520F4EC5CFF4F0C945F161496ED9190
:10039000FC91159761E029C01496ED91FC91159799
:1003A00065E023C01496ED91FC91159764E01DC0A3
:1003B0001496ED91FC91159766E017C01496ED9197
:1003C000FC91159762E011C01496ED91FC91159780
:1003D0006AE00BC01496ED91FC91159768E005C09A
:1003E0001496ED91FC91159769E0DF91CF910994F6
:1003F000CF93DF93EC01CB01BA0126E030E040E07F
:1004000050E00E944016623071058105910559F156
:100410008CF46115710581059105F1F0613071056C
:1004200081059105C1F5E881F9810480F581E02D10
:1004300065E02DC0643071058105910511F1D4F09E
:10044000653071058105910531F5E881F9810480F8
:10045000F581E02D66E01BC0E881F9810480F5811B
:10046000E02D64E014C0E881F9810480F581E02D7D
:1004700061E00DC0E881F9810480F581E02D63E041
:1004800006C0E881F9810480F581E02D62E0CE01AB
:10049000DF91CF910994DF91CF9108954370552753
:1004A00066277727DC01ED91FC910480F581E02D32
:1004B000423051056105710571F043305105610508
:1004C000710559F0413051056105710511F065E084
:1004D00005C066E003C06AE001C069E00994CF93FB
:1004E000DF93EC01CB01BA0123E030E040E050E0C3
:1004F0000E944016613071058105910581F06230DE
:1005000071058105910591F0672B682B692BC1F46A
:10051000E881F9810480F581E02D64E00DC0E88177
:10052000F9810480F581E02D61E006C0E881F98160
:100530000480F581E02D62E0CE01DF91CF91099436
:10054000DF91CF9108954370552766277727DC0107
:10055000ED91FC910480F581E02D4230510561055B
:10056000710571F0433051056105710559F0413055
:1005700051056105710511F062E005C063E003C03B
:1005800061E001C060E009940F931F93CF93DF9364
:10059000EC01E881F9810480F581E02D8C010D5B8F
:1005A0001F4FD8018C91811102C060E001C062E050
:1005B000CE010995E881F9810480F581E02DD8010B
:1005C0008C91811102C061E001C063E0CE01099508
:1005D0008BA59CA58230910538F0880F991F880F54
:1005E000991F05970197F1F7E881F9810480F5815A
:1005F000E02DD8018C91811102C060E001C062E061
:10060000CE01DF91CF911F910F910994CF93DF938A
:10061000EC0120E030E0A9016B897C898D899E89FD
:100620000E94141618161CF4EFA5F8A902C0E9A937
:10063000FAA9DF91CF9109940F931F93DC011296D1
:10064000EC910E2F10E009301105C0F5F801E55CC2
:10065000FF4F0C945F16DC01ED91FC910084F18555
:10066000E02D29C0DC01ED91FC910284F385E02DA1
:1006700022C0DC01ED91FC910484F585E02D1BC0C6
:10068000DC01ED91FC910684F785E02D14C0DC01BE
:10069000ED91FC910088F189E02D0DC0DC01ED9118
:1006A000FC910288F389E02D06C0DC01ED91FC91FC
:1006B0000488F589E02D1F910F9109941F910F91E6
:1006C0000895CF93DF93FC012281222359F1EC019D
:1006D00061E083810E94080D61E08C810E94080D19
:1006E0008A81843011F0883039F461E08D810E9474
:1006F000080D61E08E8106C0833011F0863021F450
:1007000061E08D810E94080D8EA58F3F59F061E058
:100710000E94080D6DA581E068278EA5DF91CF911D
:100720000C94BB0CDF91CF910895CF93DF93FC0124
:100730002281222389F0EC010190F081E02D0480D8
:10074000F581E02D60E009958EA58F3F29F06DA51C
:10075000DF91CF910C94BB0CDF91CF910895CF9294
:10076000DF92EF92FF920F931F93CF93DF93EC01F1
:100770009A81943041F0983031F0933031F09630D6
:1007800021F012E003C014E001C013E02396E12C35
:10079000F12CC62ED12C01E0C6010E2C02C095957D
:1007A00087950A94E2F76C8180FD602789910E9409
:1007B000BB0C8FEFE81AF80AE11670F3DF91CF91C6
:1007C0001F910F91FF90EF90DF90CF900895FC0163
:1007D000848DDF01A80FB11DA35ABF4F2C91848DCA
:1007E00090E001968F739927848FA689B7892C93FF
:1007F000A089B1898C91837080648C93938D848D52
:10080000981306C00288F389E02D80818F7D808354
:100810000895EF92FF920F931F93CF93DF93EC0114
:1008200081E0888F9B8D8C8D981305C0E889F989AC
:10083000808185FD26C0F62E0B8D10E00F5F1F4FC7
:100840000F731127E02E8C8DE8120CC00FB607FC39
:10085000FACFE889F989808185FFF5CFCE010E9422
:10086000E703F1CF8B8DFE01E80FF11DE35AFF4F37
:10087000F0829FB7F8940B8FEA89FB8980818062B0
:100880000AC09FB7F894EE89FF896083E889F989E7
:1008900080818370806480839FBF81E090E0DF91DE
:1008A000CF911F910F91FF90EF900895CF93DF9319
:1008B000EC01888D8823C9F0EA89FB89808185FD58
:1008C00005C0A889B9898C9186FD0FC00FB607FCB9
:1008D000F5CF808185FFF2CFA889B9898C9185FFFA
:1008E000EDCFCE010E94E703E7CFDF91CF910895CE
:1008F0004F925F926F927F92AF92BF92CF92DF92B0
:10090000EF92FF920F931F93CF93DF93CDB7DEB794
:10091000C454D1090FB6F894DEBF0FBECDBF5C0141
:100920002A013B016801790123E042E064E0CE0145
:1009300001960E941F0A8AE0A816B10421F4CE0194
:1009400001960E94E30BC301B2010E94DE150C85E3
:100950001D852E853F85DC01CB01800F911FA21FD5
:10096000B31F088919892A893B89081719072A079B
:100970003B0741F0888B998BAA8BBB8BCE010196EC
:100980000E94CB08B701A601CE0101960E94BC0AC5
:10099000488959896A897B890C851D852E853F8503
:1009A000CCA0DDA0EEA0FFA004171507260737078F
:1009B00014F481E001C080E040175107620773071B
:1009C00069F0C114D104E104F104B1F325968FAFAD
:1009D0002597CE0101960E94690DDACFCC5BDF4FDF
:1009E0000FB6F894DEBF0FBECDBFDF91CF911F9140
:1009F0000F91FF90EF90DF90CF90BF90AF907F90DE
:100A00006F905F904F9008958F929F92AF92BF9298
:100A1000CF92DF92EF92FF920F931F93CF93DF93CA
:100A2000CDB7DEB7C454D1090FB6F894DEBF0FBE00
:100A3000CDBF6C017B018A0123E042E064E0CE017E
:100A400001960E941F0A8AE0C816D10421F4CE0143
:100A500001960E94E30BC701FF0CAA0BBB0B4C8550
:100A60005D856E857F85840F951FA61FB71F4889FA
:100A700059896A897B89481759076A077B0741F0BA
:100A8000888B998BAA8BBB8BCE0101960E94CB08D9
:100A9000B801110F880B990B0E948E13AB01BC019A
:100AA000CE0101960E94BC0ACC8CDD8CEE8CFF8CB2
:100AB00020E030E04AEF53E4C701B6010E948713FB
:100AC000882381F16CA97DA98EA99FA90E948E130C
:100AD0004B015C0120E030E04AEF53E4C701B6016E
:100AE0000E946C159B01AC01C501B4010E94ED137D
:100AF0000E94DE156CAB7DAB8EAB9FAB80E092E0CD
:100B0000A7E2B7E488AF99AFAAAFBBAF80E090E0AF
:100B1000AAEFB3E48C8F9D8FAE8FBF8FCE0101966D
:100B20000E94CB08488959896A897B898C859D8573
:100B3000AE85BF85481759076A077B0759F18CA115
:100B40009DA1AEA1BFA1892B8A2B8B2B51F0CE0189
:100B500001960E94690D882321F0CE0101960E9422
:100B6000CB0820E030E0A9016C897D898E899F89BE
:100B70000E9487138111E3CF488959896A897B894B
:100B80008C859D85AE85BF85481759076A077B0709
:100B9000B1F6C8CFCC5BDF4F0FB6F894DEBF0FBE07
:100BA000CDBFDF91CF911F910F91FF90EF90DF901C
:100BB000CF90BF90AF909F908F9008958F929F920B
:100BC000AF92BF92CF92DF92EF92FF926A017B01C8
:100BD0000E94380BA7019601C701B6010E941916A1
:100BE000882319F082E391E01AC046015701E89486
:100BF000B7F82FEF3FEF4FE75FE7C501B4010E9461
:100C0000191681110FC02FEF3FEF4FE75FE7C501C6
:100C1000B4010E94871318162CF486E391E00E9419
:100C2000380B76C02FEF3FEF4FE75FE4C701B60107
:100C30000E94141618161CF48AE391E0F0CF2FEFEF
:100C40003FEF4FE75FECC701B6010E94871387FDB6
:100C5000F3CF20E030E0A901C701B6010E9487135D
:100C600087FF09C06DE284EA91E00E940904F7FA67
:100C7000F094F7F8F0942AE037ED43EA5BE3C7011C
:100C8000B6010E9400154B015C010E94E5156B0145
:100C90007C010E948C139B01AC01C501B4010E9430
:100CA000FF144B015C014AE0C701B6010E94730BBF
:100CB0006EE284EA91E00E94090420E030E040E224
:100CC00051E4C501B4010E94ED134B015C010E9487
:100CD000E5156B01E12CF12C4AE0C701B6010E9439
:100CE000730BC701B6010E948C139B01AC01C501B7
:100CF000B4010E94FF1420E030E040E251E40E9481
:100D0000ED130E94E51580E090E04AE00E94730B2D
:100D10008EE391E0FF90EF90DF90CF90BF90AF9087
:100D20009F908F900C94380BFF920F931F93CF934B
:100D3000DF93F82E8B01C0919401D0919501CC5A8C
:100D4000DE4F84E591E00097B9F0FC012081222379
:100D500099F08C179D0780F42F1108C00196DF9140
:100D6000CF911F910F91FF900C94401360E270E0BF
:100D70000E948B170196E7CFC801DF91CF911F9199
:100D80000F91FF9008958F929F92BF92CF92DF9222
:100D9000EF92FF920F931F93CF93DF93CDB7DEB700
:100DA00029970FB6F894DEBF0FBECDBF962F50E047
:100DB00060E070E0592B682BCB01AA27BB27152FC9
:100DC000B82EBC01812C912CA0E0B0E020E030E0F6
:100DD000809187029091880228173907E0F5809169
:100DE0008C02882371F0869F7001879FF00C11247C
:100DF000819F600111240D2D849FC0011124592F62
:100E000003C0542F012FFB2CE0909202D0908F0250
:100E100080918D0290918E02ED1003C08A0F9B1F6E
:100E200007C0880D991D6C01CE0CD11CF6011082F3
:100E3000E0908F026C01CE0CD11CF601F082F09094
:100E40009002FC01EF0DF11D008300919102800FD3
:100E5000911DFC0150832F5F3F4F1396F4E08F0EDE
:100E6000911C2031310509F0B3CF80918D02909112
:100E70008E02892B09F4A1C00E94440D00919302B7
:100E8000109194022091950230919602DC01CB01E1
:100E9000801B910BA20BB30BC297A105B10560F3A8
:100EA000F8948091890290918A029A838983E091D3
:100EB0008D02F0918E02DF011196808189879091D9
:100EC0008502E0919702F09198028091990299230E
:100ED00009F42EC09081982B988790818095892362
:100EE0008F838F818C8388E08B8358856F814985C0
:100EF0003B812C8189819A81508347FD252F3A952A
:100F00002083262F39F0441F00C0000060830000BA
:100F100000C0F2CF38E04D9160830000019761F787
:100F2000F0939802E093970249873B832C8338C063
:100F30009081982B98879081809589238F838F81CA
:100F40008E8388E08D8358856F8149853D812E8110
:100F500089819A81508347FD252F00C000C02083DE
:100F600000C000C000C000C000C060830000262F89
:100F70003A9541F0441F000000C000C000C000C00E
:100F800000C0E8CF38E04D9100C0608300C00197F9
:100F900009F7F0939802E093970249873D832E83E7
:100FA0009A83898378940E94440D6093930270938E
:100FB0009402809395029093960229960FB6F89426
:100FC000DEBF0FBECDBFDF91CF911F910F91FF907C
:100FD000EF90DF90CF90BF909F908F900895CF9229
:100FE000DF92EF92FF920F931F93CF93DF936C01E9
:100FF0007A018B01C0E0D0E0CE15DF0581F0D80189
:101000006D918D01D601ED91FC910190F081E02D63
:10101000C6010995892B11F02196EECF7E01C701FB
:10102000DF91CF911F910F91FF90EF90DF90CF90C4
:101030000895089580E090E0089584EA91E00E9488
:101040009E0121E0892B09F420E0822F08950E945F
:1010500086171F920F920FB60F9211242F933F9372
:101060008F939F93AF93BF9380919C0190919D012B
:10107000A0919E01B0919F0130919B0123E0230F2D
:101080002D3720F40196A11DB11D05C026E8230FC0
:101090000296A11DB11D20939B0180939C0190930A
:1010A0009D01A0939E01B0939F018091A00190911A
:1010B000A101A091A201B091A3010196A11DB11DB2
:1010C0008093A0019093A101A093A201B093A301EA
:1010D000BF91AF919F918F913F912F910F900FBE34
:1010E0000F901F9018951F920F920FB60F92112418
:1010F0002F933F934F935F936F937F938F939F9320
:10110000AF93BF93EF93FF9384EA91E00E94E703CC
:10111000FF91EF91BF91AF919F918F917F916F91CF
:101120005F914F913F912F910F900FBE0F901F90A5
:1011300018951F920F920FB60F9211242F938F9331
:101140009F93EF93FF93E091B401F091B5018081FB
:10115000E091BA01F091BB0182FD12C090818091B3
:10116000BD018F5F8F732091BE01821751F0E09116
:10117000BD01F0E0EC55FE4F958F8093BD0101C09D
:101180008081FF91EF919F918F912F910F900FBED2
:101190000F901F9018954F925F926F927F928F924F
:1011A0009F92AF92BF92CF92DF92EF92FF920F93F6
:1011B0001F93CF93DF93EC018F849888A988BA8816
:1011C0008B859C85AD85BE85881A990AAA0ABB0ABB
:1011D0006B897C898D899E899B01AC010E94ED13EE
:1011E0006B017C016B8D7C8D8D8D9E8D9B01AC0187
:1011F0000E9400159B01AC01C701B6010E946C154D
:101200000E94DE1581149104A104B10499F46230A6
:101210007105810591050CF079C01BA21CA21DA2CD
:101220001EA21B8A1C8A1D8A1E8A1BAA1CAA1DAA12
:101230001EAAF4C00BA91CA92DA93EA9FE01ED5BB5
:10124000FF4F181419041A041B04FCF4101611069D
:10125000120613064CF4681579058A059B054CF5B2
:101260002081211153C025C001151105210531052B
:1012700009F44CC0681579058A059B050CF046C039
:101280008081882309F442C036C010161106120668
:101290001306ECF4002711279801081919092A09E7
:1012A0003B0960177107820793071CF420812223F2
:1012B00069F19B01AC0188279927DC01821B930B04
:1012C000A40BB50B8BAB9CABADABBEAB1FC001157C
:1012D000110521053105D1F0CC24DD247601C81893
:1012E000D908EA08FB086C157D058E059F0574F486
:1012F000808181110BC030952095109501951F4F6D
:101300002F4F3F4F0BAB1CAB2DAB3EABCBA8DCA89C
:10131000EDA8FEA88E010D5B1F4FC114D104E1049E
:10132000F10491F48FA998ADA9ADBAAD8BAF9CAF84
:10133000ADAFBEAF81E0181419041A041B040CF001
:1013400080E0F80180833EC08BAC9CACADACBEAC01
:10135000A5019401C501B4010E9400152B013C01B7
:10136000C701B6010E948E1320E030E040E850E44F
:101370000E94ED1320E030E040E85FE30E9400159A
:101380009B01AC01C301B2010E946C159B01AC0131
:10139000C501B4010E94FF142B013C01FE01FF9620
:1013A00080809180A280B3809401A5010E941416D0
:1013B000181614F442015301C401D5018BAF9CAF40
:1013C000ADAFBEAFFFEFCF1ADF0AEF0AFF0ACBAA1D
:1013D000DCAAEDAAFEAACBACDCACEDACFEACC7013E
:1013E000B6010E94E5156BA37CA38DA39EA3A70164
:1013F000960160E074E284E799E40E946C156B8BBF
:101400007C8B8D8B9E8BF8012081211107C0DC0124
:10141000CB01B0588B8B9C8BAD8BBE8BDF91CF916A
:101420001F910F91FF90EF90DF90CF90BF90AF9002
:101430009F908F907F906F905F904F9008958F92C4
:101440009F92AF92BF92CF92DF92EF92FF92CF9393
:10145000DF93EC018AE091E0998388836A831B869D
:101460001C861D861E861F86188A198A1A8A1B8A60
:101470001C8A1D8A1E8AC12CD12C80E8E82E8FE39D
:10148000F82ECF8AD88EE98EFA8E1B8E1C8E1D8E7A
:101490001E8ECF8ED8A2E9A2FAA21BA21CA21DA268
:1014A0001EA281E090E09CA78BA78FEF8EA71FA2C2
:1014B00018A619A61AA64B832C8384E08D8385E099
:1014C0008E831BAA1CAA1DAA1EAA1FAA18AE19AE9B
:1014D0001AAE1BAE1CAE1DAE1EAEFE01FF96C08244
:1014E000D182E282F382349610821F821886198696
:1014F0001A86CE010E9461038B8C9C8CAD8CBE8CB5
:10150000A7019601C501B4010E948713882349F100
:101510006BA97CA98DA99EA90E948E13A501940197
:101520000E94ED130E94DE156BAB7CAB8DAB9EABC6
:1015300086E896E6A9E6B9E48FAB98AFA9AFBAAF53
:10154000CB8EDC8EED8EFE8ECE01DF91CF91FF90A3
:10155000EF90DF90CF90BF90AF909F908F900C94C2
:10156000CB08DF91CF91FF90EF90DF90CF90BF90AD
:10157000AF909F908F9008954F925F926F927F925D
:10158000AF92BF92CF92DF92EF92FF920F931F9391
:10159000CF93DF93EC015A018B019A01AB016B8968
:1015A0007C898D899E890E948713882309F451C004
:1015B000CF88D88CE98CFA8C2601370177FA7094A1
:1015C00077F87094A3019201B501C8010E948713B6
:1015D00087FD0BC0A7019601B501C8010E94141632
:1015E00018162CF06501780102C07301620120E039
:1015F00030E0A901C701B6010E948713811105C01F
:101600001BA21CA21DA21EA220C0A701960160E081
:1016100074E284E799E40E946C159F770E94E515B7
:101620006BA37CA38DA39EA35E0183E4A80EB11CD3
:1016300011E020E030E0A901C701B6010E941416B4
:1016400018160CF010E0F5011083CB8ADC8AED8AC5
:10165000FE8ADF91CF911F910F91FF90EF90DF9065
:10166000CF90BF90AF907F906F905F904F90089514
:10167000009769F0FC0101900020E9F73197AF0174
:10168000481B590BBC0184EA91E00C94EF0780E001
:1016900090E008950F931F93CF93DF938C01C0E0E8
:1016A000D0E0F801EC0FFD1F6491662341F084EA5D
:1016B00091E00E940904892B11F02196F2CFCE010E
:1016C000DF91CF911F910F910895CF93DF930E94E7
:1016D0004A0BEC018EE391E00E94380B8C0F9D1FAA
:1016E000DF91CF9108958F929F92AF92BF920F9307
:1016F0001F93CF93DF93CDB7DEB7A1970FB6F894C2
:10170000DEBF0FBECDBF19A2423008F44AE08E0101
:101710000F5D1F4F842E912CA12CB12CA50194019B
:101720000E941E16E62FB901CA0101501109EA30C4
:1017300014F4E05D01C0E95CD801EC93232B242B69
:10174000252B61F7C8010E94380BA1960FB6F894BB
:10175000DEBF0FBECDBFDF91CF911F910F91BF9024
:10176000AF909F908F900895CF92DF92EF92FF926B
:10177000CF93DF936B017C016DE284EA91E00E94DC
:101780000904EC0166277727CB016C197D098E09C6
:101790009F094AE00E94730B8C0F9D1FDF91CF9130
:1017A000FF90EF90DF90CF900895CF93DF930E944A
:1017B000380BEC018EE391E00E94380B8C0F9D1FDB
:1017C000DF91CF910895FC01A1E4B2E012968C91D3
:1017D0001297828313968C911397838314968C911E
:1017E0001497848315968C911597858316968C9102
:1017F0001697868317968C911797878318968C91E6
:101800001897808719968C91199781871A968C91D1
:101810001A9782871B964D915D916D917C911E97D1
:1018200043875487658776871F964D915D916D91AB
:101830007C9152974787508B618B728B53964D9159
:101840005D916D917C915697438B548B658B768B14
:1018500057964D915D916D917C915A97478B508F22
:10186000618F728F5B964D915D916D917C915E97CA
:10187000438F548F658F768F5F964D915D916D91FB
:101880007C919297478F50A361A372A393964D9139
:101890005D916D917C91969743A354A365A376A324
:1018A00097964D915D916D917C919A9747A350A722
:1018B00061A772A79B968D919C919C9794A783A7F3
:1018C0009D968C919D9785A79E968C919E9786A7B5
:1018D0009F968D919C91D09790AB87A7D1968D9133
:1018E0009C91D29792AB81ABD3964D915D916D91C6
:1018F0007C91D69743AB54AB65AB76ABD7964D9105
:101900005D916D917C91DA9747AB50AF61AF72AF4B
:10191000DB968D919D910D90BC91A02D83AF94AFDE
:10192000A5AFB6AF409180025091810260918202D2
:1019300070918302DF01DF964D935D936D937C93ED
:1019400013978091840214968C93CF010895CF93BE
:10195000DF9397FF03C00E94B40B03C04AE00E94CC
:10196000730BEC018EE391E00E94380B8C0F9D1FEE
:10197000DF91CF91089590E0FC01E45CFD4F24914C
:10198000FC01E05BFD4F3491FC01E259FD4FE49115
:10199000EE2309F43CC0222339F1233091F038F4CE
:1019A0002130A9F0223001F584B58F7D12C0273097
:1019B00091F02830A1F02430B9F4809180008F7D1F
:1019C00003C0809180008F77809380000DC084B524
:1019D0008F7784BD09C08091B0008F7703C080915C
:1019E000B0008F7D8093B000F0E0EE0FFF1FEC5948
:1019F000FD4FA591B4919FB7F894611104C08C91EB
:101A00003095382302C0EC913E2B3C939FBF089544
:101A1000CF93DF9390E0FC01E05BFD4F2491FC014C
:101A2000E259FD4F8491882361F190E0880F991F5E
:101A3000FC01EE5CFD4FC591D491FC01EC59FD4FCA
:101A4000A591B491611109C09FB7F8948881209540
:101A500082238883EC912E230BC0623061F49FB700
:101A6000F8948881322F309583238883EC912E2B34
:101A70002C939FBF06C08FB7F894E8812E2B288344
:101A80008FBFDF91CF9108953FB7F8948091A00167
:101A90009091A101A091A201B091A30126B5A89BAC
:101AA00005C02F3F19F00196A11DB11D3FBFBA2FF0
:101AB000A92F982F8827820F911DA11DB11DBC0150
:101AC000CD0142E0660F771F881F991F4A95D1F715
:101AD0000895CF92DF92EF92FF92CF93DF93EC01C4
:101AE0000E94440D6B017C014FA158A569A57AA500
:101AF0008BA19CA1ADA1BEA1840F951FA61FB71FEE
:101B000084179507A607B70730F0C816D906EA0666
:101B1000FB0658F405C0C816D906EA06FB0638F1DC
:101B2000C416D506E606F70610F5FE01ED5BFF4F7D
:101B300020818B859C85AD85BE85222321F0019671
:101B4000A11DB11D03C00197A109B1098B879C8715
:101B5000AD87BE874B855C856D857E85CE010E94F5
:101B60001C03CFA2D8A6E9A6FAA681E001C080E0B6
:101B7000DF91CF91FF90EF90DF90CF90089580910B
:101B80008D0290918E02009711F00E94FD168091B7
:101B90008B0287FD03C060E00C94080D08957894D3
:101BA00084B5826084BD84B5816084BD85B5826062
:101BB00085BD85B5816085BD80916E008160809313
:101BC0006E0010928100809181008260809381007C
:101BD000809181008160809381008091800081608C
:101BE000809380008091B10084608093B1008091E7
:101BF000B00081608093B00080917A00846080930F
:101C00007A0080917A00826080937A0080917A00D5
:101C1000816080937A0080917A00806880937A0056
:101C20001092C100E091B401F091B50182E080838F
:101C3000E091B401F091B5011082E091B001F09112
:101C4000B1011082E091B201F091B30180E1808393
:101C50001092BC01E091B801F091B90186E0808357
:101C6000E091B601F091B701808180618083E091BD
:101C7000B601F091B701808188608083E091B60160
:101C8000F091B701808180688083E091B601F09186
:101C9000B70180818F7D808361E089E00E94080D1B
:101CA00061E08AE00E94080D61E08FE00E94080D6B
:101CB00060E08FE00E94BB0C60E089E00E94BB0CFA
:101CC00060E08AE00E94BB0C61E083E10E94080DA5
:101CD00060E083E10E94BB0C61E082E00E94080D9D
:101CE00061E085E00E94080D61E083E00E94080D3C
:101CF00061E086E00E94080D61E083E10E94BB0C78
:101D000020E030E04AEF54E46091580270915902AB
:101D100080915A0290915B020E948713882309F4F4
:101D200053C080E090E0AAEFB4E48093580290930F
:101D30005902A0935A02B0935B0280E090E0AAEFB0
:101D4000B3E48093800290938102A0938202B093C7
:101D500083028091740290917502A0917602B091F5
:101D60007702181619061A061B0674F560915402BC
:101D70007091550280915602909157029B01AC01DF
:101D80000E94ED136B017C0160915C0270915D0219
:101D900080915E0290915F029B01AC010E94001550
:101DA0009B01AC01C701B6010E946C150E94DE15B3
:101DB0006093740270937502809376029093770219
:101DC00081E492E00E94CB0840E050E06FE274E4CE
:101DD00081E492E00E94BC0A61E082E00E94BB0CB8
:101DE00080918B0287FD08C061E00E94080D60E0D1
:101DF00080918B020E94BB0C81E08093860261E09F
:101E000082E00E94BB0C61E085E00E94BB0C84EA8A
:101E100091E00E949E01181619060CF0FAC184EA9E
:101E200091E00E947C01C82F682F84EA91E00E9413
:101E3000090480919401909195018F3391055CF490
:101E40009C012F5F3F4F3093950120939401FC013B
:101E5000EC5AFE4FC083CA3011F0CD30C1F6E0918C
:101E60009401F0919501EC5AFE4F1082C0915401FB
:101E7000CB3309F4C5C16FEF7FEF8EE40E94940667
:101E8000092E000CAA0BBB0B8F3F2FEF9207A20766
:101E9000B20709F45CC0CE3409F059C0C090960175
:101EA000D0909701E0909801F09099018C159D05D4
:101EB000AE05BF0539F084E292E00E944A0BC701EB
:101EC000B6012FC06AE270E084E591E00E948B17B2
:101ED000892B09F495C1E4E5F1E0C0E09F012455A8
:101EE000314091919A3211F0C927F8CF60E070E04B
:101EF000C9018B5A9E4F0E94F2110E94DE152C2FB1
:101F0000CC0F330B2617370779F087E192E00E9458
:101F10004A0B609196017091970180919801909180
:101F200099010E94A70C6CC1809196019091970134
:101F3000A0919801B09199010196A11DB11D8093C6
:101F4000960190939701A0939801B09399016FEF38
:101F50007FEF87E40E9494068230910581F01CF4A3
:101F600097FF30C06EC08630910509F464C0873099
:101F7000910509F464C0049709F063C023C060E0D0
:101F800070E086E40E9494067C0160E070E08CE4DE
:101F90000E949406EC0160E070E084E50E949406E3
:101FA000009731F0A701BC018AE090E00E9404058F
:101FB000209709F446C0A701BE018BE090E00E9483
:101FC00004053FC060E070E086E40E949406BC0116
:101FD000990F880B990B0E948E136B017C0160E0B6
:101FE00070E08CE40E949406EC0160E070E084E50F
:101FF0000E949406009771F0BC01990F880B990B11
:102000000E948E13AB01BC01970186018AE090E02B
:102010000E9478042097A9F0BE01DD0F880B990B70
:102020000E948E13AB01BC01970186018BE090E00A
:102030000E94780406C081E080939A0102C0109249
:102040009A016FEF7FEF8DE40E9494068531910530
:1020500009F4ABC0CCF48131910509F49AC044F481
:102060008430910509F477C0059709F47CC0C8C095
:102070008331910509F494C00CF094C061E082E0D2
:102080000E94BB0C61E08AC08E36910509F494C0B1
:10209000ECF58631910509F48AC08436910509F082
:1020A000AFC081EF91E00E944A0B81E491E00E9471
:1020B000D50B87EE91E00E94650B89EC91E00E94C0
:1020C000650B89E991E00E94650B84E891E00E942C
:1020D000650B8EE691E00E94650B84E591E00E941D
:1020E000650B89E391E00E94650B8EE191E00E940F
:1020F000650B82E091E00E94650B88EE90E00E9403
:10210000650B83EC90E00E94650B7AC0883C9105DA
:1021100009F466C0893C910509F467C082379105CE
:1021200009F06EC040E050E0BA018CE491E00E94FA
:10213000DE0540E050E0BA0182E591E00E94DE0554
:1021400040E050E46CE176E48EE491E00E94DE052C
:1021500080E591E047C060E089E00E94BB0C60E050
:102160008AE00E94BB0C60E070E082E40E9494066A
:102170007C0160E070E087E40E949406EC0160E07E
:1021800070E082E50E949406A701BE010E94C3068A
:1021900037C060E082E00E94BB0C60E085E009C0CF
:1021A00061E001C060E08AE004C061E001C060E07D
:1021B00089E00E94BB0C24C0609196017091970148
:1021C0008EE40E949406092E000CAA0BBB0B809390
:1021D000960190939701A0939801B093990110C034
:1021E00081E491E00E94D50B0BC04AE061E070E011
:1021F00080E090E00E94730B8EE391E00E94380B28
:10220000109295011092940180E392E00E94650B78
:10221000FECD80919A018823E1F140E050E06AE729
:1022200074E481E492E00E94BC0A80914C02909197
:102230004D02A0914E02B0914F020A96A11DB11D10
:10224000409150025091510260915202709153029C
:1022500084179507A607B70761F080935002909303
:102260005102A0935202B093530281E492E00E9483
:10227000CB088091640290916502A0916602B091B2
:102280006702892B8A2B8B2B21F081E492E00E943C
:10229000690D0E94AA01BBCD1092A7011092A60160
:1022A00088EE93E0A0E0B0E08093A8019093A901AC
:1022B000A093AA01B093AB0184E291E09093A501B1
:1022C0008093A40185EC90E09093B1018093B001DC
:1022D00084EC90E09093B3018093B20180EC90E0A5
:1022E0009093B5018093B40181EC90E09093B70195
:1022F0008093B60182EC90E09093B9018093B8018D
:1023000086EC90E09093BB018093BA011092BD01DE
:102310001092BE011092BF011092C00124E043E070
:1023200062E081E492E00E941F0A109286021092FD
:102330008C021092930210929402109295021092C5
:10234000960281E08093920280938F021092900215
:1023500092E0909391028093850280E390E09093C5
:102360008A02809389020E94651690938E02809360
:102370008D02009761F020E3FC0111922A95E9F7A4
:1023800080E190E0909388028093870208C01092C9
:102390008A021092890210928802109287028FE0BE
:1023A00080938B0280918602882341F061E08FE068
:1023B0000E94080D60E08FE00E94BB0CEDE7F2E0A8
:1023C000E491F0E0EE0FFF1FEC59FD4F85919491E1
:1023D0009093980280939702EFE5F2E0E491E09306
:1023E00099020895A0E0B0E0E8EFF1E10C94BF1489
:1023F000EC016B016115710519F0FB01918380837C
:102400007E01FFEFEF1AFF0A0881802F90E00E9403
:102410005E13892B11F0E701F3CF0D3239F47E0101
:1024200082E0E80EF11C098111E008C00B3229F4AA
:102430007E0192E0E90EF11C098110E0E70121978D
:1024400043E050E060E970E0CE010E946713892B01
:10245000C1F4239645E050E06BE870E0CE010E94A5
:102460006713892B09F42596C114D10419F0F601DC
:10247000D183C0831111F6C060E070E080E89FE76F
:10248000FAC043E050E068E870E0CE010E946713B4
:10249000892B59F4C114D10409F4E9C0F2E0EF0E1C
:1024A000F11CF601F182E082E2C020E030E0A901F7
:1024B000C0E0D0E0F70180EDA82EA00E89E08A15DB
:1024C00030F1912F9260B92E812F887012FF04C0D5
:1024D000811124C0219622C081112197A5E0B0E08E
:1024E0000E94AE14DC01CB01880F991FAA1FBB1FED
:1024F0009C01AD012A0D311D411D511D283989E96D
:102500003807480789E1580748F0166006C09EEF73
:10251000A9120AC013FD40C01860B12E8FEFE81A4F
:10252000F80A00811B2DC6CF802F8F7D8534A1F541
:1025300080818D3211F4106106C08B3221F031960A
:1025400061E070E004C08181329662E070E0805307
:102550008A3018F0E61BF70B1FC060E070E06038AF
:102560009CE079075CF4DB01AA0FBB1FAA0FBB1F1D
:102570006A0F7B1F660F771F680F711D3196DF0191
:1025800011978C9180538A3050F314FF03C07195DA
:1025900061957109C60FD71F11FF08C0C114D1047E
:1025A00029F0CF010197F60191838083CA01B90117
:1025B0000E948C13212F2370233019F04B015C01F2
:1025C00006C04B015C01B7FAB094B7F8B09420E0B4
:1025D00030E0A901C501B4010E948713882309F4E2
:1025E0003EC0D7FF06C0D195C195D10907EA10E0DA
:1025F00002C00FEB10E06801F8E1CF1AD10890E2B9
:10260000E92EF12CCE15DF0574F0F80125913591F6
:1026100045915491C501B4010E94ED134B015C0139
:10262000CE19DF09EFCF04501109F594E7940C158A
:102630001D0541F78A2D880F8B2D881F8F3F49F08C
:1026400020E030E0A901C501B4010E948713811187
:1026500006C082E290E090939B0280939A02C501AB
:10266000B40109C060E070E080E89FEF04C060E062
:1026700070E080EC9FE7CDB7DEB7ECE00C94DB14A4
:10268000FC0188279927E89421912032E9F3293029
:1026900010F02E30C8F32B3241F02D3239F468940B
:1026A00004C00E947F13820F911D219120532A3074
:1026B000C0F31EF4909581959F4F089591110C944D
:1026C0005A14803219F089508550C8F70895FB01DB
:1026D000DC014150504088F08D9181341CF08B35E5
:1026E0000CF4805E659161341CF06B350CF4605E17
:1026F000861B611171F3990B0895881BFCCF7AE05A
:10270000979F902D879F802D910D112408950E94F1
:10271000C91308F481E00895E89409C097FB3EF4DA
:1027200090958095709561957F4F8F4F9F4F99231E
:10273000A9F0F92F96E9BB279395F695879577959C
:102740006795B795F111F8CFFAF4BB0F11F460FF5C
:102750001BC06F5F7F4F8F4F9F4F16C0882311F0B4
:1027600096E911C0772321F09EE8872F762F05C0C8
:10277000662371F096E8862F70E060E02AF09A9563
:10278000660F771F881FDAF7880F9695879597F958
:102790000895990F0008550FAA0BE0E8FEEF1616F2
:1027A0001706E807F907C0F012161306E407F50745
:1027B00098F0621B730B840B950B39F40A2661F0B9
:1027C000232B242B252B21F408950A2609F4A1405C
:1027D000A6958FEF811D811D08950E9400140C9411
:1027E00074140E94661438F00E946D1420F0952332
:1027F00011F00C945D140C94631411240C94A8141F
:102800000E94851470F3959FC1F3950F50E0551FFA
:10281000629FF001729FBB27F00DB11D639FAA2735
:10282000F00DB11DAA1F649F6627B00DA11D661F84
:10283000829F2227B00DA11D621F739FB00DA11DA5
:10284000621F839FA00D611D221F749F3327A00D5F
:10285000611D231F849F600D211D822F762F6A2FFB
:1028600011249F5750409AF0F1F088234AF0EE0F60
:10287000FF1FBB1F661F771F881F91505040A9F78D
:102880009E3F510580F00C945D140C94A8145F3F9A
:10289000E4F3983ED4F3869577956795B795F795C9
:1028A000E7959F5FC1F7FE2B880F911D9695879541
:1028B00097F9089599278827089597F99F6780E8E1
:1028C00070E060E008959FEF80EC089500240A9482
:1028D0001616170618060906089500240A941216FB
:1028E0001306140605060895092E0394000C11F42E
:1028F000882352F0BB0F40F4BF2B11F460FF04C0DB
:102900006F5F7F4F8F4F9F4F089557FD9058440F33
:10291000551F59F05F3F71F04795880F97FB991F3E
:1029200061F09F3F79F087950895121613061406FB
:10293000551FF2CF4695F1DF08C016161706180688
:10294000991FF1CF86957105610508940895E89463
:10295000BB2766277727CB0197F908950E94F014CB
:10296000A59F900DB49F900DA49F800D911D1124E3
:1029700008952F923F924F925F926F927F928F9223
:102980009F92AF92BF92CF92DF92EF92FF920F93FE
:102990001F93CF93DF93CDB7DEB7CA1BDB0B0FB608
:1029A000F894DEBF0FBECDBF09942A8839884888C5
:1029B0005F846E847D848C849B84AA84B984C8845B
:1029C000DF80EE80FD800C811B81AA81B981CE0F52
:1029D000D11D0FB6F894DEBF0FBECDBFED01089537
:1029E000A29FB001B39FC001A39F700D811D112450
:1029F000911DB29F700D811D1124911D0895505895
:102A0000BB27AA270E9417150C9474140E94661401
:102A100038F00E946D1420F039F49F3F19F426F429
:102A20000C9463140EF4E095E7FB0C945D14E92F0D
:102A30000E94851458F3BA17620773078407950735
:102A400020F079F4A6F50C94A7140EF4E0950B2E63
:102A5000BA2FA02D0B01B90190010C01CA01A001F0
:102A60001124FF27591B99F0593F50F4503E68F14B
:102A70001A16F040A22F232F342F4427585FF3CF8C
:102A8000469537952795A795F0405395C9F77EF45D
:102A90001F16BA0B620B730B840BBAF09150A1F0A6
:102AA000FF0FBB1F661F771F881FC2F70EC0BA0F2C
:102AB000621F731F841F48F4879577956795B795B4
:102AC000F7959E3F08F0B0CF9395880F08F09927AF
:102AD000EE0F9795879508950E9480150C947414B5
:102AE0000E946D1458F00E94661440F029F45F3F74
:102AF00029F00C945D1451110C94A8140C946314D7
:102B00000E94851468F39923B1F3552391F3951B23
:102B1000550BBB27AA2762177307840738F09F5FFE
:102B20005F4F220F331F441FAA1FA9F335D00E2E6B
:102B30003AF0E0E832D091505040E695001CCAF7D8
:102B40002BD0FE2F29D0660F771F881FBB1F26179B
:102B500037074807AB07B0E809F0BB0B802DBF0172
:102B6000FF2793585F4F3AF09E3F510578F00C9441
:102B70005D140C94A8145F3FE4F3983ED4F386955B
:102B800077956795B795F7959F5FC9F7880F911D62
:102B90009695879597F90895E1E0660F771F881F4E
:102BA000BB1F621773078407BA0720F0621B730B01
:102BB000840BBA0BEE1F88F7E09508950E94E51587
:102BC0006894B1110C94A81408950E948D1488F093
:102BD0009F5798F0B92F9927B751B0F0E1F0660FE1
:102BE000771F881F991F1AF0BA95C9F714C0B13022
:102BF00091F00E94A714B1E008950C94A714672FD8
:102C0000782F8827B85F39F0B93FCCF38695779550
:102C10006795B395D9F73EF4909580957095619539
:102C20007F4F8F4F9F4F08950E94C91308F48FEF75
:102C300008950E94C913880B990B0895A1E21A2EDA
:102C4000AA1BBB1BFD010DC0AA1FBB1FEE1FFF1F50
:102C5000A217B307E407F50720F0A21BB30BE40BA0
:102C6000F50B661F771F881F991F1A9469F76095E7
:102C70007095809590959B01AC01BD01CF010895A1
:102C8000052E97FB1EF400940E94571657FD07D09F
:102C90000E941E1607FC03D04EF40C945716509554
:102CA0004095309521953F4F4F4F5F4F0895909538
:102CB0008095709561957F4F8F4F9F4F0895EE0FD0
:102CC000FF1F0590F491E02D09940F931F93CF936C
:102CD000DF938230910510F482E090E0E0919E0253
:102CE000F0919F0220E030E0A0E0B0E0309719F1D1
:102CF000408151810281138148175907C8F0841718
:102D0000950769F4109731F012960C931297139669
:102D10001C9327C000939E0210939F0222C021158E
:102D2000310519F04217530718F49A01BD01EF015C
:102D3000DF01F801DBCF21153105F9F0281B390B34
:102D40002430310580F48A819B816115710521F061
:102D5000FB019383828304C090939F0280939E0221
:102D6000FE01329644C0FE01E20FF31F819391935E
:102D700022503109398328833AC020919C02309136
:102D80009D02232B41F420910201309103013093E5
:102D90009D0220939C022091000130910101211598
:102DA000310541F42DB73EB7409104015091050122
:102DB000241B350BE0919C02F0919D02E217F30772
:102DC000A0F42E1B3F0B2817390778F0AC014E5F9B
:102DD0005F4F2417350748F04E0F5F1F50939D0239
:102DE00040939C028193919302C0E0E0F0E0CF0118
:102DF000DF91CF911F910F910895CF93DF930097AB
:102E000009F481C0FC01329713821282A0919E02C4
:102E1000B0919F02109781F420813181820F931F1E
:102E200020919C0230919D022817390751F5F093AB
:102E30009D02E0939C0267C0ED0120E030E0CE17D8
:102E4000DF0740F44A815B819E0141155105F1F095
:102E5000EA01F5CFD383C28340815181840F951F4E
:102E6000C817D90759F488819981840F951F029654
:102E7000918380838A819B8193838283211531058D
:102E800029F4F0939F02E0939E023DC0E901FB8389
:102E9000EA8349915991C40FD51FEC17FD0761F4DE
:102EA00080819181840F951F0296E901998388831F
:102EB000828193819B838A83E0E0F0E012968D917A
:102EC0009C911397009719F0FD01DC01F7CF8D91CC
:102ED0009C9111979D012E5F3F4F820F931F209170
:102EE0009C0230919D022817390769F4309729F424
:102EF00010929F0210929E0202C013821282B0931F
:102F00009D02A0939C02DF91CF91089581E090E013
:102F1000F8940C949617FC018191861721F0882370
:102F2000D9F7992708953197CF01089511E0C2E4A8
:102F3000D1E004C0FE010E945F162196C334D10780
:062F4000C9F7F894FFCF71
:102F46000000A00280000000000095036103AF03AB
:102F56001C030603C402A3026F024E02F801B40169
:102F6600000000000904EF076D0156049E017C0174
:102F760090016E616E00696E66006F7666000D0ADE
:102F860000762E3230313831313237005400460067
:042F960052454C0054
:107E0000112484B714BE81FFF0D085E080938100F7
:107E100082E08093C00088E18093C10086E0809377
:107E2000C20080E18093C4008EE0C9D0259A86E02C
:107E300020E33CEF91E0309385002093840096BBD3
:107E4000B09BFECF1D9AA8958150A9F7CC24DD24C4
:107E500088248394B5E0AB2EA1E19A2EF3E0BF2EE7
:107E6000A2D0813461F49FD0082FAFD0023811F036
:107E7000013811F484E001C083E08DD089C08234E0
:107E800011F484E103C0853419F485E0A6D080C0E4
:107E9000853579F488D0E82EFF2485D0082F10E0AE
:107EA000102F00270E291F29000F111F8ED06801E7
:107EB0006FC0863521F484E090D080E0DECF843638
:107EC00009F040C070D06FD0082F6DD080E0C81688
:107ED00080E7D80618F4F601B7BEE895C0E0D1E017
:107EE00062D089930C17E1F7F0E0CF16F0E7DF06D8
:107EF00018F0F601B7BEE89568D007B600FCFDCFD4
:107F0000A601A0E0B1E02C9130E011968C91119780
:107F100090E0982F8827822B932B1296FA010C0160
:107F200087BEE89511244E5F5F4FF1E0A038BF0790
:107F300051F7F601A7BEE89507B600FCFDCF97BE46
:107F4000E89526C08437B1F42ED02DD0F82E2BD052
:107F50003CD0F601EF2C8F010F5F1F4F84911BD097
:107F6000EA94F801C1F70894C11CD11CFA94CF0C13
:107F7000D11C0EC0853739F428D08EE10CD085E9AC
:107F80000AD08FE07ACF813511F488E018D01DD067
:107F900080E101D065CF982F8091C00085FFFCCF94
:107FA0009093C60008958091C00087FFFCCF809118
:107FB000C00084FD01C0A8958091C6000895E0E648
:107FC000F0E098E1908380830895EDDF803219F02E
:107FD00088E0F5DFFFCF84E1DECF1F93182FE3DFCA
:107FE0001150E9F7F2DF1F91089580E0E8DFEE27F6
:047FF000FF270994CA
:027FFE00040479
:0400000300007E007B
:00000001FF

View file

@ -0,0 +1,808 @@
:100000000C9443010C946B010C946B010C946B01E8
:100010000C946B010C946B010C946B010C946B01B0
:100020000C946B010C946B010C946B010C946B01A0
:100030000C946B010C946B010C946B010C946B0190
:100040000C9478080C946B010C94E8080C94C2088A
:100050000C946B010C946B010C946B010C946B0170
:100060000C946B010C946B01CC01D201D801DE0120
:10007000E401EA01F001210328032F0336033D03C5
:100080005403440354034B034E414E494E495459C3
:10009000494E46CDCCCC3D0AD7233C17B7D1387753
:1000A000CC2B329595E6241FB14F0A000020410069
:1000B00000C84200401C4620BCBE4CCA1B0E5AAEB3
:1000C000C59D744D3131343B202D207265706F72A7
:1000D0007420706F736974696F6E20616E6420663E
:1000E00065656472617465004D3130303B202D20B0
:1000F000746869732068656C70206D6573736167DF
:1001000065004D32323B202D207475726E2072696D
:10011000676874206C61736572206F6666004D328B
:10012000313B202D207475726E20726967687420CF
:100130006C61736572206F6E004D32303B202D2054
:100140007475726E206C656674206C6173657220C4
:100150006F6666004D31393B202D207475726E201C
:100160006C656674206C61736572206F6E004D3132
:10017000383B202D2064697361626C65206D6F745B
:100180006F7273004D31373B202D20656E61626CBC
:1001900065206D6F746F727300473031205B542897
:1001A0007374657073295D205B4C2873746570737C
:1001B000295D205B46286665656472617465295D0A
:1001C0003B202D206D6F766500473030205B542832
:1001D0007374657073295D3B202D206C696E6561B9
:1001E00072206D6F766500436F6D6D616E64733A5A
:1001F000004661625363616E20472D434F4444457E
:1002000020496E74657270726574657220566572ED
:1002100073696F6E3A2000424144434845434B5353
:10022000554D20004241444C494E454E554D20000D
:100230003E0000000000240027002A000000000803
:10024000000201000003040700000000000000009D
:10025000010204081020408001020408102001025D
:100260000408102000000000250028002B000404D2
:10027000040404040404020202020202030303034E
:1002800003033F11B20D11241FBECFEFD8E0DEBF34
:10029000CDBF22E0A4E5B1E001C01D92A03AB207B3
:1002A000E1F711E0A0E0B1E0E2EEFFE202C005906C
:1002B0000D92A435B107D9F711E0C2E4D1E004C032
:1002C0002197FE010E94AD16C134D107C9F70E94E3
:1002D000C20D0C94E4170C940000FC01538D448D66
:1002E000252F30E0842F90E0821B930B541710F0E1
:1002F000CF96089501970895FC01918D828D9817EE
:1003000061F0828DDF01A80FB11D5D968C91928DF9
:100310009F5F9F73928F90E008958FEF9FEF0895F6
:10032000FC01918D828D981731F0828DE80FF11DBF
:10033000858D90E008958FEF9FEF0895FC01918DDA
:10034000228D892F90E0805C9F4F821B91098F73D3
:100350009927089580E090E0892B29F00E946C088D
:1003600081110C9400000895CF93DF9347705527B7
:1003700066277727FA013197EC01A881B981E73028
:10038000F10520F4EC5CFF4F0C94AD161496ED9142
:10039000FC91159761E029C01496ED91FC91159799
:1003A00065E023C01496ED91FC91159764E01DC0A3
:1003B0001496ED91FC91159766E017C01496ED9197
:1003C000FC91159762E011C01496ED91FC91159780
:1003D0006AE00BC01496ED91FC91159768E005C09A
:1003E0001496ED91FC91159769E0DF91CF910994F6
:1003F000CF93DF93EC01CB01BA0126E030E040E07F
:1004000050E00E948E16623071058105910559F108
:100410008CF46115710581059105F1F0613071056C
:1004200081059105C1F5E881F9810480F581E02D10
:1004300065E02DC0643071058105910511F1D4F09E
:10044000653071058105910531F5E881F9810480F8
:10045000F581E02D66E01BC0E881F9810480F5811B
:10046000E02D64E014C0E881F9810480F581E02D7D
:1004700061E00DC0E881F9810480F581E02D63E041
:1004800006C0E881F9810480F581E02D62E0CE01AB
:10049000DF91CF910994DF91CF9108954370552753
:1004A00066277727DC01ED91FC910480F581E02D32
:1004B000423051056105710571F043305105610508
:1004C000710559F0413051056105710511F065E084
:1004D00005C066E003C06AE001C069E00994CF93FB
:1004E000DF93EC01CB01BA0123E030E040E050E0C3
:1004F0000E948E16613071058105910581F0623090
:1005000071058105910591F0672B682B692BC1F46A
:10051000E881F9810480F581E02D64E00DC0E88177
:10052000F9810480F581E02D61E006C0E881F98160
:100530000480F581E02D62E0CE01DF91CF91099436
:10054000DF91CF9108954370552766277727DC0107
:10055000ED91FC910480F581E02D4230510561055B
:10056000710571F0433051056105710559F0413055
:1005700051056105710511F062E005C063E003C03B
:1005800061E001C060E00994CF93DF93EC01E88162
:10059000F9810480F581E02D8A81811102C060E03B
:1005A00001C062E0CE010995E881F9810480F581FE
:1005B000E02D8A81811102C061E001C063E0CE01BB
:1005C00009958CA59DA58230910538F0880F991F5B
:1005D000880F991F05970197F1F7E881F981048049
:1005E000F581E02D8A81811102C060E001C062E0E6
:1005F000CE01DF91CF910994CF93DF93EC0120E0FE
:1006000030E0A9016C897D898E899F890E94071637
:1006100018161CF4E8A9F9A902C0EAA9FBA9DF9100
:10062000CF9109940F931F93DC011396EC910E2F39
:1006300010E009301105C0F5F801E55CFF4F0C949E
:10064000AD16DC01ED91FC910084F185E02D29C00F
:10065000DC01ED91FC910284F385E02D22C0DC01E8
:10066000ED91FC910484F585E02D1BC0DC01ED913A
:10067000FC910684F785E02D14C0DC01ED91FC911E
:100680000088F189E02D0DC0DC01ED91FC9102881C
:10069000F389E02D06C0DC01ED91FC910488F58919
:1006A000E02D1F910F9109941F910F910895CF9301
:1006B000DF93FC012381222359F1EC0161E0848165
:1006C0000E940C0D61E08D810E940C0D8B818430A5
:1006D00011F0883039F461E08E810E940C0D61E0E8
:1006E0008F8106C0833011F0863021F461E08E8165
:1006F0000E940C0D8FA58F3F59F061E00E940C0DF8
:100700006EA581E068278FA5DF91CF910C94BF0C77
:10071000DF91CF910895CF93DF93FC0123812223B2
:10072000A9F0EC010190F081E02D0480F581E02D2D
:1007300060E009958FA58F3F49F061E00E940C0DA4
:100740006EA58FA5DF91CF910C94BF0CDF91CF9157
:100750000895CF92DF92EF92FF920F931F93CF9362
:10076000DF93EC019B81943041F0983031F093306D
:1007700031F0963021F012E003C014E001C013E024
:100780002496E12CF12CC62ED12C01E0C6010E2CB2
:1007900002C0959587950A94E2F76C8180FD6027E9
:1007A00089910E94BF0C8FEFE81AF80AE11670F3E6
:1007B000DF91CF911F910F91FF90EF90DF90CF903D
:1007C0000895FC01848DDF01A80FB11DA35ABF4F0E
:1007D0002C91848D90E001968F739927848FA68940
:1007E000B7892C93A089B1898C91837080648C9394
:1007F000938D848D981306C00288F389E02D808143
:100800008F7D80830895EF92FF920F931F93CF9374
:10081000DF93EC0181E0888F9B8D8C8D981305C050
:10082000E889F989808185FD26C0F62E0B8D10E0C0
:100830000F5F1F4F0F731127E02E8C8DE8120CC035
:100840000FB607FCFACFE889F989808185FFF5CFDB
:10085000CE010E94E103F1CF8B8DFE01E80FF11D67
:10086000E35AFF4FF0829FB7F8940B8FEA89FB8918
:10087000808180620AC09FB7F894EE89FF89608307
:10088000E889F98980818370806480839FBF81E0DB
:1008900090E0DF91CF911F910F91FF90EF9008951D
:1008A000CF93DF93EC01888D8823C9F0EA89FB8917
:1008B000808185FD05C0A889B9898C9186FD0FC00E
:1008C0000FB607FCF5CF808185FFF2CFA889B989E3
:1008D0008C9185FFEDCFCE010E94E103E7CFDF9140
:1008E000CF9108954F925F926F927F92AF92BF9295
:1008F000CF92DF92EF92FF920F931F93CF93DF93EC
:10090000CDB7DEB7C454D1090FB6F894DEBF0FBE21
:10091000CDBF5C012A013B016801790123E042E07F
:1009200064E0CE0101960E94670A8AE0A816B1042D
:1009300021F4CE0101960E94E60BC301B2010E9490
:10094000D1150D851E852F853889DC01CB01800FDF
:10095000911FA21FB31F09891A892B893C89081787
:1009600019072A073B0741F0898B9A8BAB8BBC8B0D
:10097000CE0101960E941A09B701A601CE01019687
:100980000E94C40A49895A896B897C890D851E8514
:100990002F853889CDA0DEA0EFA0F8A40417150795
:1009A0002607370714F481E001C080E040175107A3
:1009B0006207730759F0C114D104E104F104B1F3E3
:1009C0008B83CE0101960E946D0DDCCFCC5BDF4F97
:1009D0000FB6F894DEBF0FBECDBFDF91CF911F9150
:1009E0000F91FF90EF90DF90CF90BF90AF907F90EE
:1009F0006F905F904F9008958F929F92AF92BF92A9
:100A0000CF92DF92EF92FF926A017B010E943B0B33
:100A1000A7019601C701B6010E945216882319F05A
:100A200082E391E01AC046015701E894B7F82FEF2E
:100A30003FEF4FE75FE7C501B4010E9452168111F5
:100A40000FC02FEF3FEF4FE75FE7C501B4010E94F2
:100A50007A1318162CF486E391E00E943B0B76C0C3
:100A60002FEF3FEF4FE75FE4C701B6010E94071683
:100A700018161CF48AE391E0F0CF2FEF3FEF4FE719
:100A80005FECC701B6010E947A1387FDF3CF20E027
:100A900030E0A901C701B6010E947A1387FF09C09F
:100AA0006DE284EA91E00E940304F7FAF094F7F80B
:100AB000F0942AE037ED43EA5BE3C701B6010E94F8
:100AC000F3144B015C010E94D8156B017C010E945C
:100AD0007F139B01AC01C501B4010E94F2144B01CC
:100AE0005C014AE0C701B6010E94760B6EE284EA1F
:100AF00091E00E94030420E030E040E251E4C501AF
:100B0000B4010E94E0134B015C010E94D8156B01F7
:100B1000E12CF12C4AE0C701B6010E94760BC70117
:100B2000B6010E947F139B01AC01C501B4010E9474
:100B3000F21420E030E040E251E40E94E0130E9411
:100B4000D81580E090E04AE00E94760B8EE391E0B9
:100B5000FF90EF90DF90CF90BF90AF909F908F90DD
:100B60000C943B0BFF920F931F93CF93DF93F82EC0
:100B70008B01C0919401D0919501CC5ADE4F84E550
:100B800091E00097B9F0FC012081222399F08C17A5
:100B90009D0780F42F1108C00196DF91CF911F911E
:100BA0000F91FF900C94331360E270E00E94D9170C
:100BB0000196E7CFC801DF91CF911F910F91FF9070
:100BC00008958F929F92AF92BF92CF92DF92EF9251
:100BD000FF920F931F93CF93DF93CDB7DEB7299783
:100BE0000FB6F894DEBF0FBECDBF962F50E060E089
:100BF00070E0592B682BCB01AA27BB27F52E982E26
:100C0000BC0100E010E0A0E0B0E020E030E0809126
:100C100087029091880228173907E0F580918C02AD
:100C2000882371F0869F6001879FD00C11248F9DCF
:100C300050011124EB2C849FC0011124592F03C0B3
:100C4000542FEF2CD92CC0909202B0908F0280913B
:100C50008D0290918E02CB1003C08A0F9B1F07C09C
:100C6000800F911F5C01AC0CB11CF5011082C0908B
:100C70008F025C01AC0CB11CF501D082D0909002C7
:100C8000FC01ED0DF11DE082E09091028E0D911DB1
:100C9000FC0150832F5F3F4F13960C5F1F4F203195
:100CA000310509F0B4CF80918D0290918E02892B8D
:100CB00009F4A2C00E94480DC0909302D090940203
:100CC000E0909502F0909602DC01CB018C199D0911
:100CD000AE09BF098C329140A105B10558F3F894D3
:100CE0008091890290918A029A838983E0918D0292
:100CF000F0918E02DF0111968081898790918502A3
:100D0000E0919702F091980280919902992309F459
:100D10002EC09081982B98879081809589238F830E
:100D20008F818C8388E08B8358856F8149853B81D7
:100D30002C8189819A81508347FD252F3A95208304
:100D4000262F39F0441F00C000006083000000C05F
:100D5000F2CF38E04D9160830000019761F7F09386
:100D60009802E093970249873B832C8338C0908197
:100D7000982B98879081809589238F838F818E838C
:100D800088E08D8358856F8149853D812E818981D9
:100D90009A81508347FD252F00C000C0208300C0EA
:100DA00000C000C000C000C060830000262F3A953C
:100DB00041F0441F000000C000C000C000C000C0DF
:100DC000E8CF38E04D9100C0608300C0019709F77B
:100DD000F0939802E093970249873D832E839A838C
:100DE000898378940E94480D6093930270939402D3
:100DF00080939502909396020E94480D4B015C01EE
:100E000084E6C82ED12CE12CF12C0E94480DDC0187
:100E1000CB0188199909AA09BB09883E9340A1050D
:100E2000B10598F321E0C21AD108E108F10888EE73
:100E3000880E83E0981EA11CB11CC114D104E104EA
:100E4000F10419F729960FB6F894DEBF0FBECDBF97
:100E5000DF91CF911F910F91FF90EF90DF90CF9096
:100E6000BF90AF909F908F9008954F925F926F9236
:100E70007F928F929F92AF92BF92CF92DF92EF922A
:100E8000FF92CF93DF93EC016A017B0120E030E019
:100E9000A901C701B6010E947A1387FF04C0F7FABF
:100EA000F094F7F8F0948C8C9D8CAE8CBF8CA701DD
:100EB0009601C501B4010E947A13882309F449C040
:100EC0006CA97DA98EA99FA90E9481132B013C01C9
:100ED000A7019601C501B4010E945F159B01AC01F9
:100EE000C301B2010E94E0130E94D1156CAB7DAB2F
:100EF0008EAB9FABA701960160E070E080E090E4CC
:100F00000E945F150E94121626E53EE04DE25FE367
:100F10000E94E01320E034E244E759E40E94E01329
:100F200068AF79AF8AAF9BAFCC8EDD8EEE8EFF8E31
:100F3000CE01DF91CF91FF90EF90DF90CF90BF90E7
:100F4000AF909F908F907F906F905F904F900C9498
:100F50001A09DF91CF91FF90EF90DF90CF90BF9073
:100F6000AF909F908F907F906F905F904F9008957B
:100F7000CF92DF92EF92FF920F931F93CF93DF9365
:100F8000CDB7DEB7C454D1090FB6F894DEBF0FBE9B
:100F9000CDBF6C018B017A0123E042E064E0CE0119
:100FA00001960E94670A8AE0C816D10421F4CE0196
:100FB00001960E94E60BB701FF0C880B990B0E946B
:100FC0008113AB01BC01CE0101960E94C40A40E02E
:100FD00050E06AEF73E4CE0101960E943507C80124
:100FE000110FAA0BBB0B49895A896B897C8984171D
:100FF0009507A607B70741F0898B9A8BAB8BBC8B03
:10100000CE0101960E941A098DA19EA1AFA1B8A59B
:10101000892B8A2B8B2B51F0CE0101960E946D0DEE
:10102000882321F0CE0101960E941A0920E030E0C9
:10103000A9016D897E898F89988D0E947A1381110B
:10104000E3CF49895A896B897C898D859E85AF85D7
:10105000B889481759076A077B07B1F6CC5BDF4FA1
:101060000FB6F894DEBF0FBECDBFDF91CF911F91B9
:101070000F91FF90EF90DF90CF900895CF92DF9285
:10108000EF92FF920F931F93CF93DF936C017A013E
:101090008B01C0E0D0E0CE15DF0581F0D8016D9165
:1010A0008D01D601ED91FC910190F081E02DC601FA
:1010B0000995892B11F02196EECF7E01C701DF91B2
:1010C000CF911F910F91FF90EF90DF90CF900895F7
:1010D000089580E090E0089584EA91E00E949E01E6
:1010E00021E0892B09F420E0822F08950E94D41773
:1010F0001F920F920FB60F9211242F933F938F934D
:101100009F93AF93BF9380919C0190919D01A0917B
:101110009E01B0919F0130919B0123E0230F2D3759
:1011200020F40196A11DB11D05C026E8230F0296EB
:10113000A11DB11D20939B0180939C0190939D0163
:10114000A0939E01B0939F018091A0019091A10175
:10115000A091A201B091A3010196A11DB11D8093A0
:10116000A0019093A101A093A201B093A301BF910C
:10117000AF919F918F913F912F910F900FBE0F9044
:101180001F9018951F920F920FB60F9211242F9354
:101190003F934F935F936F937F938F939F93AF93FF
:1011A000BF93EF93FF9384EA91E00E94E103FF91E4
:1011B000EF91BF91AF919F918F917F916F915F91CF
:1011C0004F913F912F910F900FBE0F901F90189548
:1011D0001F920F920FB60F9211242F938F939F930C
:1011E000EF93FF93E091B401F091B5018081E0911C
:1011F000BA01F091BB0182FD12C090818091BD01C6
:101200008F5F8F732091BE01821751F0E091BD0175
:10121000F0E0EC55FE4F958F8093BD0101C08081B9
:10122000FF91EF919F918F912F910F900FBE0F9093
:101230001F9018954F925F926F927F928F929F921C
:10124000AF92BF92CF92DF92EF92FF920F931F93D4
:10125000CF93DF93EC01C888D988EA88FB888C8516
:101260009D85AE85BF85C81AD90AEA0AFB0A6C8932
:101270007D898E899F899B01AC010E94E0134B01FF
:101280005C016C8D7D8D8E8D9F8D9B01AC010E94CC
:10129000F3149B01AC01C501B4010E945F150E94CB
:1012A000D115C114D104E104F10499F4623071053F
:1012B000810591050CF076C01CA21DA21EA21FA2E2
:1012C0001C8A1D8A1E8A1F8A1CAA1DAA1EAA1FAA62
:1012D000EDC00CA91DA92EA93FA91C141D041E04B4
:1012E0001F04FCF410161106120613064CF46C15BC
:1012F0007D058E059F054CF52A81211153C025C01F
:10130000011511052105310509F44CC06C157D0549
:101310008E059F050CF046C08A81882309F442C0DF
:1013200036C01016110612061306ECF4002711271A
:1013300098010C191D092E093F09601771078207D2
:1013400093071CF42A81222369F19B01AC018827B1
:101350009927DC01821B930BA40BB50B8CAB9DABC7
:10136000AEABBFAB1FC00115110521053105D1F092
:101370008824992454018C189D08AE08BF0868156C
:1013800079058A059B0574F48A8181110BC030951B
:101390002095109501951F4F2F4F3F4F0CAB1DAB64
:1013A0002EAB3FAB8CA89DA8AEA8BFA8811491041A
:1013B000A104B10489F488AD99ADAAADBBAD8CAFE1
:1013C0009DAFAEAFBFAF81E01C141D041E041F040F
:1013D0000CF080E08A833FC0CCACDDACEEACFFAC5F
:1013E000A7019601C701B6010E94F3142B013C012D
:1013F000C501B4010E94811320E030E040E850E4D0
:101400000E94E01320E030E040E85FE30E94F31424
:101410009B01AC01C301B2010E945F159B01AC01AD
:10142000C701B6010E94F2143B016C01FE01E05CB1
:10143000FF4FE080F180028113819701A8010E9493
:101440000716181614F473018601C701D8018CAF72
:101450009DAFAEAFBFAF3FEF831A930AA30AB30AA3
:101460008CAA9DAAAEAABFAACCACDDACEEACFFACF8
:10147000C701B6010E94D8156CA37DA38EA39FA3BC
:10148000A701960160E074E284E799E40E945F1589
:101490006C8B7D8B8E8B9F8B2A81211107C0DC0189
:1014A000CB01B0588C8B9D8BAE8BBF8BDF91CF91D6
:1014B0001F910F91FF90EF90DF90CF90BF90AF9072
:1014C0009F908F907F906F905F904F900895CF93F3
:1014D000DF93EC018AE091E0998388836B831C861B
:1014E0001D861E861F86188A198A1A8A1B8A1C8ADC
:1014F0001D8A1E8A1F8A80E090E0A0E8BFE3888FE3
:10150000998FAA8FBB8F1C8E1D8E1E8E1F8E88A357
:1015100099A3AAA3BBA31CA21DA21EA21FA261E0A5
:1015200070E07DA76CA73FEF3FA718A619A61AA6E3
:101530001BA64C832D8324E02E8325E02F831EA63B
:101540001CAA1DAA1EAA1FAA18AE19AE1AAE1BAE5F
:101550001CAE1DAE1EAE1FAEFE01E05CFF4F8083D1
:101560009183A283B3831A82188619861A861B86F2
:10157000CE010E94570340E050E060E87FE3CE01D7
:10158000DF91CF910C9435074F925F926F927F92CB
:10159000AF92BF92CF92DF92EF92FF920F931F9381
:1015A000CF93DF93EC015A018B019A01AB016C8957
:1015B0007D898E899F890E947A13882309F44CC003
:1015C000C88CD98CEA8CFB8C2601370177FA709491
:1015D00077F87094A3019201B501C8010E947A13B3
:1015E00087FD0BC0A7019601B501C8010E9407162F
:1015F00018162CF06501780102C07301620120E029
:1016000030E0A901C701B6010E947A13811105C01B
:101610001CA21DA21EA21FA21BC0A701960160E072
:1016200074E284E799E40E945F159F770E94D815C1
:101630006CA37DA38EA39FA311E020E030E0A9015D
:10164000C701B6010E94071618160CF010E01A83A5
:10165000CC8ADD8AEE8AFF8ADF91CF911F910F91AC
:10166000FF90EF90DF90CF90BF90AF907F906F9002
:101670005F904F900895009769F0FC010190002061
:10168000E9F73197AF01481B590BBC0184EA91E09F
:101690000C943E0880E090E008950F931F93CF9341
:1016A000DF938C01C0E0D0E0F801EC0FFD1F6491E6
:1016B000662341F084EA91E00E940304892B11F033
:1016C0002196F2CFCE01DF91CF911F910F91089516
:1016D000CF93DF930E944D0BEC018EE391E00E94CB
:1016E0003B0B8C0F9D1FDF91CF9108958F929F929E
:1016F000AF92BF920F931F93CF93DF93CDB7DEB717
:10170000A1970FB6F894DEBF0FBECDBF19A242302D
:1017100008F44AE08E010F5D1F4F842E912CA12CFE
:10172000B12CA50194010E946C16E62FB901CA01E3
:1017300001501109EA3014F4E05D01C0E95CD80100
:10174000EC93232B242B252B61F7C8010E943B0B24
:10175000A1960FB6F894DEBF0FBECDBFDF91CF913B
:101760001F910F91BF90AF909F908F900895CF924F
:10177000DF92EF92FF92CF93DF936B017C016DE2DA
:1017800084EA91E00E940304EC0166277727CB01ED
:101790006C197D098E099F094AE00E94760B8C0F17
:1017A0009D1FDF91CF91FF90EF90DF90CF90089534
:1017B000CF93DF930E943B0BEC018EE391E00E94FC
:1017C0003B0B8C0F9D1FDF91CF910895FC01A1E48D
:1017D000B2E012968C911297828313968C91139794
:1017E000838314968C911497848315968C91159706
:1017F000858316968C911697868317968C911797EA
:10180000878318968C911897808719968C911997D1
:1018100081871A968C911A9782871B968C911B97B9
:1018200083871C964D915D916D917C911F974487A4
:1018300055876687778750964D915D916D917C9124
:101840005397408B518B628B738B54964D915D9166
:101850006D917C915797448B558B668B778B5896FF
:101860004D915D916D917C915B97408F518F628F0F
:10187000738F5C964D915D916D917C915F97448FD4
:10188000558F668F778F90964D915D916D917C917C
:10189000939740A351A362A373A394964D915D9136
:1018A0006D917C91979744A355A366A377A39896CF
:1018B0004D915D916D917C919B9740A751A762A737
:1018C00073A79C968D919C919D9795A784A79E96B2
:1018D0008C919E9786A79F968C919F9787A7D0966D
:1018E0008D919C91D19791AB80ABD2968D919C912B
:1018F000D39793AB82ABD4964D915D916D917C91D2
:10190000D79744AB55AB66AB77ABD8964D915D910D
:101910006D917C91DB9740AF51AF62AF73AFDC96B6
:101920008D919D910D90BC91A02D84AF95AFA6AFE8
:10193000B7AF409181025091820260918302709111
:101940008402DF01A05CBF4F4D935D936D937C9348
:101950001397CF010895CF93DF9397FF03C00E94A1
:10196000B70B03C04AE00E94760BEC018EE391E0D6
:101970000E943B0B8C0F9D1FDF91CF91089590E04B
:10198000FC01E45CFD4F2491FC01E05BFD4F3491D0
:10199000FC01E259FD4FE491EE2309F43CC02223FF
:1019A00039F1233091F038F42130A9F0223001F5DB
:1019B00084B58F7D12C0273091F02830A1F02430FB
:1019C000B9F4809180008F7D03C0809180008F7773
:1019D000809380000DC084B58F7784BD09C080914D
:1019E000B0008F7703C08091B0008F7D8093B000EE
:1019F000F0E0EE0FFF1FEC59FD4FA591B4919FB79A
:101A0000F894611104C08C913095382302C0EC9198
:101A10003E2B3C939FBF0895CF93DF9390E0FC0152
:101A2000E05BFD4F2491FC01E259FD4F8491882336
:101A300061F190E0880F991FFC01EE5CFD4FC591AC
:101A4000D491FC01EC59FD4FA591B491611109C0ED
:101A50009FB7F8948881209582238883EC912E2368
:101A60000BC0623061F49FB7F8948881322F3095B3
:101A700083238883EC912E2B2C939FBF06C08FB7B6
:101A8000F894E8812E2B28838FBFDF91CF910895A2
:101A90003FB7F8948091A0019091A101A091A2017B
:101AA000B091A30126B5A89B05C02F3F19F0019660
:101AB000A11DB11D3FBFBA2FA92F982F8827820FD4
:101AC000911DA11DB11DBC01CD0142E0660F771F24
:101AD000881F991F4A95D1F70895CF92DF92EF9210
:101AE000FF92CF93DF93EC010E94480D6B017C01C4
:101AF00088A599A5AAA5BBA5B701A601481B590BA6
:101B00006A0B7B0B8CA19DA1AEA1BFA14817590701
:101B10006A077B07F8F02A818C859D85AE85BF8595
:101B2000222321F00196A11DB11D03C00197A10937
:101B3000B1098C879D87AE87BF874C855D856E8593
:101B40007F85CE010E941203C8A6D9A6EAA6FBA6ED
:101B500081E001C080E0DF91CF91FF90EF90DF90B6
:101B6000CF90089580918D0290918E02009711F090
:101B70000E944B1780918B0287FD03C060E00C949C
:101B80000C0D0895789484B5826084BD84B581601D
:101B900084BD85B5826085BD85B5816085BD809138
:101BA0006E00816080936E001092810080918100B0
:101BB00082608093810080918100816080938100A8
:101BC000809180008160809380008091B10084606A
:101BD0008093B1008091B00081608093B0008091CB
:101BE0007A00846080937A0080917A00826080938A
:101BF0007A0080917A00816080937A0080917A00E7
:101C0000806880937A001092C100E091B401F09155
:101C1000B50182E08083E091B401F091B5011082BA
:101C2000E091B001F091B1011082E091B201F09128
:101C3000B30180E180831092BC01E091B801F09182
:101C4000B90186E08083E091B601F091B70180810F
:101C500080618083E091B601F091B7018081886056
:101C60008083E091B601F091B70180818068808324
:101C7000E091B601F091B70180818F7D808361E0B2
:101C800089E00E940C0D61E08AE00E940C0D61E089
:101C90008FE00E940C0D60E08FE00E94BF0C60E0BE
:101CA00089E00E94BF0C60E08AE00E94BF0C61E006
:101CB00083E10E940C0D60E083E10E94BF0C61E0B3
:101CC00082E00E940C0D61E085E00E940C0D61E055
:101CD00083E00E940C0D61E086E00E940C0D61E043
:101CE00083E10E94BF0C20E030E04AEF54E46091B1
:101CF000590270915A0280915B0290915C020E949D
:101D00007A13882309F453C080E090E0AAEFB4E48A
:101D10008093590290935A02A0935B02B0935C02A5
:101D200080E090E0AAEFB3E4809381029093820276
:101D3000A0938302B0938402809175029091760201
:101D4000A0917702B0917802181619061A061B06A0
:101D500074F56091550270915602809157029091EE
:101D600058029B01AC010E94E0136B017C01609161
:101D70005D0270915E0280915F02909160029B0112
:101D8000AC010E94F3149B01AC01C701B6010E9493
:101D90005F150E94D115609375027093760280934F
:101DA00077029093780281E492E00E941A0940E061
:101DB00050E06FE274E481E492E00E94C40A61E0C2
:101DC00082E00E94BF0C80918B0287FD08C061E019
:101DD0000E940C0D60E080918B020E94BF0C81E09C
:101DE0008093860261E082E00E94BF0C61E085E0A2
:101DF0000E94BF0C84EA91E00E949E011816190609
:101E00000CF0FAC184EA91E00E947C01C82F682F8F
:101E100084EA91E00E9403048091940190919501DD
:101E20008F3391055CF49C012F5F3F4F30939501F8
:101E300020939401FC01EC5AFE4FC083CA3011F08C
:101E4000CD30C1F6E0919401F0919501EC5AFE4F2E
:101E50001082C0915401CB3309F4C5C16FEF7FEFFD
:101E60008EE40E94B205092E000CAA0BBB0B8F3F1B
:101E70002FEF9207A207B20709F45CC0CE3409F035
:101E800059C0C0909601D0909701E0909801F090D1
:101E900099018C159D05AE05BF0539F084E292E0ED
:101EA0000E944D0BC701B6012FC06AE270E084E5C5
:101EB00091E00E94D917892B09F495C1E4E5F1E07E
:101EC000C0E09F012455314091919A3211F0C92709
:101ED000F8CF60E070E0C9018B5A9E4F0E94E51177
:101EE0000E94D1152C2FCC0F330B2617370779F012
:101EF00087E192E00E944D0B6091960170919701ED
:101F000080919801909199010E94AB0C6CC18091D5
:101F1000960190919701A0919801B0919901019635
:101F2000A11DB11D8093960190939701A0939801F4
:101F3000B09399016FEF7FEF87E40E94B205823082
:101F4000910581F01CF497FF30C06EC0863091057A
:101F500009F464C08730910509F464C0049709F05E
:101F600063C023C060E070E086E40E94B2057C019B
:101F700060E070E08CE40E94B205EC0160E070E08B
:101F800084E50E94B205009731F0A701BC018AE008
:101F900090E00E94B807209709F446C0A701BE014F
:101FA0008BE090E00E94B8073FC060E070E086E4FC
:101FB0000E94B205BC01990F880B990B0E948113F6
:101FC0006B017C0160E070E08CE40E94B205EC01E2
:101FD00060E070E084E50E94B205009771F0BC01FA
:101FE000990F880B990B0E948113AB01BC019701DB
:101FF00086018AE090E00E9472042097A9F0BE0159
:10200000DD0F880B990B0E948113AB01BC01970176
:1020100086018BE090E00E94720406C081E080930C
:102020009A0102C010929A016FEF7FEF8DE40E9437
:10203000B2058531910509F4ABC0CCF4813191052D
:1020400009F49AC044F48430910509F477C00597E7
:1020500009F47CC0C8C08331910509F494C00CF028
:1020600094C061E082E00E94BF0C61E08AC08E36BD
:10207000910509F494C0ECF58631910509F48AC004
:102080008436910509F0AFC081EF91E00E944D0BBD
:1020900081E491E00E94D80B87EE91E00E94680BEA
:1020A00089EC91E00E94680B89E991E00E94680B3D
:1020B00084E891E00E94680B8EE691E00E94680B34
:1020C00084E591E00E94680B89E391E00E94680B2F
:1020D0008EE191E00E94680B82E091E00E94680B23
:1020E00088EE90E00E94680B83EC90E00E94680B01
:1020F0007AC0883C910509F466C0893C910509F4D1
:1021000067C08237910509F06EC040E050E0BA0127
:102110008CE491E00E94FC0440E050E0BA0182E5CA
:1021200091E00E94FC0440E050E46CE176E48EE42F
:1021300091E00E94FC0480E591E047C060E089E006
:102140000E94BF0C60E08AE00E94BF0C60E070E07B
:1021500082E40E94B2057C0160E070E087E40E94A6
:10216000B205EC0160E070E082E50E94B205A701D3
:10217000BE010E94E10537C060E082E00E94BF0C12
:1021800060E085E009C061E001C060E08AE004C071
:1021900061E001C060E089E00E94BF0C24C0609152
:1021A0009601709197018EE40E94B205092E000CF1
:1021B000AA0BBB0B8093960190939701A093980173
:1021C000B093990110C081E491E00E94D80B0BC03C
:1021D0004AE061E070E080E090E00E94760B8EE3E0
:1021E00091E00E943B0B109295011092940180E3C4
:1021F00092E00E94680BFECD80919A018823E1F164
:1022000040E050E06AE774E481E492E00E94C40A8E
:1022100080914D0290914E02A0914F02B0915002D8
:102220000A96A11DB11D4091510250915202609138
:1022300053027091540284179507A607B70761F0FF
:102240008093510290935202A0935302B093540290
:1022500081E492E00E941A098091650290916602E1
:10226000A0916702B0916802892B8A2B8B2B21F0F9
:1022700081E492E00E946D0D0E94AA01BBCD1092F4
:10228000A7011092A60188EE93E0A0E0B0E0809351
:10229000A8019093A901A093AA01B093AB0184E295
:1022A00091E09093A5018093A40185EC90E0909338
:1022B000B1018093B00184EC90E09093B3018093DE
:1022C000B20180EC90E09093B5018093B40181EC71
:1022D00090E09093B7018093B60182EC90E09093E8
:1022E000B9018093B80186EC90E09093BB01809394
:1022F000BA011092BD011092BE011092BF0110925E
:10230000C00124E043E062E081E492E00E94670AB9
:102310001092860210928C021092930210929402F4
:10232000109295021092960281E08093920280931F
:102330008F021092900292E0909391028093850216
:1023400080E390E090938A02809389020E94B31602
:1023500090938E0280938D02009761F020E3FC0140
:1023600011922A95E9F780E190E09093880280939A
:10237000870208C010928A02109289021092880285
:10238000109287028FE080938B02809186028823CF
:1023900041F061E08FE00E940C0D60E08FE00E9450
:1023A000BF0CEDE7F2E0E491F0E0EE0FFF1FEC5917
:1023B000FD4F859194919093980280939702EFE559
:1023C000F2E0E491E09399020895A0E0B0E0EBEE32
:1023D000F1E10C94B214EC016B016115710519F077
:1023E000FB01918380837E01FFEFEF1AFF0A0881D2
:1023F000802F90E00E945113892B11F0E701F3CF59
:102400000D3239F47E0182E0E80EF11C098111E001
:1024100008C00B3229F47E0192E0E90EF11C09811B
:1024200010E0E701219743E050E060E970E0CE0161
:102430000E945A13892BC1F4239645E050E06BE8C3
:1024400070E0CE010E945A13892B09F42596C1141D
:10245000D10419F0F601D183C0831111F6C060E0F8
:1024600070E080E89FE7FAC043E050E068E870E081
:10247000CE010E945A13892B59F4C114D10409F4D6
:10248000E9C0F2E0EF0EF11CF601F182E082E2C059
:1024900020E030E0A901C0E0D0E0F70180EDA82EF7
:1024A000A00E89E08A1530F1912F9260B92E812F0C
:1024B000887012FF04C0811124C0219622C08111AE
:1024C0002197A5E0B0E00E94A114DC01CB01880FA8
:1024D000991FAA1FBB1F9C01AD012A0D311D411D73
:1024E000511D283989E93807480789E1580748F01C
:1024F000166006C09EEFA9120AC013FD40C0186006
:10250000B12E8FEFE81AF80A00811B2DC6CF802F5D
:102510008F7D8534A1F580818D3211F4106106C064
:102520008B3221F0319661E070E004C081813296F7
:1025300062E070E080538A3018F0E61BF70B1FC092
:1025400060E070E060389CE079075CF4DB01AA0F82
:10255000BB1FAA0FBB1F6A0F7B1F660F771F680F79
:10256000711D3196DF0111978C9180538A3050F3A1
:1025700014FF03C0719561957109C60FD71F11FF34
:1025800008C0C114D10429F0CF010197F60191834D
:102590008083CA01B9010E947F13212F2370233049
:1025A00019F04B015C0106C04B015C01B7FAB09415
:1025B000B7F8B09420E030E0A901C501B4010E9451
:1025C0007A13882309F43EC0D7FF06C0D195C19580
:1025D000D10907EA10E002C00FEB10E06801F8E152
:1025E000CF1AD10890E2E92EF12CCE15DF0574F058
:1025F000F8012591359145915491C501B4010E948E
:10260000E0134B015C01CE19DF09EFCF0450110933
:10261000F594E7940C151D0541F78A2D880F8B2D35
:10262000881F8F3F49F020E030E0A901C501B401C7
:102630000E947A13811106C082E290E090939B027F
:1026400080939A02C501B40109C060E070E080E89F
:102650009FEF04C060E070E080EC9FE7CDB7DEB78D
:10266000ECE00C94CE14FC0188279927E894219182
:102670002032E9F3293010F02E30C8F32B3241F02C
:102680002D3239F4689404C00E947213820F911D98
:10269000219120532A30C0F31EF4909581959F4FCD
:1026A000089591110C944D14803219F08950855081
:1026B000C8F70895FB01DC014150504088F08D912E
:1026C00081341CF08B350CF4805E659161341CF014
:1026D0006B350CF4605E861B611171F3990B0895E4
:1026E000881BFCCF7AE0979F902D879F802D910DBE
:1026F000112408950E94BC1308F481E00895E89421
:1027000009C097FB3EF490958095709561957F4F39
:102710008F4F9F4F9923A9F0F92F96E9BB279395E7
:10272000F695879577956795B795F111F8CFFAF4F7
:10273000BB0F11F460FF1BC06F5F7F4F8F4F9F4F28
:1027400016C0882311F096E911C0772321F09EE886
:10275000872F762F05C0662371F096E8862F70E0EC
:1027600060E02AF09A95660F771F881FDAF7880FC6
:102770009695879597F90895990F0008550FAA0B1C
:10278000E0E8FEEF16161706E807F907C0F0121684
:102790001306E407F50798F0621B730B840B950B87
:1027A00039F40A2661F0232B242B252B21F40895DC
:1027B0000A2609F4A140A6958FEF811D811D089579
:1027C0000E94F3130C9467140E94591438F00E946D
:1027D000601420F0952311F00C9450140C945614AE
:1027E00011240C949B140E94781470F3959FC1F3EC
:1027F000950F50E0551F629FF001729FBB27F00DAF
:10280000B11D639FAA27F00DB11DAA1F649F662703
:10281000B00DA11D661F829F2227B00DA11D621F52
:10282000739FB00DA11D621F839FA00D611D221F0C
:10283000749F3327A00D611D231F849F600D211DF0
:10284000822F762F6A2F11249F5750409AF0F1F073
:1028500088234AF0EE0FFF1FBB1F661F771F881FDC
:1028600091505040A9F79E3F510580F00C945014B0
:102870000C949B145F3FE4F3983ED4F386957795D0
:102880006795B795F795E7959F5FC1F7FE2B880F82
:10289000911D9695879597F908959927882708950A
:1028A00097F99F6780E870E060E008959FEF80EC03
:1028B000089500240A9416161706180609060895A6
:1028C00000240A9412161306140605060895092E0C
:1028D0000394000C11F4882352F0BB0F40F4BF2B7B
:1028E00011F460FF04C06F5F7F4F8F4F9F4F0895BB
:1028F00057FD9058440F551F59F05F3F71F04795B1
:10290000880F97FB991F61F09F3F79F08795089595
:10291000121613061406551FF2CF4695F1DF08C0B4
:10292000161617061806991FF1CF869571056105D1
:1029300008940895E894BB2766277727CB0197F979
:1029400008950E94E314A59F900DB49F900DA49F3D
:10295000800D911D112408952F923F924F925F9206
:102960006F927F928F929F92AF92BF92CF92DF929F
:10297000EF92FF920F931F93CF93DF93CDB7DEB704
:10298000CA1BDB0B0FB6F894DEBF0FBECDBF099498
:102990002A88398848885F846E847D848C849B84EF
:1029A000AA84B984C884DF80EE80FD800C811B81FD
:1029B000AA81B981CE0FD11D0FB6F894DEBF0FBE2C
:1029C000CDBFED010895A29FB001B39FC001A39FA9
:1029D000700D811D1124911DB29F700D811D112458
:1029E000911D08955058BB27AA270E940A150C94E0
:1029F00067140E94591438F00E94601420F039F4D2
:102A00009F3F19F426F40C9456140EF4E095E7FB5E
:102A10000C945014E92F0E94781458F3BA176207E7
:102A200073078407950720F079F4A6F50C949A149F
:102A30000EF4E0950B2EBA2FA02D0B01B9019001D9
:102A40000C01CA01A0011124FF27591B99F0593F1D
:102A500050F4503E68F11A16F040A22F232F342F65
:102A60004427585FF3CF469537952795A795F040B3
:102A70005395C9F77EF41F16BA0B620B730B840BC8
:102A8000BAF09150A1F0FF0FBB1F661F771F881F80
:102A9000C2F70EC0BA0F621F731F841F48F48795D8
:102AA00077956795B795F7959E3F08F0B0CF9395CA
:102AB000880F08F09927EE0F9795879508950E9443
:102AC00073150C9467140E94601458F00E945914F6
:102AD00040F029F45F3F29F00C94501451110C94EC
:102AE0009B140C9456140E94781468F39923B1F344
:102AF000552391F3951B550BBB27AA276217730724
:102B0000840738F09F5F5F4F220F331F441FAA1FB7
:102B1000A9F335D00E2E3AF0E0E832D09150504073
:102B2000E695001CCAF72BD0FE2F29D0660F771F21
:102B3000881FBB1F261737074807AB07B0E809F007
:102B4000BB0B802DBF01FF2793585F4F3AF09E3F8C
:102B5000510578F00C9450140C949B145F3FE4F3EF
:102B6000983ED4F3869577956795B795F7959F5FCF
:102B7000C9F7880F911D9695879597F90895E1E01B
:102B8000660F771F881FBB1F621773078407BA077A
:102B900020F0621B730B840BBA0BEE1F88F7E095D5
:102BA00008950E94D8156894B1110C949B1408954F
:102BB0000E94801488F09F5798F0B92F9927B75139
:102BC000B0F0E1F0660F771F881F991F1AF0BA95D1
:102BD000C9F714C0B13091F00E949A14B1E0089581
:102BE0000C949A14672F782F8827B85F39F0B93F73
:102BF000CCF3869577956795B395D9F73EF4909584
:102C00008095709561957F4F8F4F9F4F08950E94DB
:102C1000BC1308F48FEF089519F416F40C945614AD
:102C20000C9457160E948014B8F39923C9F3B6F395
:102C30009F57550B87FF0E9465160024A0E640EAC7
:102C4000900180585695979528F4805C660F771F01
:102C5000881F20F026173707480730F4621B730BD4
:102C6000840B202931294A2BA695179407942025F7
:102C700031254A2758F7660F771F881F20F026173F
:102C80003707480730F4620B730B840B200D311D9E
:102C9000411DA09581F7B901842F9158880F969511
:102CA000879508950E94BC13880B990B08959F3F48
:102CB00031F0915020F4879577956795B795880FF7
:102CC000911D9695879597F9089591505040660FFC
:102CD000771F881FD2F70895A1E21A2EAA1BBB1BEB
:102CE000FD010DC0AA1FBB1FEE1FFF1FA217B307D8
:102CF000E407F50720F0A21BB30BE40BF50B661FEE
:102D0000771F881F991F1A9469F7609570958095B1
:102D100090959B01AC01BD01CF010895052E97FB55
:102D20001EF400940E94A51657FD07D00E946C1651
:102D300007FC03D04EF40C94A516509540953095A1
:102D400021953F4F4F4F5F4F089590958095709517
:102D500061957F4F8F4F9F4F0895EE0FFF1F059096
:102D6000F491E02D09940F931F93CF93DF9382305A
:102D7000910510F482E090E0E0919E02F0919F02B4
:102D800020E030E0A0E0B0E0309719F140815181BF
:102D90000281138148175907C8F08417950769F411
:102DA000109731F012960C93129713961C9327C02C
:102DB00000939E0210939F0222C02115310519F045
:102DC0004217530718F49A01BD01EF01DF01F80122
:102DD000DBCF21153105F9F0281B390B24303105E3
:102DE00080F48A819B816115710521F0FB01938339
:102DF000828304C090939F0280939E02FE013296CC
:102E000044C0FE01E20FF31F8193919322503109D8
:102E1000398328833AC020919C0230919D02232B54
:102E200041F4209102013091030130939D022093DF
:102E30009C0220910001309101012115310541F4DE
:102E40002DB73EB74091040150910501241B350B6D
:102E5000E0919C02F0919D02E217F307A0F42E1B73
:102E60003F0B2817390778F0AC014E5F5F4F2417EE
:102E7000350748F04E0F5F1F50939D0240939C0210
:102E80008193919302C0E0E0F0E0CF01DF91CF9118
:102E90001F910F910895CF93DF93009709F481C09C
:102EA000FC01329713821282A0919E02B0919F0280
:102EB000109781F420813181820F931F20919C0211
:102EC00030919D022817390751F5F0939D02E09348
:102ED0009C0267C0ED0120E030E0CE17DF0740F430
:102EE0004A815B819E0141155105F1F0EA01F5CF60
:102EF000D383C28340815181840F951FC817D9079E
:102F000059F488819981840F951F0296918380835B
:102F10008A819B81938382832115310529F4F09363
:102F20009F02E0939E023DC0E901FB83EA83499141
:102F30005991C40FD51FEC17FD0761F48081918171
:102F4000840F951F0296E90199838883828193817A
:102F50009B838A83E0E0F0E012968D919C91139719
:102F6000009719F0FD01DC01F7CF8D919C9111972D
:102F70009D012E5F3F4F820F931F20919C02309145
:102F80009D022817390769F4309729F410929F029F
:102F900010929E0202C013821282B0939D02A093EF
:102FA0009C02DF91CF91089581E090E0F8940C9419
:102FB000E417FC018191861721F08823D9F799271E
:102FC00008953197CF01089511E0C2E4D1E004C023
:102FD000FE010E94AD162196C334D107C9F7F894BB
:022FE000FFCF21
:102FE2000000A0028000000000008B035703A90329
:102FF2001203FC02C402A3026F024E02F801B401E2
:103002000000000003043E086D0150049E017C0193
:1030120090016E616E00696E66006F7666000D0A41
:1030220000762E32303139303231310054004600D0
:0430320052454C00B7
:107E0000112484B714BE81FFF0D085E080938100F7
:107E100082E08093C00088E18093C10086E0809377
:107E2000C20080E18093C4008EE0C9D0259A86E02C
:107E300020E33CEF91E0309385002093840096BBD3
:107E4000B09BFECF1D9AA8958150A9F7CC24DD24C4
:107E500088248394B5E0AB2EA1E19A2EF3E0BF2EE7
:107E6000A2D0813461F49FD0082FAFD0023811F036
:107E7000013811F484E001C083E08DD089C08234E0
:107E800011F484E103C0853419F485E0A6D080C0E4
:107E9000853579F488D0E82EFF2485D0082F10E0AE
:107EA000102F00270E291F29000F111F8ED06801E7
:107EB0006FC0863521F484E090D080E0DECF843638
:107EC00009F040C070D06FD0082F6DD080E0C81688
:107ED00080E7D80618F4F601B7BEE895C0E0D1E017
:107EE00062D089930C17E1F7F0E0CF16F0E7DF06D8
:107EF00018F0F601B7BEE89568D007B600FCFDCFD4
:107F0000A601A0E0B1E02C9130E011968C91119780
:107F100090E0982F8827822B932B1296FA010C0160
:107F200087BEE89511244E5F5F4FF1E0A038BF0790
:107F300051F7F601A7BEE89507B600FCFDCF97BE46
:107F4000E89526C08437B1F42ED02DD0F82E2BD052
:107F50003CD0F601EF2C8F010F5F1F4F84911BD097
:107F6000EA94F801C1F70894C11CD11CFA94CF0C13
:107F7000D11C0EC0853739F428D08EE10CD085E9AC
:107F80000AD08FE07ACF813511F488E018D01DD067
:107F900080E101D065CF982F8091C00085FFFCCF94
:107FA0009093C60008958091C00087FFFCCF809118
:107FB000C00084FD01C0A8958091C6000895E0E648
:107FC000F0E098E1908380830895EDDF803219F02E
:107FD00088E0F5DFFFCF84E1DECF1F93182FE3DFCA
:107FE0001150E9F7F2DF1F91089580E0E8DFEE27F6
:047FF000FF270994CA
:027FFE00040479
:0400000300007E007B
:00000001FF

View file

@ -0,0 +1,48 @@
import json
import urllib2
import requests
import socket
import logging
try:
import ssl
except ImportError:
print "error: no ssl support"
_logger = logging.getLogger(__name__)
DISCOVERY_URL = "https://find.fabscan.org/register.php"
def get_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except:
IP = '127.0.0.1'
finally:
s.close()
return IP
def register_to_discovery(server_version, firmware_version):
_logger.info("Registering ip "+get_ip()+" to discovery service.")
headers = {
'Content-Type': 'application/json'
}
payload = {
'ip': str(get_ip()),
'server_version': str(server_version),
'firmware_version': str(firmware_version)
}
response = requests.post(DISCOVERY_URL, headers=headers, data=json.dumps(payload))
response.raise_for_status()
if response.status_code == 200:
_logger.info('Successfully registered to find.fabscan.org')
else:
_logger.warn('Not able to register to find.fabscan.org')

View file

@ -24,7 +24,12 @@ def get_latest_version_tag():
_logger.debug("Scanner is Online...")
try:
response = urllib2.urlopen("http://archive.fabscan.org/dists/stable/main/binary-armhf/Packages", timeout=0.4)
stage = "stable"
if "+" in __version__:
stage = "testing"
response = urllib2.urlopen("http://archive.fabscan.org/dists/" + str(stage) + "/main/binary-armhf/Packages", timeout=0.4)
latest_version = __version__
line = 'START'
while line != '':
@ -71,4 +76,4 @@ def upgrade_is_available(current_version):
def do_upgrade():
os.system('nohup bash -c "sudo apt-get update -y && sudo apt-get dist-upgrade -y" > /var/log/fabscanpi/upgrade.log')
os.system('nohup bash -c "sudo apt-get update -y && sudo apt-get dist-upgrade -y" >> /var/log/fabscanpi/upgrade.log')

View file

@ -82,6 +82,7 @@ class FSCalibration(FSCalibrationInterface):
def start(self):
#self._hardwarecontroller.stop_camera_stream()
tools = FSSystem()
tools.delete_folder(self.config.folders.scans+'calibration')
self._hardwarecontroller.turntable.enable_motors()
@ -106,8 +107,6 @@ class FSCalibration(FSCalibrationInterface):
self._do_calibration(self._capture_camera_calibration, self._calculate_camera_calibration)
self._do_calibration(self._capture_scanner_calibration, self._calculate_scanner_calibration)
self._hardwarecontroller.led.off()
self._hardwarecontroller.turntable.disable_motors()
if self._stop:
self._logger.debug("Calibration canceled...")
@ -154,10 +153,7 @@ class FSCalibration(FSCalibrationInterface):
# 90 degree turn
try:
if not self._stop:
self._logger.debug(self.quater_turn)
self._hardwarecontroller.turntable.step_blocking(self.quater_turn, speed=900)
# self._hardwarecontroller.start_camera_stream(mode="calibration")
position = 0
while abs(position) < self.quater_turn * 2:
@ -219,9 +215,9 @@ class FSCalibration(FSCalibrationInterface):
#TODO: find out if it is better and try this...again.
#if (position > self.laser_calib_start and position < self.laser_calib_end):
flags = cv2.CALIB_CB_FAST_CHECK | cv2.CALIB_CB_ADAPTIVE_THRESH | cv2.CALIB_CB_NORMALIZE_IMAGE
#flags = cv2.CALIB_CB_FAST_CHECK | cv2.CALIB_CB_ADAPTIVE_THRESH | cv2.CALIB_CB_NORMALIZE_IMAGE
#else:
# flags = cv2.CALIB_CB_FAST_CHECK
flags = cv2.CALIB_CB_FAST_CHECK
corners = self._imageprocessor.detect_corners(image, flags)

View file

@ -7,7 +7,7 @@ __email__ = "info@mariolukas.de"
import logging
import time
import threading
import copy
from fabscan.FSConfig import ConfigInterface
from fabscan.FSSettings import SettingsInterface
from fabscan.lib.util.FSInject import singleton
@ -55,10 +55,57 @@ class FSHardwareControllerSingleton(FSHardwareControllerInterface):
self._logger.debug("Hardware controller initialized...")
self.lock = threading.Lock()
self.hardware_test_functions = {
"TURNTABLE": {
"FUNCTIONS": {
"START": self.turntable.start_turning,
"STOP": self.turntable.stop_turning
},
"LABEL": "Turntable"
},
"LEFT_LASER": {
"FUNCTIONS": {
"ON": lambda: self.laser.on(0),
"OFF": lambda: self.laser.off(0)
},
"LABEL": "First Laser"
},
#"RIGHT_LASER": {
# "FUNCTIONS": {
# "ON": lambda: self.laser.on(1),
# "OFF": lambda: self.laser.off(1)
# },
# "LABEL": "Second Laser"
#},
"LED_RING": {
"FUNCTIONS": {
"ON": lambda: self.led.on(255, 255, 255),
"OFF": lambda: self.led.off()
},
"LABEL": "Led Ring"
}
}
def flush(self):
self.camera.camera_buffer.flush()
#self.serial_connection.flush()
def get_devices_as_json(self):
devices = copy.deepcopy(self.hardware_test_functions)
for fnct in self.hardware_test_functions:
devices[fnct]['FUNCTIONS'] = self.hardware_test_functions[fnct]['FUNCTIONS'].keys()
return devices
def call_test_function(self, device):
device_name = str(device.name)
device_value = str(device.function)
#self._logger.debug(device)
call_function = self.hardware_test_functions.get(device_name).get("FUNCTIONS").get(device_value)
call_function()
def settings_mode_on(self):
while not self.camera.device.is_idle():
time.sleep(0.1)
@ -66,7 +113,7 @@ class FSHardwareControllerSingleton(FSHardwareControllerInterface):
self._settings_mode_is_off = False
self.camera.device.flush_stream()
self.laser.on(laser=0)
self.turntable.start_turning()
#self.turntable.start_turning()
def settings_mode_off(self):
self.turntable.stop_turning()
@ -75,6 +122,8 @@ class FSHardwareControllerSingleton(FSHardwareControllerInterface):
self.camera.device.stop_stream()
self.camera.device.flush_stream()
self._settings_mode_is_off = True
time.sleep(0.3)
def get_picture(self):
img = self.camera.device.get_frame()

View file

@ -245,13 +245,19 @@ class ImageProcessor(ImageProcessorInterface):
def get_laser_stream_frame(self, image, type='CAMERA'):
points, ret_img = self.compute_2d_points(image, roi_mask=False)
u, v = points
c = zip(u, v)
if bool(self.settings.show_laser_overlay):
points, ret_img = self.compute_2d_points(image, roi_mask=False)
u, v = points
c = zip(u, v)
for t in c:
cv2.line(image, (int(t[0]) - 1, int(t[1])), (int(t[0]) + 1, int(t[1])), (255, 0, 0), thickness=1,
lineType=8, shift=0)
if bool(self.settings.show_calibration_pattern):
cv2.line(image, (int(0.5*image.shape[1]), 0), (int(0.5*image.shape[1]), image.shape[0]), (0, 255, 0), thickness=1, lineType=8, shift=0)
cv2.line(image, (0,int(0.5*image.shape[0])), (image.shape[1], int(0.5*image.shape[0])), (0, 255, 0), thickness=1, lineType=8, shift=0)
for t in c:
cv2.line(image, (int(t[0]) - 1, int(t[1])), (int(t[0]) + 1, int(t[1])), (255, 0, 0), thickness=1,
lineType=8, shift=0)
return image

View file

@ -202,6 +202,8 @@ class FSScanProcessor(FSScanProcessorInterface):
pass
def start_calibration(self):
self.hardwareController.settings_mode_off()
time.sleep(0.5)
self.calibration.start()
def stop_calibration(self):
@ -227,9 +229,19 @@ class FSScanProcessor(FSScanProcessorInterface):
self.eventmanager.broadcast_client_message(FSEvents.ON_INFO_MESSAGE, message)
def settings_mode_on(self):
#message = {
# "message": "SETTINGS_MODE_ON",
# "level": "info"
#}
#self.eventmanager.broadcast_client_message(FSEvents.ON_INFO_MESSAGE, message)
self.hardwareController.settings_mode_on()
def settings_mode_off(self):
#message = {
# "message": "SETTINGS_MODE_OFF",
# "level": "info"
#}
#self.eventmanager.broadcast_client_message(FSEvents.ON_INFO_MESSAGE, message)
self.hardwareController.settings_mode_off()
def start_scan(self):
@ -255,7 +267,7 @@ class FSScanProcessor(FSScanProcessorInterface):
self._prefix = datetime.fromtimestamp(time.time()).strftime('%Y%m%d-%H%M%S')
self.point_cloud = FSPointCloud(color=self._is_color_scan)
if not (self.config.calibration.camera_matrix == []) and self.actor_ref.is_alive():
if not (self.config.calibration.laser_planes[0]['normal'] == []) and self.actor_ref.is_alive():
if self._is_color_scan:
self._total = self._number_of_pictures * 2 * self.config.laser.numbers
self.actor_ref.tell({FSEvents.COMMAND: FSScanProcessorCommand._SCAN_NEXT_TEXTURE_POSITION})

View file

@ -124,6 +124,7 @@ class CamProcessor(threading.Thread):
if self.mode == "settings":
image = self.imageprocessor.get_laser_stream_frame(image)
#if self.use_distortion:
# if image is not None and \
# self.config.calibration.camera_matrix is not [] and \
@ -229,8 +230,15 @@ class PiCam(threading.Thread):
# self.resolution = (self.config.camera.preview_resolution.width, self.config.camera.preview_resolution.height)
self.camera_buffer = cam_ring_buffer
# self.camera = picamera.PiCamera(resolution=self.resolution)
self.newcameramtx = None
self.roi = None
self.mapx = None
self.mapy = None
self.idle = True
self.resolution = (self.config.camera.preview_resolution.width, self.config.camera.preview_resolution.height)
self.camera = picamera.PiCamera(resolution=self.resolution)
self.start()
def run(self):
@ -246,11 +254,24 @@ class PiCam(threading.Thread):
else:
time.sleep(0.05)
def get_frame(self):
def get_frame(self, undistort=False):
image = None
while image is None:
#with self.camera_buffer._lock:
image = self.camera_buffer.get()
#if undistort:
# self._logger.debug(self.config.calibration.camera_matrix)
# self.newcameramtx, self.roi = cv2.getOptimalNewCameraMatrix(np.asarray(self.config.calibration.camera_matrix), np.asarray(self.config.calibration.distortion_vector), self.resolution, 1, self.resolution )
#image = cv2.remap(image, self.mapx, self.mapy, cv2.INTER_LINEAR)
# image = cv2.undistort(image,
# np.asarray(self.config.calibration.camera_matrix),
# np.asarray(self.config.calibration.distortion_vector),
# None,
# self.newcameramtx)
return image
def set_mode(self, mode):
@ -286,8 +307,25 @@ class PiCam(threading.Thread):
#self.flush_stream()
self.set_mode(mode)
if self.camera is None:
self.camera = picamera.PiCamera(resolution=self.resolution)
#if len(self.config.calibration.camera_matrix) > 0:
# self.newcameramtx, self.roi = cv2.getOptimalNewCameraMatrix(self.config.calibration.camera_matrix,
# self.config.calibration.distortion_vector,
# self.resolution,
# 1,
# self.resolution)
# self.mapx, self.mapy = cv2.initUndistortRectifyMap(self.config.calibration.camera_matrix,
# self.config.calibration.distortion_vector,
# None,
# self.newcameramtx,
# self.resolution,
# 5)
#if self.camera is None:
# self.camera = picamera.PiCamera(resolution=self.resolution)
if self.camera:
self.camera.resolution = self.resolution
self.idle = False
self.camera.start_recording(self.output, format='mjpeg')
@ -303,8 +341,8 @@ class PiCam(threading.Thread):
self.camera.stop_recording()
while self.camera.recording:
time.sleep(0.4)
self.camera.close()
self.camera = None
#self.camera.close()
#self.camera = None
self.idle = True
self._logger.debug("Cam Stream with Resolution " + str(self.resolution) + " stopped")
@ -318,6 +356,7 @@ class PiCam(threading.Thread):
def flush_stream(self):
self.camera_buffer.flush()
###
# This class is used to catch openCV errors which are not catchable by python
# see https://stackoverflow.com/questions/9131992/how-can-i-catch-corrupt-jpegs-when-loading-an-image-with-imread-in-opencv/45055195
@ -413,7 +452,7 @@ class USBCam(threading.Thread):
def set_settings_preview(self):
self.resolution = (
self.config.camera.preview_resolution.width, self.config.camera.preview_resolution.height)
self.config.camera.resolution.width, self.config.camera.resolution.height)
self.output = ProcessCamOutput(self.camera_buffer, self.resolution, mode="settings")
def set_default_mode(self):

View file

@ -9,10 +9,12 @@ import glob
import serial
import time
import logging
import threading
from fabscan.lib.util.FSUtil import FSSystem
from fabscan.lib.util.FSInject import inject
from fabscan.FSConfig import ConfigInterface
@inject(
config=ConfigInterface
)
@ -41,7 +43,8 @@ class FSSerialCom():
self._openSerial()
self._logger.debug("Connection baudrate is: "+str(self._baudrate))
self._logger.debug("Firmware flashing baudrate is: "+str(self.flash_baudrate))
self.lock = threading.RLock()
self._stop = False
def avr_device_is_available(self):
status = FSSystem.run_command("sudo avrdude-autoreset -p m328p -b "+str(self.flash_baudrate)+" -carduino -P"+str(self._port))
@ -58,7 +61,7 @@ class FSSerialCom():
self._logger.debug("Trying to connect Arduino on port: "+str(self._port))
# open serial port
try:
self._serial = serial.Serial(str(self._port), int(self._baudrate), timeout=0.3)
self._serial = serial.Serial(str(self._port), int(self._baudrate), timeout=5)
time.sleep(1)
except:
self._logger.error("Could not open serial port")
@ -68,8 +71,10 @@ class FSSerialCom():
def _openSerial(self):
basedir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))
flash_file_version = max(sorted(glob.iglob(basedir+'/firmware/*.hex'), key=os.path.getctime,reverse=True))
flash_version_number = os.path.basename(os.path.normpath(os.path.splitext(flash_file_version)[0]))
flash_file_version = max(sorted(glob.iglob(basedir+'/firmware/'+str(self.config.serial.plattform_type)+'_*.hex'), key=os.path.getctime, reverse=True))
flash_version_number = os.path.basename(os.path.normpath(os.path.splitext(flash_file_version.split('_', 1)[-1])[0]))
self._logger.debug("Latest available firmware version is: "+flash_version_number)
try:
@ -144,17 +149,19 @@ class FSSerialCom():
def send_and_receive(self, message):
self.send(message)
time.sleep(0.2)
# time.sleep(0.2)
response = ""
while True:
response += self._serial.read()
if ">" in response:
response = response.rstrip(">")
response = response.translate(None, '\n\t\r')
if response:
self._logger.debug("Command successfully sent: " + response)
break
self._stop = False
with self.lock:
while not self._stop:
response += self._serial.read()
if ">" in response:
response = response.rstrip(">")
response = response.translate(None, '\n\t\r')
if response:
self._logger.debug("Command successfully sent: " + response)
self._stop = True
break
def flush(self):
self._serial.flushInput()

View file

@ -4,6 +4,7 @@ __license__ = "GPL v2"
__maintainer__ = "Mario Lukas"
__email__ = "info@mariolukas.de"
import time
from fabscan.lib.util.FSInject import inject
from fabscan.FSConfig import ConfigInterface
@ -34,8 +35,9 @@ class Turntable(object):
steps *= self.scaler
if self.serial_connection != None:
command = "G02 T"+str(steps)+" F"+str(speed)+";"
command = "G04 T"+str(steps)+" F"+str(speed)+";"
self.serial_connection.send_and_receive(command)
time.sleep(1)
def enable_motors(self):
if self.serial_connection != None:

View file

@ -16,24 +16,29 @@ from fabscan.server.services.api.FSScanHandler import FSScanHandler
from fabscan.server.services.api.FSStreamHandler import FSStreamHandler
from fabscan.server.services.api.FSStaticFileHandler import FSStaticFileHandler
from fabscan.server.services.api.FSDownloadHandler import FSDownloadHandler
from fabscan.server.services.api.FSLogHandler import FSLogHandler
from fabscan.server.services.api.FSDeviceHandler import FSDeviceHandler
from fabscan.FSEvents import FSEvents, FSEventManagerSingleton
from fabscan.scanner.interfaces.FSScanProcessor import FSScanProcessorInterface
from fabscan.scanner.interfaces.FSHardwareController import FSHardwareControllerInterface
from fabscan.FSConfig import ConfigSingleton, ConfigInterface
from fabscan.lib.util.FSInject import inject
@inject(
config=ConfigInterface,
scanprocessor=FSScanProcessorInterface,
eventmanager=FSEventManagerSingleton
eventmanager=FSEventManagerSingleton,
hardwarecontroller=FSHardwareControllerInterface
)
class FSWebServer(threading.Thread):
def __init__(self, config, scanprocessor, eventmanager):
def __init__(self, config, scanprocessor, eventmanager, hardwarecontroller):
threading.Thread.__init__(self)
self.config = config
self.exit = False
self.scanprocessor = scanprocessor
self.eventmanager = eventmanager
self.hardwarecontroller = hardwarecontroller
self.www_folder = os.path.join(os.path.dirname(__file__), self.config.folders.www)
self.scan_folder = os.path.join(os.path.dirname(__file__), self.config.folders.scans)
self._logger = logging.getLogger(__name__)
@ -43,7 +48,10 @@ class FSWebServer(threading.Thread):
return tornado.web.Application([
(r"/api/v1/filters/", FSFilterHandler),
(r"/api/v1/streams/", FSStreamHandler, dict(scanprocessor=self.scanprocessor)),
(r"/api/v1/log/show", FSLogHandler, dict(config=self.config)),
(r"/api/v1/log/download", FSLogHandler, dict(config=self.config)),
(r"/api/v1/scans/", FSScanHandler, dict(config=self.config)),
(r"/api/v1/devices/", FSDeviceHandler, dict(config=self.config, hardwarecontroller=self.hardwarecontroller)),
(r"/api/v1/scans/(?P<scan_id>\d{8}[-]\d{6}$)", FSScanHandler, dict(config=self.config)),
(r"/api/v1/scans/(?P<scan_id>\d{8}[-]\d{6})/(?P<files>files)$", FSScanHandler, dict(config=self.config)),
(r"/api/v1/scans/(?P<scan_id>\d{8}[-]\d{6})/(?P<files>downloads)/(?P<file_name>.*)$", FSDownloadHandler, dict(config=self.config)),

View file

@ -2,6 +2,10 @@ import tornado.web
class BaseHandler(tornado.web.RequestHandler):
def set_extra_headers(self, path):
# Disable cache
self.set_header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
def set_default_headers(self):
self.set_header("Access-Control-Allow-Origin", "*")
self.set_header("Access-Control-Allow-Headers", "x-requested-with")

View file

@ -0,0 +1,19 @@
import os
import json
import glob
import shutil
import logging
import tornado.web
from fabscan.lib.file.FSScans import FSScans
from fabscan.server.services.api.FSBaseHandler import BaseHandler
class FSDeviceHandler(BaseHandler):
def initialize(self, *args, **kwargs):
self._logger = logging.getLogger(__name__)
self.config = kwargs.get('config')
self.hardwarecontroller = kwargs.get('hardwarecontroller')
def get(self):
devices = self.hardwarecontroller.get_devices_as_json()
self.write(json.dumps(devices))

View file

@ -0,0 +1,90 @@
import subprocess
import logging
import tornado.web
import time
from os.path import basename
from datetime import datetime
from zipfile import ZipFile
from fabscan.lib.file.FSScans import FSScans
from fabscan.server.services.api.FSBaseHandler import BaseHandler
class FSLogHandler(BaseHandler):
def initialize(self, *args, **kwargs):
self._logger = logging.getLogger(__name__)
self.config = kwargs.get('config')
self.scanlib = FSScans()
@tornado.web.asynchronous
def get(self):
try:
log_file = self._logger.handlers[0].baseFilename
except:
log_file = "/var/log/fabscanpi/fabscanpi.log"
timestamp = datetime.fromtimestamp(time.time()).strftime('%Y%m%d-%H%M%S')
if "download" in self.request.path:
zip_file = "/tmp/fanbscanpi-debug-" + timestamp + ".zip"
config_file = "/etc/fabscanpi/default.config.json"
settings_file = "/etc/fabscanpi/default.settings.json"
process_list = "/tmp/process_list.txt"
cpu_info = "/tmp/cpu_info.txt"
voltage_monitor = "/tmp/voltage_state.txt"
process = subprocess.Popen(["ps -axf > " + process_list], shell=True, stdout=subprocess.PIPE)
process.wait()
process = subprocess.Popen(["cat /proc/cpuinfo > " + cpu_info], shell=True, stdout=subprocess.PIPE)
process.wait()
process = subprocess.Popen(["vcgencmd get_throttled > " + voltage_monitor], shell=True, stdout=subprocess.PIPE)
process.wait()
# put all debug files to zip
with ZipFile(zip_file, 'w') as log_zip:
log_zip.write(log_file, basename(log_file))
log_zip.write(config_file, basename(config_file))
log_zip.write(settings_file, basename(settings_file))
log_zip.write(process_list, basename(process_list))
log_zip.write(cpu_info, basename(cpu_info))
log_zip.write(voltage_monitor, basename(voltage_monitor))
buf_size = 4096
self.set_header('Content-Type', 'application/octet-stream')
self.set_header('Content-Disposition', 'attachment; filename='+basename(zip_file))
with open(zip_file, 'r') as f:
while True:
data = f.read(buf_size)
if not data:
break
self.write(data)
self.finish()
if "show" in self.request.path:
try:
self.p = subprocess.Popen( ["tail", "-f", log_file, "-n+1"], stdout=subprocess.PIPE)
self.write("<pre>")
self.flush()
self.stream = tornado.iostream.PipeIOStream(self.p.stdout.fileno())
self.stream.read_until("\n", self.line_from_nettail)
except:
self.write("No log path configured. Default logging to stdout is active.<br>")
self.write("For seeing a log output here you need to configure a log file path.<br>")
self.flush()
self.finish()
def on_connection_close(self, *args, **kwargs):
"""Clean up the nettail process when the connection is closed.
"""
self.p.terminate()
tornado.web.RequestHandler.on_connection_close(self, *args, **kwargs)
def line_from_nettail(self, data):
self.write(data)
self.flush()
self.stream.read_until("\n", self.line_from_nettail)

View file

@ -6,9 +6,11 @@
type="image/png"
href="icons/favicon.png">
<meta charset="utf-8">
<meta http-equiv="Pragma" content="no-cache">
<meta name=viewport content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name=apple-mobile-web-app-capable content=yes>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<link href="style/lib.css" rel="stylesheet">
<link href="style/app.css" rel="stylesheet">
@ -83,114 +85,150 @@
</div>
<!-- Settings View -->
<div class="settingsWindow" ng-class="{'open':('SETTINGS' | currentState)}">
<div ng-if="('SETTINGS' | currentState)" ng-controller="fabscan.controller.FSSettingsController" >
<div id="settingsWindow" class="settingsWindow" ng-class="{'open':('SETTINGS' | currentState)}">
<div ng-if="('SETTINGS' | currentState)" ng-controller="fabscan.controller.FSSettingsController" >
<!-- <div style="background-color: black; height:240px; position:absolute; left:0px;"></div>-->
<div>
<mjpeg mode="'preview'" url="streamUrl"></mjpeg>
</div>
<div class="settings-content">
<div style="height: 40px;">
<div ng-click="selectTab('general')" class="tab icon settings" ng-class="{'active':(selectedTab == 'general')}">
<i class="fa fa-cogs fa-2x"></i>
</div>
<div ng-click="selectTab('camera')" class="tab icon settings" ng-class="{'active':(selectedTab == 'camera')}">
<i class="fa fa-adjust fa-2x"></i>
</div>
<div ng-click="selectTab('light')" class="tab icon settings" ng-class="{'active':(selectedTab == 'light')}">
<i class="fa fa-sun-o fa-2x"></i>
</div>
<!--
<div ng-click="setCalibrationTab()" class="tab icon settings" ng-class="{'active':(selectedTab == 'calibration')}">
<i class="fa fa-crosshairs fa-2x"></i>
</div>
-->
<div class="tab" sytle="width:100%">
</div>
</div>
<div style="z-index:100;" class="settings-preview" id="settings-preview">
<div style="text-align:center; position:absolute; background-color:black; color: white; height:800px; width:300px; z-index:-1000">
<div style="margin-top:70%;">
<img style="position:absolute; margin-top:50%; width:50px; height:50px;" src="icons/spinner.gif" />
Preview is loading...
</div>
</div>
<mjpeg style="z-index:2000" url="streamUrl"></mjpeg>
</div>
<div class="settings-content">
<div class="tab-content" ng-show="(selectedTab == 'general')">
<div>
<div ng-class="{'fadeOut':!showThresholdValue}" class="slider-value-label">{{settings.threshold}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Threshold</div>
<slider style="width:70%; margin-left:1em;" floor="0" ceiling="60" step="1" precision="1" ng-model="settings.threshold"></slider>
</div>
<div>
<div ng-class="{'longFadeOut':!showResolutionValue}" class="slider-value-label" >{{settings.resolution | toResolutionValue }}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Resolution</div>
<slider class="resolution" style="width:70%; margin-left:1em;" show-steps="true" floor="-16" ceiling="-1" step="4" precision="1" ng-model="settings.resolution"></slider>
</div>
<!--
<div>
<div ng-class="{'longFadeOut':!showResolutionValue}" class="slider-value-label" >{{settings.laser_positions}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Positions</div>
<slider class="resolution" style="width:70%; margin-left:1em;" floor="1" ceiling="4" step="1" precision="1" ng-model="settings.laser_positions"></slider>
</div>
-->
<div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;" >Color Scan</div><input style="width:1em; height:1em; margin-left:1.5em; margin-top:0.5em;" type="checkbox" ng-change="setColor()" ng-checked="colorIsSelected()" ng-model="settings.color">
<div style="height: 40px;">
<div ng-click="selectTab('general')" class="tab icon settings" ng-class="{'active':(selectedTab == 'general')}">
<i class="fa fa-cogs fa-2x"></i>
</div>
<div ng-click="selectTab('camera')" class="tab icon settings" ng-class="{'active':(selectedTab == 'camera')}">
<i class="fa fa-adjust fa-2x"></i>
</div>
<div ng-click="selectTab('light')" class="tab icon settings" ng-class="{'active':(selectedTab == 'light')}">
<i class="fa fa-sun-o fa-2x"></i>
</div>
<div ng-click="selectTab('hardware')" class="tab icon settings" ng-class="{'active':(selectedTab == 'hardware')}">
<i class="fa fa-sliders fa-2x"></i>
</div>
<a class="hvr-grow" style="margin-right: 13%; margin-top:0.2em; text-decoration:none; float:right; color:white; font-size:1.5em;" ng-click="startScan()" href="#">Start Scan</a>
</div>
</div>
<div class="tab-content" ng-show="(selectedTab == 'camera')">
<div>
<div ng-class="{'fadeOut':!showSaturationValue}" class="slider-value-label" >{{settings.camera.saturation}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Saturation</div>
<slider style="width:70%; margin-left:1em;" floor="-100" ceiling="100" step="1" precision="1" ng-model="settings.camera.saturation"></slider>
</div>
<div>
<div ng-class="{'fadeOut':!showBrightnessValue}" class="slider-value-label" >{{settings.camera.brightness}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Brightness</div>
<slider style="width:70%; margin-left:1em;" floor="0" ceiling="100" step="1" precision="1" ng-model="settings.camera.brightness"></slider>
</div>
<div>
<div ng-class="{'fadeOut':!showContrastValue}" class="slider-value-label" >{{settings.camera.contrast}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Contrast</div>
<slider style="width:70%; margin-left:1em;" floor="-100" ceiling="100" step="1" precision="1" ng-model="settings.camera.contrast"></slider>
</div>
<div ng-click="setCalibrationTab()" class="tab icon settings" ng-class="{'active':(selectedTab == 'calibration')}">
<i class="fa fa-crosshairs fa-2x"></i>
</div>
</div>
<div class="tab-content" ng-show="(selectedTab == 'light')">
<div>
<div ng-class="{'fadeOut':!showLedRedValue}" class="slider-value-label" >{{settings.led.red}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Red</div>
<slider style="width:70%; margin-left:1em;" floor="0" ceiling="255" step="1" precision="1" ng-model="settings.led.red"></slider>
</div>
<div>
<div ng-class="{'fadeOut':!showLedGreenValue}" class="slider-value-label" >{{settings.led.green}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Green</div>
<slider style="width:70%; margin-left:1em;" floor="0" ceiling="255" step="1" precision="1" ng-model="settings.led.green"></slider>
</div>
<div>
<div ng-class="{'fadeOut':!showLedBlueValue}" class="slider-value-label" >{{settings.led.blue}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Blue</div>
<slider style="width:70%; margin-left:1em;" floor="0" ceiling="255" step="1" precision="1" ng-model="settings.led.blue"></slider>
</div>
</div>
<!--
<div class="tab-content" ng-if="(selectedTab == 'calibration')">
<div style="display:inline-block; width:100%; margin-top:1em; color:white; padding-left:1em;">
Calibration<br>
<br>
Before calibration remove objects!
<a class="hvr-grow" style="margin-right: 13%; margin-top:0.2em; bottom: 0px; text-decoration:none; float:right; color:white; font-size:1.5em;" ng-click="startCalibration()" href="#">Start Calibration</a>
</div>
</div>-->
</div>
</div>
</div>
<div class="tab" sytle="width:100%">
</div>
</div>
<div class="tab-content" ng-show="(selectedTab == 'general')">
<div style="margin-right:20em;">
<div ng-class="{'fadeOut':!showThresholdValue}" class="slider-value-label">{{settings.threshold}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Threshold</div>
<slider style="width:70%; margin-left:1em;" floor="0" ceiling="60" step="1" precision="1" ng-model="settings.threshold"></slider>
</div>
<div style="margin-right:20em;">
<div ng-class="{'longFadeOut':!showResolutionValue}" class="slider-value-label" >{{settings.resolution | toResolutionValue }}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Resolution</div>
<slider class="resolution" style="width:70%; margin-left:1em;" show-steps="true" floor="-16" ceiling="-1" step="4" precision="1" ng-model="settings.resolution"></slider>
</div>
<!--
<div>
<div ng-class="{'longFadeOut':!showResolutionValue}" class="slider-value-label" >{{settings.laser_positions}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Positions</div>
<slider class="resolution" style="width:70%; margin-left:1em;" floor="1" ceiling="4" step="1" precision="1" ng-model="settings.laser_positions"></slider>
</div>
-->
<div style="margin-right:20em;">
<div style="width:100%; margin-bottom:1em; margin-top:1em;">
<div style="display:inline-block; width:15em; color:white; padding-left:1em;" >Scan with Color</div><input style="width:1em; height:1em; margin-left:1.5em; margin-top:0.5em;" type="checkbox" ng-change="setColor()" ng-checked="colorIsSelected()" ng-model="settings.color">
</div>
</div>
<div style="margin-right:20em;">
<div >
<button class="fsButton" style="margin-top:2em; margin-left:1em; text-decoration:none; color:white;" ng-click="startScan()" href="#">Start Scan</button>
</div>
</div>
</div>
<div class="tab-content" ng-show="(selectedTab == 'camera')">
<div style="margin-right:20em;">
<div ng-class="{'fadeOut':!showSaturationValue}" class="slider-value-label" >{{settings.camera.saturation}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Saturation</div>
<slider style="width:70%; margin-left:1em;" floor="-100" ceiling="100" step="1" precision="1" ng-model="settings.camera.saturation"></slider>
</div>
<div style="margin-right:20em;">
<div ng-class="{'fadeOut':!showBrightnessValue}" class="slider-value-label" >{{settings.camera.brightness}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Brightness</div>
<slider style="width:70%; margin-left:1em;" floor="0" ceiling="100" step="1" precision="1" ng-model="settings.camera.brightness"></slider>
</div>
<div style="margin-right:20em;">
<div ng-class="{'fadeOut':!showContrastValue}" class="slider-value-label" >{{settings.camera.contrast}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Contrast</div>
<slider style="width:70%; margin-left:1em;" floor="-100" ceiling="100" step="1" precision="1" ng-model="settings.camera.contrast"></slider>
</div>
</div>
<div class="tab-content" ng-show="(selectedTab == 'light')">
<div style="margin-right:20em;">
<div ng-class="{'fadeOut':!showLedRedValue}" class="slider-value-label" >{{settings.led.red}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Red</div>
<slider style="width:70%; margin-left:1em;" floor="0" ceiling="255" step="1" precision="1" ng-model="settings.led.red"></slider>
</div>
<div style="margin-right:20em;">
<div ng-class="{'fadeOut':!showLedGreenValue}" class="slider-value-label" >{{settings.led.green}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Green</div>
<slider style="width:70%; margin-left:1em;" floor="0" ceiling="255" step="1" precision="1" ng-model="settings.led.green"></slider>
</div>
<div style="margin-right:20em;">
<div ng-class="{'fadeOut':!showLedBlueValue}" class="slider-value-label" >{{settings.led.blue}}</div>
<div style="display:inline-block; width:5em; color:white; padding-left:1em;">Blue</div>
<slider style="width:70%; margin-left:1em;" floor="0" ceiling="255" step="1" precision="1" ng-model="settings.led.blue"></slider>
</div>
</div>
<div class="tab-content" ng-show="(selectedTab == 'hardware')">
<div ng-repeat="(key,values) in devices">
<div style="padding:1em;">
<span style="display:inline-block; width:8em; color:white; padding-left:1em;">{{devices[key]['LABEL']}}</span>
<button style="margin-right:1em;" class="fsButton" ng-repeat="function in devices[key]['FUNCTIONS']" ng-click="sendDeviceCommand(key, function)">{{function}}</button>
</div>
</div>
<div style="margin-right:20em;">
<div style="width:100%; margin-bottom:1em;">
<div style="display:inline-block; width:15em; color:white; padding-left:1em;" >Show Laser Overlay</div><input style="width:1em; height:1em; margin-left:1.5em; margin-top:0.5em;" type="checkbox" ng-change="setLaserOverlay()" ng-checked="laserOverlaySelected()" ng-model="settings.show_laser_overlay">
</div>
<div style="width:100%; margin-bottom:1em;">
<div style="display:inline-block; width:15em; color:white; padding-left:1em;" >Show Alignment Cross</div><input style="width:1em; height:1em; margin-left:1.5em; margin-top:0.5em;" type="checkbox" ng-change="setCalibrationPattern()" ng-checked="calibrationPatternSelected()" ng-model="settings.show_calibration_pattern">
</div>
</div>
</div>
<div class="tab-content" ng-if="(selectedTab == 'calibration')">
<div style="display:inline-block; width:100%; margin-top:1em; color:white; padding-left:1em;">
<div style="margin-top:2em;">
<button class="fsButton" ng-click="startCalibration()">Start Calibration</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Scan View -->
<div ng-controller="fabscan.controller.FSPreviewController" style="margin: 0 auto; z-index:-100;">
<div ng-if="showStream" class="texture-preview">
<mjpeg mode="'texture'" url="streamUrl"></mjpeg>
<div style="z-index:100;" ng-if="showStream" class="texture-preview">
<mjpeg url="streamUrl"></mjpeg>
</div>
<div ng-click="manviewhandler()">
<div
id="webgl"
@ -207,6 +245,7 @@
<span>Server: {{server_version}} <br> Firmware: {{firmware_version}}</span>
</div>
<!--
<div style="position:absolute; left:10px; top:2px; color:white">
<a class="icon" style="" ng-click="startCalibration()" ng-show="(!scanIsLoading() && ('IDLE' | currentState) && !('CALIBRATING' | currentState))">
<span class="hvr-grow">
@ -214,6 +253,7 @@
</span>
</a>
</div>
-->
<!--<div style="position:absolute;">
<a href="#" ng-click="renderObjectAsType('MESH')">Show Mesh</a>
@ -373,6 +413,7 @@
</ul>
</div>
</div>
</div>
</div>
@ -381,7 +422,7 @@
</div>
<div id="controlpanel" class="footer row" style="background-color: grey">
<div id="controlpanel" class="footer row" style="z-index:1000; background-color: grey">
<!--<div ng-show="isConnected">-->
<div ng-if="appIsInitialized">

View file

@ -9,7 +9,7 @@
(function() {
var m, mods;
mods = ['common.services.envProvider', 'common.filters.currentStateFilter', 'common.filters.toLabelFilter', 'common.filters.toResolutionValue', 'fabscan.directives.FSWebglDirective', 'fabscan.directives.FSMJPEGStream', 'fabscan.directives.FSModalDialog', 'fabscan.directives.text', 'fabscan.services.FSMessageHandlerService', 'fabscan.services.FSEnumService', 'fabscan.services.FSWebsocketConnectionFactory', 'fabscan.services.FSScanService', 'fabscan.services.FSi18nService', 'common.filters.scanDataAvailableFilter', 'common.services.Configuration', 'common.services.toastrWrapperSvc', 'fabscan.controller.FSPreviewController', 'fabscan.controller.FSAppController', 'fabscan.controller.FSNewsController', 'fabscan.controller.FSSettingsController', 'fabscan.controller.FSScanController', 'fabscan.controller.FSLoadingController', 'fabscan.controller.FSShareController', 'ngSanitize', 'ngTouch', 'ngCookies', '720kb.tooltips', 'ngProgress', 'vr.directives.slider', 'slickCarousel'];
mods = ['common.services.envProvider', 'common.filters.currentStateFilter', 'common.filters.toLabelFilter', 'common.filters.toResolutionValue', 'fabscan.directives.FSWebglDirective', 'fabscan.directives.FSMJPEGStream', 'fabscan.directives.FSModalDialog', 'fabscan.directives.text', 'fabscan.services.FSMessageHandlerService', 'fabscan.services.FSEnumService', 'fabscan.services.FSWebsocketConnectionFactory', 'fabscan.services.FSScanService', 'fabscan.services.FSi18nService', 'common.filters.scanDataAvailableFilter', 'fabscan.directives.onSizeChanged', 'common.services.Configuration', 'common.services.toastrWrapperSvc', 'fabscan.controller.FSPreviewController', 'fabscan.controller.FSAppController', 'fabscan.controller.FSNewsController', 'fabscan.controller.FSSettingsController', 'fabscan.controller.FSScanController', 'fabscan.controller.FSLoadingController', 'fabscan.controller.FSShareController', 'ngSanitize', 'ngTouch', 'ngCookies', '720kb.tooltips', 'ngProgress', 'vr.directives.slider', 'slickCarousel'];
/*
*/
@ -62,38 +62,25 @@
name = 'fabscan.directives.FSMJPEGStream';
angular.module(name, []).directive('mjpeg', [
'$log', function($log) {
return {
restrict: 'E',
replace: true,
template: '<span></span>',
scope: {
'url': '=',
'mode': '='
},
link: function(scope, element, attrs) {
scope.createFrame = function(newVal) {
var doc, iframe, iframeHtml;
angular.module(name, []).directive('mjpeg', function() {
return {
restrict: 'E',
replace: true,
template: '<span></span>',
scope: {
'url': '='
},
link: function(scope, element, attrs) {
scope.$watch('url', (function(newVal, oldVal) {
var doc, iframe, iframeHtml;
if (newVal) {
iframe = document.createElement('iframe');
iframe.setAttribute('width', '100%');
iframe.setAttribute('frameborder', '0');
iframe.setAttribute('scrolling', 'no');
iframe.setAttribute('style', "height:100%; position:absolute;");
if (element.childElementCount > 0) {
element.childNodes[0].destroy();
element.append(iframe);
} else {
element.append(iframe);
}
if (scope.mode === "texture") {
iframe.setAttribute('width', '100%');
iframeHtml = '<html><head><base target="_parent" /><style type="text/css">html, body { margin: 0; padding: 0; height: 320px; }</style><script> function resizeParent() { var ifs = window.top.document.getElementsByTagName("iframe"); for (var i = 0, len = ifs.length; i < len; i++) { var f = ifs[i]; var fDoc = f.contentDocument || f.contentWindow.document; if (fDoc === document) { f.height = 0; f.height = document.body.scrollHeight; } } }</script></head><body style="" onresize="resizeParent()"><div><img src="' + newVal + '" style="z-index:1000; display: block; margin-left: auto; margin-right: auto; width: 30em; margin-top:1em; -webkit-mask-image: radial-gradient(ellipse 106% 148% at 50% 50%, black 35%, transparent 48%); mask-image: radial-gradient(ellipse 106% 148% at 50% 50%, black 35%, transparent 48%);" onload="resizeParent()" /></div></body></html>';
}
if (scope.mode === "preview") {
iframe.setAttribute('height', '240px');
iframeHtml = '<html><head><base target="_parent" /><style type="text/css">html, body { margin: 0; padding: 0; height: 240px; }</style><script> function resizeParent() { var ifs = window.top.document.getElementsByTagName("iframe"); for (var i = 0, len = ifs.length; i < len; i++) { var f = ifs[i]; var fDoc = f.contentDocument || f.contentWindow.document; if (fDoc === document) { f.width = 0; f.width = document.body.scrollWidth; } } }</script></head><body onresize="resizeParent()"><img src="' + newVal + '" style="z-index:1000; opacity: 1.0; height:240px; position:absolute;" onload="resizeParent()" /><div style="position:absolute; text-align:center; background-color:black; width:180px; height:240px; float:left; z-index:-1000;"><img style="margin-top:100px; margin-left:70px width:50px; height:50px;" src="icons/spinner.gif" /></div></body></html>';
}
element.replaceWith(iframe);
iframeHtml = '<html><head><base target="_parent" /><style type="text/css">html, body { margin: 0; padding: 0; height: 100%; width: 100%; }</style><script> function resizeParent() { var ifs = window.top.document.getElementsByTagName("iframe"); for (var i = 0, len = ifs.length; i < len; i++) { var f = ifs[i]; var fDoc = f.contentDocument || f.contentWindow.document; if (fDoc === document) { f.height = 0; f.height = document.body.scrollHeight; } } }</script></head><body onresize="resizeParent()"><img src=\"' + newVal + '\" style="width: 100%; height: auto" onload="resizeParent()" /></body></html>';
doc = iframe.document;
if (iframe.contentDocument) {
doc = iframe.contentDocument;
@ -102,15 +89,14 @@
}
doc.open();
doc.writeln(iframeHtml);
return doc.close();
};
scope.$watch('url', (function(newVal, oldVal) {
return scope.createFrame(newVal);
}), true);
}
};
}
]);
doc.close();
} else {
element.html('<span></span>');
}
}), true);
}
};
});
}).call(this);
@ -323,7 +309,7 @@
var screenshot;
screenshot = renderer.domElement.toDataURL('image/png');
return $http.post(Configuration.installation.httpurl + "api/v1/scans/" + id + "/previews", {
return $http.post(Configuration.installation.apiurl + "api/v1/scans/" + id + "/previews", {
image: screenshot
}).success(function(response) {
$log.info(response);
@ -610,6 +596,44 @@
}).call(this);
(function() {
var name;
name = 'fabscan.directives.onSizeChanged';
angular.module(name, []).directive('onSizeChanged', [
'$window', function($window) {
return {
restrict: 'A',
scope: {
onSizeChanged: '&'
},
link: function(scope, $element, attr) {
var cacheElementSize, element, onWindowResize;
element = $element[0];
cacheElementSize = function(scope, element) {
scope.cachedElementWidth = element.offsetWidth;
scope.cachedElementHeight = element.offsetHeight;
};
onWindowResize = function() {
var expression, isSizeChanged;
isSizeChanged = scope.cachedElementWidth !== element.offsetWidth || scope.cachedElementHeight !== element.offsetHeight;
if (isSizeChanged) {
expression = scope.onSizeChanged();
expression();
}
};
cacheElementSize(scope, element);
$window.addEventListener('resize', onWindowResize);
}
};
}
]);
}).call(this);
/*
Takes a string and makes it lowercase
Example of a 'common' filter that can be shared by all views
@ -741,28 +765,36 @@ Example of a 'common' filter that can be shared by all views
angular.module(name, []).factory(name, [
'$log', '$location', function($log, $location) {
var config, host, localDebug;
var config, host, http, localDebug, ws;
localDebug = $location.host() === 'localhost';
config = null;
host = $location.host();
$log.info(host);
http = 'http';
ws = 'ws';
console.log($location.protocol());
if ($location.protocol() === 'https') {
http = 'https';
ws = 'wss';
}
if (localDebug) {
config = {
installation: {
host: "fabscanpi.local",
websocketurl: 'ws://fabscanpi.local/websocket',
httpurl: 'http://fabscanpi.local:8080/',
newsurl: 'http://mariolukas.github.io/FabScanPi-Server/news/'
websocketurl: ws + '://fabscanpi.local/websocket',
httpurl: http + '://fabscanpi.local/',
newsurl: http + '://fabscanpi-server.readthedocs.io/en/latest/news/',
apiurl: http + '://fabscanpi.local/'
}
};
} else {
config = {
installation: {
host: host,
websocketurl: 'ws://' + host + '/websocket',
httpurl: 'http://' + host + ':8080/',
newsurl: 'http://mariolukas.github.io/FabScanPi-Server/news/'
websocketurl: ws + '://' + host + '/websocket',
httpurl: http + '://' + host + ':8080/',
newsurl: http + '://fabscanpi-server.readthedocs.io/en/latest/news/',
apiurl: http + '://' + host + '/'
}
};
}
@ -804,7 +836,8 @@ Example of a 'common' filter that can be shared by all views
UPDATE_SETTINGS: 'UPDATE_SETTINGS',
MESHING: 'MESHING',
UPGRADE_SERVER: 'UPGRADE_SERVER',
RESTART_SERVER: 'RESTART_SERVER'
RESTART_SERVER: 'RESTART_SERVER',
HARDWARE_TEST_FUNCTION: 'HARDWARE_TEST_FUNCTION'
};
return FSEnumService;
});
@ -1332,7 +1365,7 @@ Example of how to wrap a 3rd party library, allowing it to be injectable instead
name = "fabscan.controller.FSLoadingController";
angular.module(name, []).controller(name, [
'$log', '$scope', '$rootScope', 'fabscan.services.FSScanService', 'fabscan.services.FSEnumService', function($log, $scope, $rootScope, FSScanService, FSEnum) {
'$log', '$scope', '$rootScope', 'fabscan.services.FSScanService', 'fabscan.services.FSEnumService', 'common.services.Configuration', function($log, $scope, $rootScope, FSScanService, FSEnum, Configuration) {
$scope.loadPointCloud = function(pointcloud, id) {
$scope.setScanIsLoading(true);
$scope.setScanIsComplete(false);
@ -1379,7 +1412,17 @@ Example of how to wrap a 3rd party library, allowing it to be injectable instead
$scope.displayNews(false);
}), 30);
deferred = $q.defer();
return $scope.news = "No news available.";
$scope.news = "No news available.";
return $http({
method: 'GET',
url: configuration.installation.newsurl,
timeout: deferred.promise
}).success(function(data, status, headers, config) {
$scope.news = data;
return $timeout.cancel(timeoutPromise);
}).error(function(data, status, headers, config) {
return $scope.news = "Error retrieving news.";
});
}
]);
@ -1417,7 +1460,7 @@ Example of how to wrap a 3rd party library, allowing it to be injectable instead
return $scope.$apply();
};
startStream = function() {
$scope.streamUrl = Configuration.installation.httpurl + 'api/v1/streams/?type=textures';
$scope.streamUrl = Configuration.installation.apiurl + 'api/v1/streams/?type=textures';
$scope.showStream = true;
return $scope.$apply();
};
@ -1569,7 +1612,7 @@ Example of how to wrap a 3rd party library, allowing it to be injectable instead
$scope.loadFilters = function() {
var filter_promise;
filter_promise = $http.get(Configuration.installation.httpurl + 'api/v1/filters/');
filter_promise = $http.get(Configuration.installation.apiurl + 'api/v1/filters/');
return filter_promise.then(function(payload) {
$log.info(payload);
$scope.m_filters = payload.data.filters;
@ -1631,7 +1674,7 @@ Example of how to wrap a 3rd party library, allowing it to be injectable instead
$scope.displayNews(false);
if (!$scope.loadDialog) {
promise = $http.get(Configuration.installation.httpurl + 'api/v1/scans/');
promise = $http.get(Configuration.installation.apiurl + 'api/v1/scans/');
return promise.then(function(payload) {
$scope.scans = payload.data.scans;
$scope.scanListLoaded = true;
@ -1684,12 +1727,33 @@ Example of how to wrap a 3rd party library, allowing it to be injectable instead
name = "fabscan.controller.FSSettingsController";
angular.module(name, []).controller(name, [
'$log', '$scope', '$timeout', '$swipe', 'common.services.Configuration', 'fabscan.services.FSEnumService', 'fabscan.services.FSMessageHandlerService', 'fabscan.services.FSScanService', function($log, $scope, $timeout, $swipe, Configuration, FSEnumService, FSMessageHandlerService, FSScanService) {
var updateSettings;
'$log', '$scope', '$timeout', '$swipe', '$http', 'common.services.Configuration', 'fabscan.services.FSEnumService', 'fabscan.services.FSMessageHandlerService', 'fabscan.services.FSScanService', function($log, $scope, $timeout, $swipe, $http, Configuration, FSEnumService, FSMessageHandlerService, FSScanService) {
var devices_promise, updateSettings;
$scope.streamUrl = Configuration.installation.httpurl + 'api/v1/streams/?type=laser';
$scope.streamUrl = Configuration.installation.apiurl + 'api/v1/streams/?type=laser';
$scope.previewMode = "laser";
$scope.selectedTab = 'general';
devices_promise = $http.get(Configuration.installation.httpurl + 'api/v1/devices/');
devices_promise.then(function(payload) {
$log.info(payload);
return $scope.devices = payload.data;
});
$scope.sendDeviceCommand = function(device, f_name) {
var message;
message = {};
message = {
event: FSEnumService.events.COMMAND,
data: {
command: FSEnumService.commands.HARDWARE_TEST_FUNCTION,
device: {
name: device,
"function": f_name
}
}
};
return FSMessageHandlerService.sendData(message);
};
$scope.timeout = null;
updateSettings = function() {
var _settings;
@ -1723,14 +1787,32 @@ Example of how to wrap a 3rd party library, allowing it to be injectable instead
}
};
$scope.showCalibrationPreview = function() {
$scope.streamUrl = Configuration.installation.httpurl + 'api/v1/streams/?type=texture';
$scope.previewMode = "calibration";
return $scope.$apply();
$scope.streamUrl = Configuration.installation.apiurl + 'api/v1/streams/?type=texture';
return $scope.previewMode = "calibration";
};
$scope.showLaserPreview = function() {
$scope.streamUrl = Configuration.installation.httpurl + 'api/v1/streams/?type=laser';
$scope.previewMode = "laser";
return $scope.$apply();
$scope.streamUrl = Configuration.installation.apiurl + 'api/v1/streams/?type=laser';
return $scope.previewMode = "laser";
};
$scope.calibrationPatternSelected = function() {
if ($scope.settings.show_calibration_pattern) {
return true;
} else {
return false;
}
};
$scope.laserOverlaySelected = function() {
if ($scope.settings.show_laser_overlay) {
return true;
} else {
return false;
}
};
$scope.setCalibrationPattern = function() {
return updateSettings();
};
$scope.setLaserOverlay = function() {
return updateSettings();
};
$scope.setColor = function() {
return updateSettings();
@ -1856,7 +1938,7 @@ Example of how to wrap a 3rd party library, allowing it to be injectable instead
$scope.getScans = function() {
var scan_promise;
scan_promise = $http.get(Configuration.installation.httpurl + 'api/v1/scans/' + FSScanService.getScanId());
scan_promise = $http.get(Configuration.installation.apiurl + 'api/v1/scans/' + FSScanService.getScanId());
return scan_promise.then(function(payload) {
$log.debug(payload);
$scope.raw_scans = payload.data.raw_scans;
@ -1916,7 +1998,7 @@ Example of how to wrap a 3rd party library, allowing it to be injectable instead
var promise;
$scope.toggleShareDialog();
promise = $http["delete"](Configuration.installation.httpurl + 'api/v1/scans/' + FSScanService.getScanId() + '/files?filename=' + filename);
promise = $http["delete"](Configuration.installation.apiurl + 'api/v1/scans/' + FSScanService.getScanId() + '/files?filename=' + filename);
return promise.then(function(payload) {
$log.info(payload.data);
$scope.getScans();
@ -1935,7 +2017,7 @@ Example of how to wrap a 3rd party library, allowing it to be injectable instead
var promise;
$scope.toggleShareDialog();
promise = $http["delete"](Configuration.installation.httpurl + 'api/v1/scans/' + FSScanService.getScanId());
promise = $http["delete"](Configuration.installation.apiurl + 'api/v1/scans/' + FSScanService.getScanId());
return promise.then(function(payload) {
$log.info(payload.data);
toaster.info('Scan ' + FSScanService.getScanId() + ' deleted');

View file

@ -7,12 +7,135 @@ body, html {
font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;
position: fixed !important;
overflow: hidden
height: 100%;
}
* {
margin: 0
}
button:focus {outline:0;}
.control {
font-family: arial;
display: block;
position: relative;
padding-left: 30px;
margin-bottom: 5px;
padding-top: 3px;
cursor: pointer;
font-size: 16px;
}
.control input {
position: absolute;
z-index: -1;
opacity: 0;
}
.control_indicator {
position: absolute;
top: 2px;
left: 0;
height: 20px;
width: 20px;
background: #e6e6e6;
border: 0px solid #000000;
}
.control-radio .control_indicator {
border-radius: undefined%;
}
.control:hover input ~ .control_indicator,
.control input:focus ~ .control_indicator {
background: #cccccc;
}
.control input:checked ~ .control_indicator {
background: #838383;
}
.control:hover input:not([disabled]):checked ~ .control_indicator,
.control input:checked:focus ~ .control_indicator {
background: #0e6647d;
}
.control input:disabled ~ .control_indicator {
background: #e6e6e6;
opacity: 0.6;
pointer-events: none;
}
.control_indicator:after {
box-sizing: unset;
content: '';
position: absolute;
display: none;
}
.control input:checked ~ .control_indicator:after {
display: block;
}
.control-checkbox .control_indicator:after {
left: 8px;
top: 2px;
width: 3px;
height: 11px;
border: solid #ffffff;
border-width: 0 3px 3px 0;
transform: rotate(45deg);
}
.control-checkbox input:disabled ~ .control_indicator:after {
border-color: #7b7b7b;
}
.video-container {
/* width: 50%;*/
width:33.3em;
float: left;
bottom: 100px;
}
.video {
position: relative;
/*padding-bottom: 56.25%;*/
min-width: 30em;
min-height: 800px;
bottom:60px;
height: inherit !important;
overflow: hidden;
}
.video iframe{
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.side-div{
float: left;
width: 50%;
}
.wrapper {
width:100%;
display:flex;
background-color:#CCC;
}
.wrapper-top {
width:100%;
height:60px;
background-color:#000;
}
.wrapper-bottom {
width:100%;
height:40px;
background-color:#000;
clear: both
}
.slick-slider {
margin-bottom: 0em;
}
@ -268,6 +391,7 @@ a:active .icon {
bottom: 60px;
position: fixed;
left: 0px;
z-index:1000;
/*background-color:grey;*/
background-color: rgba(53, 53, 53, 0.5);
transition: height 0.3s;
@ -315,7 +439,10 @@ a:active .icon {
.settings-content {
height: 100%;
margin-left: 180px;
position: absolute;
left: 300px;
width: 100%;
/*margin-left: 180px;*/
}
.config-content {
@ -328,7 +455,7 @@ a:active .icon {
}
.settingsWindow.open {
height: 240px;
height: 400px;
bottom: 60px;
transition: height 0.3s;
border-top: 2px solid rgb(73, 73, 73);
@ -342,11 +469,35 @@ a:active .icon {
opacity: 0.75;
}
.fsButton {
background-color:transparent;
-moz-border-radius:31px;
-webkit-border-radius:31px;
border-radius:31px;
border:3px solid #dcdcdc;
display:inline-block;
cursor:pointer;
color:#ffffff;
font-family:Arial;
font-size:15px;
font-weight:bold;
padding:6px 24px;
text-decoration:none;
}
.fsButton:hover {
background-color:rgba(53, 53, 53, 0.4);
}
.fsButton:active {
position:relative;
top:1px;
}
.hide {
height: 150px;
}
.footer {
z-index:1000;
position: fixed;
bottom: 0;
width: 100%;
@ -403,6 +554,7 @@ html, body {
position: fixed;
bottom: 0;
width: 100%;
z-index:1000;
text-align: center;
margin-bottom: 1em;
border-top: 2px solid rgb(73, 73, 73);
@ -416,14 +568,59 @@ html, body {
overflow-y: auto;
}
.settings-preview {
/* position: absolute;
top: 100px;
z-index: 2;
margin-left:-160px;
left:50%;*/
position:absolute;
margin-left: auto;
margin-right: auto;
}
.settings-preview img {
height: 70%;
width: 70%;
opacity: 0.6;
border-radius: 70px;
/* -webkit-mask-box-image: -webkit-linear-gradient(left,transparent, transparent 15%, white 50%, white 50%, transparent 85%);*/
-webkit-mask-box-image: -webkit-radial-gradient(white, transparent 69%);
display: block;
margin: 0 auto;
top: 0;
bottom: 0;
left: 0;
right: 0;
position: absolute;
margin-top: 12%;
}
.texture-preview {
/* position: absolute;
top: 100px;
z-index: 2;
margin-left:-160px;
left:50%;*/
width: 50%;
position:absolute;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
bottom:59px;
}
.texture-preview img {
height: 70%;
width: 70%;
@ -483,7 +680,8 @@ html, body {
.tab-content {
background-color: rgba(53, 53, 53, 0.4);
height: 200px;
height: 100%;
/*height:100%;*/
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
@ -629,7 +827,7 @@ and (max-device-width: 450px) {
margin-left: 0px;
width: 100%;
float: left;
height: 100%;
height: 200px;
}
.preview-image {
@ -717,7 +915,7 @@ and (max-device-width: 480px) {
}
*/
.settingsWindow.open {
height: 100%;
/* height: 100%;*/
}
.optionsWindow.open {