pax_global_header00006660000000000000000000000064131615227500014514gustar00rootroot0000000000000052 comment=7cff7561a4f74ce9a3f6b34472f59082ff25c2bf pytrainer-1.11.0/000077500000000000000000000000001316152275000136115ustar00rootroot00000000000000pytrainer-1.11.0/.gitignore000066400000000000000000000000351316152275000155770ustar00rootroot00000000000000*.pyc /messages.pot build *~ pytrainer-1.11.0/.travis.yml000066400000000000000000000005111316152275000157170ustar00rootroot00000000000000sudo: required language: python env: - TZ=Europe/Kaliningrad before_install: - sudo apt-get install python-gtk2 python-glade2 python-lxml python-matplotlib python: - "2.7" script: "python setup.py test" virtualenv: system_site_packages: true notifications: irc: channels: "ircs://chat.freenode.net:7000/#pytrainer" pytrainer-1.11.0/CHANGES000066400000000000000000000647301316152275000146160ustar00rootroot00000000000000We have migrated to GitHub, for more details about changelog please see git log documentation (http://git-scm.com/docs/git-log). One simple approach: git log --oneline --stat --decorate .. - pytrainer changes for 1.11.0: - Known issues: Gtk outputs warnings about extra properties when loading the main window - Improvements: 1a237adba0fb, 640ef4e55da8, 30fdfd9e83eb Performance improvements fcc8f3361d4f FIT conversion updated to work with Perl 5.22 92d6a33aed16 Setuptools is now used for installation where available 4bb91436522b Start screen can now be configured (ticket #12) 086a0dd81549 The map functionality is now optional (and python-webkit is no longer required) - Bugs fixed: 9d1c670ea1ac Logging now works as configured 10b04c8b38e1 Sports list stays up to date 0a23585c2d25 Prior usage is included in equipment usage stats acbe61ddbf16 Strings are now quoted correctly with sqlite 8ca54a97a9f6 Fix pace unit conversion f52235a9d921 Missing import in gpxplus c2f41e97022f Check that Activity.gpx exists before using it - Internals: a6f80a252a1d All tests are now found and executed d82fbeee3a06 Use DDBB with an in-memory database when testing Equipment b284fdffee3a Use DDBB with an in-memory database when testing Sport 3ade6e1dd822 Date methods converted into simple utility functions 80805b326cd0 Test cases added for date utility functions 321206a797ea Environment converted into a singleton 96e471f38958 Profile converted into a singleton 2573955d9c0c Tests added for the Athlete class 29db339f41fc Tests added for the Waypoint class bfacd6d55598 Tests added for unit conversion f9a93daffc28, 37982f5e214b Heavily refactor the Activity class 4c84abf522ba Tests added for the Activity class 5eab5b0a38fa unitsconversor was fully replaced with UC and removed 1ac7db0049a1 Default log level was changed to warning 005accf46b2f Stop using glade for the popup menu 0303a92fb0ef Use the locale module instead of the gtk.glade helper 4601b5f1c703 Migrated from gtk.glade to gtk.Builder - pytrainer changes for 1.10.0: - Known issues Can't maximize main window. Issue related to graph subtab in register tab - SF tickets #113 #124 - New features: Support for Garmin FIT format via file import (ticket #5) 979b7c9 Adding test case for workout summary - ticket #5 8e6f8d2 Removed print entry 9a6245e Amended recursive addition issue when indenting - ticket #5 0cb21ca Adding basic test case for TCXv2 file import - ticket #5 d4d1b2b Code refactoring - ticket #5 a0da00d Adding test case for Garmin FIT file import - ticket #5 d63ce44 Renaming directory to avoid conflict with reserved 'import' word - ticket #5 4581b67 Added perl dependency for garmin-fit plugin - ticket #5 a7eeae2 Updated version to 0.11 - ticket #5 de9a78b Updating ES localization 577b0de Including garmin-fit plugin also with external perl files needed to translate from FIT to TCXv2 - ticket #5 d17913f Plugins are executed from 'Import' tabs 3c0e645 File imports only managed via 'Import' menu. Need to migrate import processes which read data directly from GPS device 9444f5b Updating ES localization b8da65c Prevent importing already present activities 222b89f Removed commented lines 380a940 Removed commented lines. Amended minor localization issues 6176111 First step to import Garmin FIT files. Quick parse for validation previous to actual import 43a0e56 Updating ES locale cb936d4 Including more messages for localization. Updating status bar text when there is an error with a file c58fb0a Extension to upload activities to Strava - credits to spaceyjase (971be41) aa7fde6 Added gpx2garmin extension - thanks to spaceyjase (a139757) d8f864f New "pace" column in ranking tab (thanks to cz8s) - Improvements: Localizations updated, added update_localizations script to automate process under utils directory 037d91d Updated FR localization. Thanks to Christian Perrier 09e40df Updating DE localization. Thanks to Wilfried f174af1 Amended filename in update_localizations script for mo files. Updated files dc21fa7 Removing mo binary files from repository 9780a89 Updating localizations for 1.10.0 version. Includes script to automate process under utils directory 286cba9 Updating GL localization - thanks to Aníbal 8689009 Updating ES localization c5ccfe9 Retrieving all record related data from DB when exporting to csv - #11 cdc639d Amended path issue when testing gpx files ba37e2a Setting current date for new athlete log entry - on behalf of Andreas Mair 0f5c84a Defining version number in one place for the whole application d2a0153 Looking for tag instead of non intuitive list indexes when using garmintools import 3e785c8 Finally showing product description from garmin_get_info d256862 Added tests to check lap parsing with samples ef474c7 Accept date range object for actualize_weekview() 56c038d Accept date range object for record.getrecordPeriod() 4d10679 Accept date object for record.newRecord() 4428a3e Accept date object for record.getRecordDayList() 4af8a35 Accept date object for record.getrecordList() 81ad5f5 Accept date object for date.getNameMonth() 1a5af41 Return date object from date.getDate() 9ab01ab Use date range for week/month/year interval calculations () 4bca25e Add date range utility class 7f4578a Add pytrainer.util and pytrainer.core packages to setup script. 25145e6 Move pytrainer.lib.color module to pytrainer.util package e9e6674 Move sport module to pytrainer.core package 7c7ff55 Move equipment module to pytrainer.core package 8273a36 Create pytrainer.core package - Bugs fixed: dc795e9 Texts and units which can change when switching unit system are localized separately - ticket #16 46a1775 Fix year tab text labels/units (thanks to spaceyjase) d4d988f Fixed unhandled exception by removing the Osmarender layer 41df1d8 Amended wrong value to average speed in totals graph. Thnx to lifo2 - ticket:173 72a84c8 Better duration estimation for activities with no laps and several breaks - ticket:167 d239c37 Matching xml parse with amended stylesheets data structure keeping backward compatibility ac5261d Amended stylesheets to match GPXDATA schema 1dcf5fe Showing proper figures in graph title according to units. Thnx Jason for the hint - Internal stuff: 2886ac4 (HEAD, pytrainer-git/master, master) Updated man file bef3116 Getting closer to release: updated version 83d9e50 Updated pytrainer project url f314697 Removed link to SourceForge and amended 'imports' directory name 5c25518 Updated links of some doc pages migrated to GitHub wiki 797b3af Update version to "1.10.0" a6e7c49 Ignore generated artifacts 9fd8b0c Adding a description in name section. Renaming man file. No need for README file any more e636650 Appending development suffix to version number ############################################################ - pytrainer changes for 1.9.1: * Known issues - Can't maximize main window. Issue related to graph subtab in register tab - tickets #113 #124 * Fixes - Corrected german localization (thanks to Andreas) - [938] - Amended typo in translator credits - [937] - Coloring graph not working when selecting speed as reference - #154 [936] - Added support for sqlalchemy-migrate 0.5.4 - #153 [935] - pytrainer changes for 1.9.0: * Known issues - Can't maximize main window. Issue related to graph subtab in register tab - tickets #113 #124 * New functionality or improvement - Updated DE localization. Thanks to Erik Pfannenstein from Debian DE group and Andreas Mair - [923] [927] - Added portuguese localization (thanks to Pedro Ribeiro) - [896] - Option added in localization script (utils/translator.sh) to generate only .pot file - [888 - 892] - Galician localization (thanks to Kaptan) - [885 - 887] [893] - Manpage for pytrainer - #125 [872] [874] - Create sport service - #138 [838] [840 - 845] [850] [850 - 856] [875] [880] - Provide means to run all unit tests - #139 [837] - Discrete version migration - #132 [815 - 836] [839] [864] [865] [899 - 906] [911] - Totals tab - #60 [766] [800] [801] [802] [803] - Display projected times in record view, including ranking - #116 [782] [785] [811] - Ascent and descent figures shown in all views. Added time spent moving and paused in record view (thanks to Friso) - #114 [781] - Assign graph color to sports - #111 [780] - Display laps information on record summary page - #109 #122 [768 - 772] [775] [777] [778] [788] [812] [813] - Coloring Google Maps path by speed/pace - thanks to Jonathan - #107 [765] - Added swedish localization (thanks to Per) - #98 [756 - 760] - Added startup option for choosing console or file logging. When "console" is chosen all logging messsages are sent to stdout instead of a log file. [755] * Fixes - Syncing calculations of distance, time, speed and pace. Normalized pace format - #71 #152 [916] [918 - 919] [922] [924] [928] - pytrainer quits when exporting activities in csv format [912] - Importing TCXv2 files failed - [907 - 909] - Date value was not saved in "Athlete" tab - #149 [898] - Fixed encoding issue that prevented some days of the week and associated information to be shown in stacked bars graph under week tab [897] - Cannot edit record created from GPX import with null sport reference - #147 [881] - pytrainer crashes when closing edit record dialog - #146 [879] - Added zero padding to overcome lap order issue - #145 [878] - Updated french localization - thanks to Vincent, Pierr [876] [895] - Heartrate figures from profile are retrieved independently so only those which fail are set to default value [873] - Active/Rest times are not calculated for activities with only one lap - [811] - Activity's data (equipment and title) missing when importing activity from file - #105 #137 [866 - 868] - Wrong duration calculation when breaks are present - #103 [858 - 862] - GUI problems when resizing - #113 [857] [877] [882] - GPX file import fails - #141 [849] - Enabling localization for some labels - #99 [846] [847] - Broken MySQL support - #130 [810] [817] [818] - Moving from GtkMozEmbed to WebKit - thanks to Christian - #131 [809] - Support US units and display units in analytics view - [808] - Start time can be changed in manually entered activities - #127 [807] - Sort records in record tree view by time by default - #128 [806] - Graphical improvements - [795] [796] [797] [798] [799] [805] - Improved OSM performance through caching and also anonymize sensitive date before upload - [790] [791] [792] - Failed to build stacked bars graphic in week, month and year tabs - #123 [789] - Changed the way OS is checked to allow pytrainer run on other POSIX in addition to GNU/LINUX - thanks to Christian - #120 [784] - Renaming danish suffix in po file to avoid confusion - #119 [783] - Try using Google Maps Elevation API if all else fails - #102 [779] - Updated ES localization [773] [774] [776] [804] [848] [863] [883] - Better management of wrong/corrupted data - #118 [767] [786] [787] - [793] [794] - Elevation correction extension not handling properly errors #102 [764] - Equipment management fixes - #95 [763] #96 [762] - Distance data is retrieved from laps if present, calculated from trackpoints otherwise - #101 [761] - Remove non iso-8859-1 characters [754] - Fix so only once instance of preferences dialog can be open at a time - #74 [753] - pytrainer changes for 1.8.0: * New functionality - Equipment management (thx to Nathan) [571] [572] [573] [598] [678] [679] [680] [685] [698] [699] [707] [708] [711] [717] [718] #12 - OpenStreetMap added as route map viewer (user selectable) - thanks to Druzee [578] [585] [590] - Anonymous data for OSM, cancel button (thx to Druzee, Arnd) [608] [611] [626] - Changes to graphing to allow user to change limits, color, line width etc [563] [567] [579] [599] - Remember size of main screen [581] - Function to merge tracks (work in progress) [597] - New Activity and ActivityPool classes to hold all info about an activity [582] [583] [584] [587] [589] [591] [677] [694] - Management of athlete data [605] [609] [649] [651] [653] [655] [656] [665] [668] [731] #13 - New graphic approach [616] [617] [622] [624] [628] [638] [639] [640] [642] [644] [646] [648] [674] [675] [721] [726] [727] [730] [733] - Added support for Nokia exported GPX files [673] - Added support for new formats (csv, delimited file) in unified import [688] [689] [690] [692] [693] [695] [697] [701] * Fixes - Variables and configuration refactored to be 'global' (reused and not re-instantiated by each class) [561] [562] [564] [565] [566] [568] #28 - Config file accepting non ascii characters [574] [575] [576] - Config file handling fixed to not fail with empty or missing file [586] #48 - Fix list view to update after edit, delete, import. Added filters and improvements (tnx Arnd) [569] [650] [652] [658] [661] [663] [664] [735] [742] [745] [746] - Localization updates (thanks to Pierre, David) [570] [588] [595] [715] [737] [744] [747] - Fix wordpress extension to work with newer wordpress codebase and support US measurement [577] [601] [602] #45 #51 - Update plugins to write UTF8 not ASCII GPX files [580] #47 - Fix googlemaps lap data display [592] [632] [633] - Fix calories display in heartrate tab [593] - Fix html in map generation (thanks to Druzee) [594] - Change default graph colors [596] - Improve handling of US units [600] [669] [672] [683] [687] [696] [700] [702] [703] [704] [705] [710] [738] [739] - Fix bug in plugins where ESC during file open dialog causes error [603] - Fix to garmintools_full plugin to make progress bar work (thanks to Druzee) [604] - Avoid exiting when parsing problem is found, entry skipped [607] # - Activites without GPX data don't break application [610] [615] - Improvements (show and calculation) to pace and elevation as suggested by Arnd [612] [618] [619] [623] [627] [741] - Better troubleshooting for graphics issues and minor fixes [625] [629] [636] - Fixes to csv export (thx Arnd) [630] - Fixes to startup script to better handling different environments [631] [637] [713] [714] - Updates to wordpress extension - removed separate googlemaps [634] - Allowing zero calories entries [641] - Fixes to edit record [643] [647] - Fixing confusion with dates (start day of the week, week number) [654] [655] [657] [670] [750] #57 - Fix for GPX files with no lap info [660] - Correction to date handling to work for mysql and sqlite [667] - Improving logging output [671] [748] [749] - Fix for HR percent graph so does not error in hr is None - thanks to Arnd [676] - Bug fixes for sports filtering from Patrick [681] - Updates for heartrate pie chart from Patrick [682] - Fixes in lap generation (divide by zero, empty laps) - thanks to Arnd [684] [686] - Fixes for record filtering from Patrick [691] - Tolerate non-unicode strings returned from DB for better MySQL support [706] - Add program argument for specifying config directory [709] #67 - Better handling of floats and division. Thx to Martin [712] - Retrieving a real list with DB tables, comparison was failing [716] - Remove redundant Port option in preferences [719] #80 - Fix to display blank sport properties correctly (not as None) [720] #78 - Fix mysql code to match changes to sqlite tablelist handling [722] - Stop preferences sport list edit button disabling dialog buttons if no sport is selected [723] #75 - Fix to stop crash on editing record with empty distance [724] #73 - Update record summary after edit [725] #79 - Fix sport filtering to work with non consecutive sport_ids [728] - Fix summary screens to update correctly with record add and deletes [729] - Make pace read only [732] - Display heartrate as integer in day, week, month and year views [734] - Update DB check to ensure time == duration [736] - Updating credits [740] [743] - pytrainer changes for 1.7.2: * Lap DB table created and code changed to populate and use the table [507] [508] [509] * Moved some global variables to class variables in main.py [513] * Google Earth plugin modified to work with new plugin architecture [515] * Waypoint editor modified to use handle_title_changed() call back instead of SOAP calls (thanks to David Fraser) and a few bugs fixed [516] [524] [543] * Firefox removed as a dependency [518] * Shebang tidied to be compatible with all python versions [520] * Extension code refactored to run extensions as internal classes [527] * Webservice / SOAP code removed [527] [531] * Incomplete webpublish extension removed from svn [528] * Upload to Openstreetmap extension added [536], [540] * pytrainer startup script modified to work with different install locations [532] [533] * Misc fixes and patches to pytrainer (thanks to David Fraser) [524] [530] [535] * Add support for with command for python versions <2.6 [541] * Removed bug that caused errors for activities with no GPX file [542] * Localisation updates [539] * New tab in preferences displays and allows changes to be made to pytrainer startup options [544] [545] [546] * Move individual screens into separate glade files [547] * Full screen map view reinstated [548] * Removed DB field order bug [549] * Removed fake error when importing entries [550] * Minor fixes to graph display options [551] * Minor cosmetic changes [552] [553] [554] * Added check for early detection of empty local configuration file [555] * EXPERIMENTAL Unified Import GUI modifications (disabled by default, enabled on startup with --testimport) [526] - file import supports multiple files at once [510] [511] - option to have file import window automatically start with a file selection dialog [519] - activities can be edited before import [514] [517] [521] [522] [534] [537] [538] - kml file import support [523] [525] - plugins tab added - provides alternative way of viewing and running import plugins [512] - device import NOT functional - pytrainer changes for 1.7.1: * New import plugin - Garmintools - svn [430], [431], [436], [452], [453], [459], [460], [461], [463], [464], [486], [487], [488] - both file (dump file) and device import implemented - smart import from device to cater for different start times compared to GPSBabel (to reduce duplicated activities) * Move to Google maps API version 3 - svn [477] * Add lap functionality - svn [433], [447], [448], [451], [454], [455] - display individual laps under activity on treeview - visually display lap duration on record graphs (user selectable) - display lap markers on route map * Improve check functionality - svn [437], [438], [439], [475], [478], [479], [480], [482] - Can be initiated by command line option --check - Will be initiated if DB version in code is newer than user's DB version - DB migration checks refactored and improved * Timezone support - svn [434], [440], [442], [483] - DB updated with new field date_time_local - field populated on import (or when DB check is run) - field used in preference to UTC if present for display * Cadence / RPM support and graph added (tcx v2 file import only) - svn [432] * Improved install process and remove unneeded files - svn [445], [446], [462], [467], [472], [473] * Bug fix to TCX v2 to cater for multiple activities per file - svn [435] * Bug fix for calorie calculation - svn [441], [474] * Bug fix for migration/new install error bug #2924209 - svn [456] * Bug fix for GPX import without elevation data - svn [490] * Bug fix to prevent adding empty entries - svn [496], [498], [499] * Updated localizations (es, fr) - svn [494], [495], [497] * Separate some GUI elements into separate files to ease development - svn [443], [457], [465] * EXPERIMENTAL Unified Import GUI begun (for testing/feedback only) - svn [458], [466], [468], [469], [470], [471], [476], [481], [489] - disabled by default - enabled on startup with --testimport - file import functional - device import NOT functional - pytrainer changes for 1.7.0: Updated Spanish translation (svn rev 420,423,424) Updated French translation (svn rev 421) Migration to lxml for better performance (svn rev 412,413,414) Start of rework for Google Map rendering - experimental!, test with --gmaps3 at startup (svn 411,415) Modified on_sportlist_changed event to improve performance (svn rev 409) Fix for minor bug in translation scripts (svn rev 402) Fix for bug #2811470 - clickable link for further details on MET (links to wikipedia) (svn rev 391) Fix for bug #2089342 auto refresh after import, edit and delete of records (svn rev 390,425) Refactoring database and config file sanity checks (triggered with --check at startup) (svn rev 389,392,396,401) Added weekly view (svn rev 388,393,394,395,398,403-410,426) Fix for multiple graphs view (svn rev 386,387) Better error handling preventing pytrainer to crash (svn rev 364,369) Support for plugin validation (triggered with --valid at startup)(svn rev 361,363,371) Import TCXv2 files (svn rev 351,355,356) Improving import from TCXv1 format (svn rev 354,371,375,376) Several improvements in plugins handling (svn rev 350,353,360,378,422) Import GPX files (svn rev 349) - pytrainer tasks for 1.6.0.9: Added dynamic loading and unloading of plugin menu items (svn rev 344) Removal of decommissioned plugin (garmin301) and addition of new ones (garmingpx). Update of project data (version and url) (svn rev 343) Adding calories support suggested by JB (svn rev 342) Maximum is misspelled Maximun, see http://bugs.debian.org/537723 (svn 341) Fixed some hardcoded stuff that prevents pytrainer to copy entries to ~/.pytrainer/gpx (thanks to JB) (svn 340) Major improvements in graphs (thanks to Fiz) (svn revs 339, 336, 332, 331) Updated german translation - bug ID: 2811507 (thanks to Noèl) (svn revs 338, 333) Minor project and license information updated (svn revs 337, 335, 334, 329) - pytrainer tasks for 1.6.0.8: Rotating log file support added (rev 322, http://sourceforge.net/tracker/?func=detail&aid=2717142&group_id=213157&atid=1024595) Translations reviewed and added script to facilitate them (rev 319-321,323) Several improvements to Wordpress extension (rev 315,317,326) Changed potential problems when dealing with date objects using MySQL as DB (rev 311-314) Removing redundant calls improving graphical performance (rev 310, linked to http://sourceforge.net/tracker/?func=detail&aid=2717135&group_id=213157&atid=1024592, not yet fully fixed) Optimizing xml files parsing when retrieving data from them (rev 309) - pytrainer tasks for 1.6.0.7: Removing pytrainer gui minimal window size (svn rev 304) Ordered shutdown of logging stuff (svn rev 303) HR and elevation graphs included when exporting to wordpress (svn rev 302) Removal of maps directory due to license issue: https://sourceforge.net/mailarchive/message.php?msg_name=1237752714.4330.15.camel%40thinker.domain.lan (svn rev 300) Removal of opensuse_mozpytrainer.sh launch script as it is included in (renamed) pytrainer.sh. Deleted README.txt file to avoid confusion (svn rev 298) Updated INSTALL file with current package versions (svn rev 297) Fixed Google Maps integration (svn rev 296) Updated garmin-hr config file with correct usb port value (svn rev 294) Fixed bug where track record was supposed to be updated in database. Type cast was missing (svn rev 293) Bug #2100647 - Quick entry doesn't work if no gpx file - Fixed (svn rev. 287) FR #2126411 - Package python-sqlite2 not needed anymore: http://www.python.org/doc/2.5.2/lib/module-sqlite3.html (svn rev. 286) - pytrainer tasks for 1.6.0.6: Close button in "About" dialog now works. Migrating from Glade to GTKBuilder Fixed some properties in pytrainer.desktop (ID#2126616) Added COPYING file with GPLv2 (ID#2126413) Removal of garmin301 plugin Fixed some issues with MySql tables creation (email from Jonas Liljenfeldt) - pytrainer tasks for 1.6.0.5: mozpytrainer launch script with log level support -> DONE (24.08.2008) MET and extra weight values swapped when adding a new sport -> DONE (22.08.2008) pytrainer crashes when adding an activity which sport is not yet in DB -> DONE (31.08.2008) Should be enough to check timestamps when adding new activities -> DONE (31.08.2008) Correct initialization of pace and maxpace values -> DONE (31.08.2008) - pytrainer tasks for 1.6.0.4: Added support for date_time_utc field when importing new tracks via file upload pytrainer/profile.py: fixed logging issue when removing sport from database - pytrainer tasks for 1.6.0.3: Complete review of migration scripts. Special attention to ~/.pytrainer/conf.xml file -> DONE (31.07.2008) Number output always with two figures to avoid confusion -> DONE (02.08.2008) - pytrainer tasks for 1.6.0.2: Check paces in DB (maxspeed<->maxpace | average<->pace) -> DONE (19.07.2008) Error when updating records because of new date_time_utc field in DB -> FIXED (20.07.2008) - pytrainer tasks for 1.6.0.1: Adjust migration scripts Sports saved in ddbb (new column in table sports) -> id_sports in table sports (nothing to do) Date_time saved for each record (new column in table records) -> main.addDateTimeUTC (DONE - 13.07.2008) ALTER TABLE records ADD date_time_utc varchar2(20); update records set date_time_utc="2008-07-11T10:21:31Z" where id_record='158'; -> automate process reading gpx files at the beginning Hardcoded sport whem importing record.shortFromLocal (retrieves sport from local files) -> retrieve from DB (shortFromLocalDB) DONE - 13.07.2008 record.summaryFromGPX (retrieves what will be saved in DB) DONE (12.07.2008) - Future releases Loading of changed preferences seems weird Incorrect timezone when importing tracks -> check gpx._getValues garmintools integration (laps and calories support, real sport and complete history retrieved from gps device, overall performance improvement) Logging improvements XML output with cElementTree Tracks regularization Review visual output Added from Pierre's email: - Equipment management : Ability to store a list of equipment (running shoes, ...) and associate it (or not) with records. It is to follow how many km have been done with some shoes for example. - Graph improvement: Many things here... Curve smoothing option. Ability to zoom in and out. Select a portion of track and extract some simple statistics information (avg speed, hr, max hr, Total Ascent, ...) pytrainer-1.11.0/COPYING000066400000000000000000000431021316152275000146440ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. pytrainer-1.11.0/INSTALL000066400000000000000000000041221316152275000146410ustar00rootroot00000000000000pytrainer basic installation =========================== These are generic installation instructions to use with *.tar.gz files 1.- Dependency Overview Here you are dependencies for pytrainer. Of course you must have a working environment with proper shell configuration and typical GNU tools to uncompress (gunzip) and untar (tar) files. 1.1.- Packages python >= 2.5 (python >= 3.0 not checked on 2011/11!) distutils >= 2.5 (python-devel, to run installation from tarball) dateutil >= 1.5 (python-dateutil) GTK+ >= 2.6.0 PyGTK >= 2.6.0 libglade >= 2.6.4 (libglade, pygtk2-libglade) pywebkitgtk >= 1.1.8 (see ticket #131) matplotlib >= 0.99.x (python-matplotlib) python-lxml >= 2.2 libxml2 >= 2.7.8 libxml2-python >= 2.7.8 libxslt >= 1.1.26 libxslt-python >= 1.1.26 sqlite >= 3.2.0 (sqlite is preferred to mysql as database, MySQL-python has been reported to be installed if so) sqlalchemy >= 0.6.4 sqlalchemy-migrate >= 0.5.4 zenity >= 2.30 - Only needed if correspondent plugin or extension is enabled: gpsbabel == 1.3.5 ("GoogleEarth" and "Garmin via GPSBabel 1.3.5" aka "garmin_hr") garmintools >= 0.10 ("Import from Garmin GPS device (via garmintools)" aka "garmintools_full" plugin) wordpresslib (already distributed within pytrainer tarball, wordpress extension) httplib2 >= 0.6.0 (wordpress extension) SOAPpy >= 0.11.6 (dotclear extension) GDAL (Elevation correction, via "gdal-python" or "python-gdal") perl (garmin-fit plugin, tested with perl v5.16.2 on Fedora 18, see ticket #5) 2.- Installation process Copy tarball file to a location where you have write and execution rights (e.g. /tmp or your $HOME directory). Make sure executables are under your $PATH. $ tar -xzf pytrainer-X.Y.Z.tar.gz $ cd pytrainer-X.Y.Z $ sudo python setup.py install $ pytrainer -i For more information about the process, please check http://docs.python.org/distutils/setupscript.html 3.- USB access pytrainer can use gpsbabel (http://www.gpsbabel.org) to retrieve information from Garmin devices. There are some problems regarding driver to access usb ports, please take a look at http://www.gpsbabel.org/os/Linux_Hotplug.html pytrainer-1.11.0/PLUGINS.README000066400000000000000000000017601316152275000156150ustar00rootroot00000000000000Information on creating Plugins =========================================== Plugins are created by: 1) Making a directory in /plugins/ 2) Creating a python class in a file in your directory - class must have run(self) function - run(self) returns tuple of GPX files to import 3) Creating a conf.xml configuration file in your directory with at least the following information: Where name: is the name of your plugin description: is the description plugincode: is the name of the class in your plugin file pluginbutton: is the label that the menu option will have once your plugin is enabled executable: is the file that the python class in in (without the .py extension) pytrainer-1.11.0/README.md000066400000000000000000000031621316152275000150720ustar00rootroot00000000000000pytrainer - Free your sports ================================================== Source Repository Structure --------------------------- * **bin** pytrainer executable *python script* files * **extensions** addons to extend pytrainer basic functionality * **glade** user interface design * **imports** files to parse different source formats * **locale** localization files * **man** source manpage * **plugins** files to retrieve data from different sources * **pytrainer** core files * **schemas** schemas to support correct xml parsing * **utils** localization shell script Installation from source tarball ----------------- Copy tarball file to a location where you have write and execution rights (e.g. `/tmp` or your `$HOME` directory). Make sure executables are under your `$PATH`. `$ tar -xzf pytrainer-X.Y.Z.tar.gz` `$ cd pytrainer-X.Y.Z` `$ sudo python setup.py install` `$ pytrainer -i` For more information about the process, please check [Distutils documentation] (http://docs.python.org/distutils/setupscript.html) Further Resources ----------------- * FAQ [https://github.com/pytrainer/pytrainer/wiki/FAQ](https://github.com/pytrainer/pytrainer/wiki/FAQ) * Distribution list: pytrainer-devel@lists.sourceforge.net * Development guide: [https://github.com/pytrainer/pytrainer/wiki/Development-guide](https://github.com/pytrainer/pytrainer/wiki/Development-guide) * Localization guide: [https://github.com/pytrainer/pytrainer/wiki/Localization-guide](https://github.com/pytrainer/pytrainer/wiki/Localization-guide) * Report an Issue: [https://github.com/pytrainer/pytrainer/issues](https://github.com/pytrainer/pytrainer/issues) pytrainer-1.11.0/bin/000077500000000000000000000000001316152275000143615ustar00rootroot00000000000000pytrainer-1.11.0/bin/pytrainer000077500000000000000000000061231316152275000163260ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: iso-8859-1 -*- #Copyright (C) Fiz Vazquez vud1@sindominio.net #This program is free software; you can redistribute it and/or #modify it under the terms of the GNU General Public License #as published by the Free Software Foundation; either version 2 #of the License, or (at your option) any later version. #This program is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #GNU General Public License for more details. #You should have received a copy of the GNU General Public License #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import sys import os import glob import commands import platform def _max(one, two): '''Function to determine the max of two versions of format /xx/xxx/????-1.2.3 ''' if one is None: return two elif two is None: return one try: one_v = os.path.basename(one).split('-')[1] two_v = os.path.basename(two).split('-')[1] except IndexError: #Got format that doesnt fit what we expect #Do simple comparison if os.path.basename(one) > os.path.basename(two): return one else: return two one_v_nos = one_v.split('.') two_v_nos = two_v.split('.') for index, no in enumerate(one_v_nos): if index >= len(two_v_nos): return one elif no > two_v_nos[index]: return one elif no < two_v_nos[index]: return two else: pass if len(one_v_nos) >= len(two_v_nos): return one return two bin_path = os.path.realpath(os.path.dirname(__file__)) # directory that the pytrainer script executes from e.g. /usr/bin or /usr/local/bin base_path = os.path.dirname(bin_path) #Get the version of the running python interpreter ver = platform.python_version_tuple() if (os.path.exists(base_path + "/INSTALL") and os.path.exists(base_path + "/setup.py") and os.path.exists(base_path + "/pytrainer/main.py") and os.path.exists(base_path + "/locale")): print("running pytrainer from source path") data_path = base_path + "/" site_path = base_path gettext_path = base_path + "/locale" else: print("running pytrainer from egg installation") parts = os.path.split(base_path) if parts[1] == 'EGG-INFO': base_path = parts[0] data_path = base_path + "/share/pytrainer/" site_path = "%s/lib/python%s.%s/site-packages" % (base_path, ver[0], ver[1]) gettext_path = base_path + "/share/locale" print "data_path: " + data_path print "gettext_path: " + gettext_path print "site_path: " + site_path #ensure pytrainer directory is included in import path sys.path.insert(0, site_path) def main(): import pytrainer.lib.localization pytrainer.lib.localization.initialize_gettext(gettext_path) from pytrainer.main import pyTrainer pytrainer = pyTrainer(None, data_path) if __name__ == "__main__": main() pytrainer-1.11.0/extensions/000077500000000000000000000000001316152275000160105ustar00rootroot00000000000000pytrainer-1.11.0/extensions/dotclear/000077500000000000000000000000001316152275000176055ustar00rootroot00000000000000pytrainer-1.11.0/extensions/dotclear/README.txt000066400000000000000000000131641316152275000213100ustar00rootroot00000000000000 Dotclear pytrainer extension =============================== This extension allows you to post your sport record directly into your dotclear weblog. It work only on a Dotclear 2.0 blog It's a small program to learn python, it's not a revolution but is work First section in english (for all over the world) Second section the same but in french (because dotclear is primary use in France) CONFIG OPTIONS ============== You have to fill in all the fields. xmlrpcserver: to send a new post on your blog, you have to activate the xml/rpc server. when this service is activated dotclear give you a xml/rpc adress ( like http://yourblog.be/index.php/xmlrpc/default ) bloguser: Your user id for your blog blogpass : Your password that you use on connect you to your blog blogid: dotclear 2.0 can accept somes blogs with one install, you have to define the blog id (by default it's 1 ) blogcategory: It's the category's number where this extension post your record on youR blog USAGE ===== Simply submit the dotclear extension preferences form and then go to the record tab and press "post it in dotclear". ON YOUR BLOG ============ I have created a category only for my pytrainer record. I have excluded this category on my homepage and took a section on the sidebard for show only this category To exclude the category ------------------------ You must (HAVE TO ENCORE ET TOUJOURS) edit the home.html file on your template directory. And change the to the name of your category is the dotclear name for your categories (without accents and spécial char) To only show the record category on your sidebar -------------------------------------------------

{{tpl:EntryTitle encode_html="1"}}

{{tpl:EntryExcerpt}}
{{tpl:EntryContent}}
you have to replace training by the category's name THANKS ====== Fiz for pytrainer, and is help for every stupid question that i have sent. Gnomefiles for the promotion of somes app's My stupid stage, where if i wanT take something i must have do wath i want IN FRENCH Dotclear pytrainer extension =============================== Cette extension vous permet d'envoyer vos scores de pytrainer vers votre blog dotclear 2.0 Options de configuration ======================== Vous devez remplir tous les champs xmlrpcserver: pour envoyer un nouveau post sur votre blog, vous devez activer l'interface xml/rpc de votre blog dotclear 2.0. Pour cela rendez-vous sur la page Parametres du blog, il y a une section xml/rpc à activer. Après activation de l'interface, dotclear vous indiquerea une adresse ( comme http://votre blog.be/index.php/xmlrpc/default ) bloguser: Votre identifiant de connections a votre blog, votre nom d'utilisateur quoi blogpass : Le mot de passe que vous utilisez pour vous connecter a votre blog (n'ayez crainte personne, ne le verra) blogid: Dotclear 2.0 peut faire plusieurs blogs différents avec une seule installation (le multiblog que ça s'appelle) pour que cette extension sache où envoyer votre post, il faut lui dire vers quel blog (par défaut c'est 1 ) blogcategory: Chaque catégorie crée dans votre blog à un nº (par ordre de création, donc général a le nº 1), il s'agit de la catégorie dans laquelle cette extension enverra les données de votre score. Pour trouver le nº de la catégorie vous cliquez sur Catégories dans la colonne de gauche de l'interface d'administration de votre blog, vous cliquez sur la catégorie et dans la barre d'adresse de votre navigateur vous trouverez un truc comme admin/category.php?id=5 et bien ici le nº de la catégorie est 5 UTILISATION =========== Dans la fenêtre qui donne les détails sur un record, vous devez avoir en bas à droite un petit bouton "Post in Dotclear" et hop cette extension grâce a l'aide de pytrainer enverra certaines informations de votre score sur votre blog SUR VOTRE BLOG ============ J'ai créé une catégorie exprès pour mes scores de pytrainer. J'ai exclu cette catégorie de ma page d'accueil et utilisé une partie de ma barre latérale pour montrer uniquement cette catégorie Pour exclure la catégorie ------------------------ Vous devez éditer le fichier home.html dans le dossier de votre template. Et remplacer le code par . le nom de la catégorie doit être le nom de votre catégorie selon dotclear (sans accents et sans caractères spéciaux) Pour uniquement montrer la catégorie avec vos record dans la barre latérale -------------------------------------------------

{{tpl:EntryTitle encode_html="1"}}

{{tpl:EntryExcerpt}}
{{tpl:EntryContent}}
il faut remplacer entrainements par le nom de votre catégorie, et 4 dans lastn="" c'est le nombre de billets affichés pytrainer-1.11.0/extensions/dotclear/conf.xml000066400000000000000000000010241316152275000212510ustar00rootroot00000000000000 pytrainer-1.11.0/extensions/dotclear/main.py000077500000000000000000000116231316152275000211110ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: iso-8859-1 -*- #Copyright (C) DJ dj@namurlug.org http://blog.dedj.be #This program is free software; you can redistribute it and/or #modify it under the terms of the GNU General Public License #as published by the Free Software Foundation; either version 2 #of the License, or (at your option) any later version. #This program is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #GNU General Public License for more details. #You should have received a copy of the GNU General Public License #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import xmlrpclib import SOAPpy import os from pytrainer.lib.date import second2time from pytrainer.lib.soapUtils import * from optparse import OptionParser class Main: def __init__(self,options): # on definit les parametres de connection au blog self.xmlrpcserver = options.xmlrpcserver self.blogid = options.blogid self.user = options.bloguser self.password = options.blogpass self.category_nbr = options.blogcategory #if you want accept comment, replace False by True self.comment = False #or ping self.ping = False self.category = [{'isPrimary': True, "categoryId" : self.category_nbr}] self.error = "" self.log ="" self.idrecord = options.idrecord self.webserviceserver = SOAPpy.SOAPProxy("http://localhost:8081/") #we try the connection to the xml/rpc server try : self.connect = xmlrpclib.Server(self.xmlrpcserver) self.error = False except : print "can't connect the server" def loadRecordInfo(self): record = self.webserviceserver.getRecordInfo(self.idrecord) self.sport = record["sport"] self.date = record["date"] self.distance = record["distance"] self.time = second2time(float(record["time"])) self.heure = self.time[0] self.minute = self.time[1] self.seconde = self.time[2] self.beats = record["beats"] self.comments = record["comments"] self.average = record["average"] self.calories = record["calories"] self.title = record["title"] self.upositive = record["upositive"] self.unegative = record["unegative"] def construction(self): #this methode create the content post content, the section between the ''' are on html thake wath you want #self.date, self.distance, self.time, self.beats, self.comments, self.average, self.calories, self.title, self.title, self.upositive, self.unegative, self.sport description_table = '''

%s %s

With a average of %s km/h


I have lost %s kcalories and my heart have %s pulsations (on average)

''' %(self.sport, self.title,self.average, self.calories, self.beats) return description_table def chapeau(self): chapeau_table = '''

A %s score on a distance of %s km on %sh %sm %s


''' %(self.sport,self.distance,self.heure, self.minute, self.seconde) return chapeau_table def run(self): #we load all info for the record self.loadRecordInfo() blog_desc = self.construction() blog_chap = self.chapeau() if self.error == False: #post_description = "Du " + str(self.sport) + " sur une distance de " + str(self.distance) +"km " + " en " + str(self.time) + " ce qui nous fait une moyenne de " + str(self.average) server = xmlrpclib.Server(options.xmlrpcserver) content = {'title' : self.date, 'description' : blog_desc, 'mt_allow_comments' : self.comment, 'mt_allow_pings' : self.ping,'mt_excerpt' : blog_chap} post = server.metaWeblog.newPost(self.blogid, self.user, self.password, content , True) #we change the post categories because, i( or it's the false of xml/rpc) can't select the categories before the upload on the blog change_cat = server.mt.setPostCategories(post,self.user,self.password, self.category) return "The post has been submited" self.webserviceserver.stop else: return self.log parser = OptionParser() parser.add_option("-d", "--device", dest="device") parser.add_option("-k", "--xmlrpcserver", dest="xmlrpcserver") parser.add_option("-u", "--bloguser", dest="bloguser") parser.add_option("-p", "--blogpass", dest="blogpass") parser.add_option("-l", "--blogid", dest="blogid") parser.add_option("-c", "--blogcategory", dest="blogcategory") parser.add_option("-g", "--gpxfile", dest="gpxfile") parser.add_option("-i", "--idrecord", dest="idrecord") (options,args) = parser.parse_args() try : x = Main(options) x.run() print "le score du %s a ete envoye" % x.date except xmlrpclib.Fault, f: print "ERROR on the server\n Code %i\n Reason %s" % (f.faultCode, f.faultString) pytrainer-1.11.0/extensions/fixelevation/000077500000000000000000000000001316152275000205055ustar00rootroot00000000000000pytrainer-1.11.0/extensions/fixelevation/README.txt000066400000000000000000000030331316152275000222020ustar00rootroot00000000000000 Fix Elevation pytrainer extension =============================== This extension allows you to correct elevations within gpx data. Code is based on Wojciech Lichota's gpxtools http://lichota.pl/blog/topics/gpxtools Elevations are corrected using SRTM data, therefore on first usage the necessary SRTM tile will be downloaded (large!). Tiles will be cached. Extension requires 'GDAL python bindings'. Install e.g. apt-get install python-gdal or yum install gdal-python CONFIG OPTIONS ============== n.n. USAGE ===== Simply submit the fixelevation extension preferences form and then go to the record tab and press "Fix Elevation". --------------------------- IMPORTANT ========= - On first use, the extension will download a geo_tif File (about 79mb) for your region, there is no warning dialog or similiar. - Original gpx data (in '.pytrainer/gpx/') will be overwritten. - The main record isn't forced to be reloaded at the moment, so restart pytrainer to study the manipulated heights. TODO ==== (?) Interface to specify source of SRTM data (at the moment hardcoded CGIAR mirror) (?) Interface to specify where to store SRTM data (at the moment .pytrainer/SRTM_data) (?) Store original gpx elevation data (gpx extension or whole backup file?); offer revert possibility (?) Improve Wojciech's border trick. (?) Offer alternative SRTM/DEM Sources eg http://www.viewfinderpanoramas.org/dem3.html (?) Offer batch mode to fix bundle of tracks (?) Higher order of interpolation (ie bicubic) pytrainer-1.11.0/extensions/fixelevation/conf.xml000066400000000000000000000004331316152275000221540ustar00rootroot00000000000000 pytrainer-1.11.0/extensions/fixelevation/fixelevation.py000066400000000000000000000145701316152275000235630ustar00rootroot00000000000000#!/usr/bin/env python import os #, stat, sys import logging import gtk from lxml import etree from pytrainer.lib.srtmlayer import SrtmLayer class fixelevation: _data = None _srtm = SrtmLayer() def __init__(self, parent = None, pytrainer_main = None, conf_dir = None, options = None): self.parent = parent self.pytrainer_main = pytrainer_main self.options = options self.conf_dir = conf_dir def run(self, aid, activity=None): #TODO Convert to use activity... #print activity logging.debug(">>") gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, aid) ele_fixed = True if os.path.isfile(gpx_file): # Backup original raw data as *.orig.gpx #orig_file = open(gpx_file, 'r') #orig_data = orig_file.read() #orig_file.close() #backup_file = open("%s/gpx/%s.orig.gpx" % (self.conf_dir, id), 'w') #backup_file.write(orig_data) #backup_file.close() #GPX file is ok and found, so open it logging.debug("ELE GPX file: %s found, size: %d" % (gpx_file, os.path.getsize(gpx_file))) """ Parse GPX file to ElementTree instance. """ self._data = etree.parse(gpx_file) self._xmlns = self._data.getroot().nsmap[None] nsmap = self._data.getroot().nsmap pyt_ns = "http://sourceforge.net.project/pytrainer/GPX/0/1" PYTRAINER = "{%s}" % pyt_ns self._trkpt_path = '{%s}trk/{%s}trkseg/{%s}trkpt' % (self._xmlns, self._xmlns, self._xmlns) def addExt(trackpoint, ele_new): #Add new elevation to extension tag ''' 31.1 ''' ext = etree.Element("extensions") py_ele = etree.SubElement(ext, PYTRAINER + "ele", method="srtm_bilinear") py_ele.text = str(ele_new) trackpoint.append(ext) """ Replace elevation from GPX by data from SRTM. TODO (Arnd) make a function within class fixelevation out of this for better reuse """ trackpoints = self._data.findall(self._trkpt_path) for trkpt in trackpoints: lat = float(trkpt.attrib['lat']) lon = float(trkpt.attrib['lon']) ele = trkpt.find('{%s}ele' % self._xmlns) ele_new = self._srtm.get_elevation(lat, lon) if not ele_new: ele_fixed = False break addExt(trkpt, ele_new) if not ele_fixed: # Try Google maps elevation API import cjson, urllib2, math steps = len(trackpoints) / 300 path = '' lat_prev, long_prev = 0, 0 t = 0 for t in xrange(0,len(trackpoints),steps): lat = float(trackpoints[t].attrib['lat']) lon = float(trackpoints[t].attrib['lon']) encoded_lat, lat_prev = encode_coord(lat, lat_prev) encoded_long, long_prev = encode_coord(lon, long_prev) path += encoded_lat + encoded_long t += 1 url = "http://maps.googleapis.com/maps/api/elevation/json?sensor=true&samples=%d&path=enc:" % int((len(trackpoints) / steps)) url += path try: google_ele = cjson.decode(urllib2.urlopen(url).read()) if google_ele['status'] == "OK": t_idx = 0 ele_points = len(google_ele['results']) for ele_new in xrange(0,ele_points): addExt(trackpoints[t_idx], google_ele['results'][ele_new]['elevation']) for intermediate in xrange(ele_new+1, ele_new+steps): if intermediate= 32: b.append(n & 31) n = n >> 5 b = [(c | 0x20) for c in b] b.append(n) b = [(i + 63) for i in b] return ''.join([chr(i) for i in b]) pytrainer-1.11.0/extensions/gpx2garmin/000077500000000000000000000000001316152275000200665ustar00rootroot00000000000000pytrainer-1.11.0/extensions/gpx2garmin/README000066400000000000000000000017561316152275000207570ustar00rootroot00000000000000Summary: gpx2garmin is a pytrainer (https://github.com/pytrainer/pytrainer) extension that will export the current record's gpx track to a garmin device. Requirements: gbsbabel - http://www.gpsbabel.org/ (typically installable via your repository) Usage: 1) Plug your device in via USB, switch it on. 2) Click the 'Export to device' button = export to garmin device! Caveats: - Some (all?) devices will truncate the track because they only support a limited amount of track points. The extension can (via gpsbabel) simplify a track using the limit supplied by the user. Beware of track changes (e.g. sharp bends on the map may show the trace cutting corners)! - Track names aren't part of the track data so are added by the extension from the metadata. Some devices, however, truncate the name (e.g. biking2010-08-23 > biking2010-08) so rename tracks where necessary. You may also need to fix the device permissions as documented here: http://www.gpsbabel.org/os/Linux_Hotplug.html pytrainer-1.11.0/extensions/gpx2garmin/conf.xml000066400000000000000000000006201316152275000215330ustar00rootroot00000000000000 pytrainer-1.11.0/extensions/gpx2garmin/gpx2garmin.py000077500000000000000000000036261316152275000225300ustar00rootroot00000000000000#!/usr/bin/env python import gtk import subprocess import re class gpx2garmin: def __init__(self, parent = None, pytrainer_main = None, conf_dir = None, options = None): self.limit = options["gpx2garminmaxpoints"] self.device = options["gpx2garmindevice"] self.conf_dir = conf_dir self.gpxfile = None self.tmpgpxfile = "/tmp/_gpx2garmin.gpx" self.pytrainer_main = pytrainer_main def prepareGPX(self): ' create an output file and insert a name into the stanza ' f = open(self.tmpgpxfile, 'w') name = 'default' for line in open(self.gpxfile): if re.search('^.+$', line): name = line elif re.search('^$', line): line = '%s%s' % (line, name) f.write(line) f.close() def exportGPX(self): ' export the GPX file using gpsbabel ' cmd = ["gpsbabel", "-t", "-i", "gpx", "-f", self.tmpgpxfile, "-o", "garmin"] if self.limit is not None: cmd = cmd + ["-x", "simplify,count=%s" % self.limit] cmd = cmd + ["-F", self.device] return subprocess.call(cmd) def run(self, id, activity=None): ' main extension method ' self.gpxfile = "%s/gpx/%s.gpx" % (self.conf_dir, id) self.log = "Export " try: self.prepareGPX() if self.exportGPX() == 1: # assume no device present? self.log = self.log + "failed - no device present?" else: self.log = self.log + "succeeded!" except: self.log = self.log + "failed!" md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, self.log) md.set_title(_("gpx2garmin Extension")) md.set_modal(False) md.run() md.destroy() pytrainer-1.11.0/extensions/openstreetmap/000077500000000000000000000000001316152275000206765ustar00rootroot00000000000000pytrainer-1.11.0/extensions/openstreetmap/OSM_AnonSelection.glade000066400000000000000000000057561316152275000251700ustar00rootroot00000000000000 Select your private area True center 600 400 True True vertical True vertical 0 True 3 _Ok True True True True 1 _Cancel True True True GDK_BUTTON_PRESS_MASK | GDK_STRUCTURE_MASK True 3 False 1 pytrainer-1.11.0/extensions/openstreetmap/README.txt000066400000000000000000000007351316152275000224010ustar00rootroot00000000000000 Openstreetmap pytrainer extension =============================== This extension allows you to post your sport record directly into Openstreetmap. CONFIG OPTIONS ============== You MUST fill in all the fields username: A valid Openstreetmap username password: The password for the Openstreetmap username. USAGE ===== Simply submit the openstreetmap extension preferences form and then go to the record tab and press "Post to Openstreetmap". pytrainer-1.11.0/extensions/openstreetmap/conf.xml000066400000000000000000000006531316152275000223510ustar00rootroot00000000000000 pytrainer-1.11.0/extensions/openstreetmap/openstreetmap.py000066400000000000000000000421231316152275000241400ustar00rootroot00000000000000#!/usr/bin/env python from optparse import OptionParser import os, stat import sys import logging import gtk import string from lxml import etree import httplib, httplib2 import urllib2 import mimetools, mimetypes from json import dumps, loads # for deserializing JSON data form javascript from pytrainer.extensions.mapviewer import MapViewer from pytrainer.extensions.osm import Osm class openstreetmap: def __init__(self, parent = None, pytrainer_main = None, conf_dir = None, options = None): self.parent = parent self.pytrainer_main = pytrainer_main self.options = options self.conf_dir = conf_dir self.description = " " self.tags = "" self.visibility = "private" self.mozTitle="" # Keeps embedded mozilla document title while displaying map for private area selection self.privBounds=[] # Bounds of areas to be anonymized def run(self, id, activity=None): #TODO Convert to use activity... logging.debug(">>") try: uri = "http://api.openstreetmap.org/api/0.6/gpx/create" #URI for uploading traces to OSM if 'username' not in self.options or self.options['username'] == "" or 'password' not in self.options or self.options['password'] == "": logging.error("Must have username and password configured") raise Exception("Must have username and password configured") username = self.options['username'] password = self.options['password'] gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, id) if not os.path.isfile(gpx_file): raise Exception(str(gps_file) + ' File not found') #GPX file is ok and found, so open it logging.debug("GPX file: %s found, size: %d" % (gpx_file, os.path.getsize(gpx_file))) f = open(gpx_file, 'r') file_contents = f.read() #TODO Fix to use etree functionality..... if file_contents.find("") != -1: logging.debug("GPX file: %s has ASCII encoding - updating to UTF-8 for OSM support" % gpx_file) f.close() #Close readonly file f = open(gpx_file, 'w') #and open file for writing file_contents = file_contents.replace("","", 1) f.write(file_contents) #Write new content f.close() #Close f = open(gpx_file, 'r') #Reopen in readonly mode #Get extra info from user response=self.display_options_window() if not response==gtk.RESPONSE_ACCEPT: f.close() logging.debug("User abort") return if self.makeanon: logging.debug("User requested anonymizing of GPX data") f.close() #Close standard gpxfile gpx_file = self.make_gpx_private(gpx_file) f = open(gpx_file, 'r') #Open anonymous gpxfile in readonly mode fields = (("description",self.description), ("tags",self.tags), ("visibility",self.visibility)) logging.debug("Added fields: %s" % str(fields)) #Multipart encode the request boundary, body = self.multipart_encode(fields=fields, files=(("file", f),)) content_type = 'multipart/form-data; boundary=%s' % boundary #Finished with the file so close it f.close() #Add the http headers to the request h = httplib2.Http() headers = { 'Content-Type': content_type } #Add basic authentication credentials to the request h.add_credentials(username, password) #Show user something is happening msg = _("Posting GPX trace to Openstreetmap\n\nPlease wait this could take several minutes") md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, msg) md.set_title(_("Openstreetmap Extension Processing")) md.set_modal(True) md.show() while gtk.events_pending(): # This allows the GUI to update gtk.main_iteration() # before completion of this entire action logging.debug("before request posting") #POST request to OSM res, content = h.request(uri, 'POST', body=body, headers=headers) logging.debug("after request posting") logging.debug("Got response status: %s, reason: %s, content: %s" % (res.status, res.reason, content)) if res.reason == 'OK': res_msg = "Successfully posted to OSM.\nYou should get an email with the outcome of the upload soon\n\nTrace id is %s" % content else: res_msg = "Some error occured\nGot a status %s, reason %s\nContent was: %s" % (res.status, res.reason, content) #Close 'Please wait' dialog md.destroy() #Show the user the result md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, res_msg) md.set_title(_("Openstreetmap Extension Upload Complete")) md.set_modal(False) md.run() md.destroy() except Exception as e: msg = _("Error while uploading file to OSM: " + str(e)) md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg) md.set_title(_("Openstreetmap Extension Error")) md.run() md.destroy() return finally: logging.debug("<<") def display_options_window(self): self.prefwindow = gtk.Dialog(title=_("Please add any additional information for this upload"), parent=None, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)) self.prefwindow.set_modal(False) table = gtk.Table(1,3) self.entryList = [] #Add description label = gtk.Label("Description") label.set_use_markup(True) entry = gtk.Entry() self.entryList.append(entry) table.attach(label,0,1,0,1) table.attach(entry,1,2,0,1) #Add tags label = gtk.Label("Tags") label.set_use_markup(True) entry = gtk.Entry() self.entryList.append(entry) table.attach(label,0,1,1,2) table.attach(entry,1,2,1,2) #Add visibility label = gtk.Label("Visibility") label.set_use_markup(True) combobox = gtk.combo_box_new_text() combobox.append_text("private") combobox.append_text("public") combobox.append_text("trackable") combobox.append_text("identifiable") combobox.set_active(0) table.attach(combobox,1,2,2,3) self.entryList.append(combobox) table.attach(label,0,1,2,3) #Add anonymize GPX option label = gtk.Label("Anonymize GPX Data") label.set_use_markup(True) table.attach(label,0,1,3,4) checkbutton = gtk.CheckButton() table.attach(checkbutton,1,2,3,4) self.entryList.append(checkbutton) #Add anon area selection button button = gtk.Button("Area selection") button.connect("clicked",self.areaSelect) table.attach(button,1,2,4,5) self.entryList.append(button) #Build dialog and show self.prefwindow.vbox.pack_start(table) self.prefwindow.show_all() self.prefwindow.connect("response", self.on_options_ok_clicked) response=self.prefwindow.run() self.prefwindow.destroy() return response def on_options_ok_clicked(self, widget, response_id): if not response_id == gtk.RESPONSE_ACCEPT: return response_id self.description = self.entryList[0].get_text() if self.description == "": logging.debug("A description is required - setting to default") self.description = "Uploaded from pytrainer" self.tags = self.entryList[1].get_text() self.visibility = self.entryList[2].get_active_text() self.makeanon = self.entryList[3].get_active() logging.debug("Description: %s, tags: %s, visibility: %s, makeanon: %s" % ( self.description, self.tags, self.visibility, self.makeanon) ) def areaSelect(self,dc): """ Open a window with OSM map so user could select his private/anonymized area - all GPX dots in this area will be removed before uploading to OSM """ try: wTree = gtk.glade.XML(self.pytrainer_main.data_path+"extensions/openstreetmap/OSM_AnonSelection.glade") self.privAreaWindow = wTree.get_widget("OSM_AnonSelection") dic = { "on_buttonOk_clicked" : self.privArea_Ok, "on_buttonCancel_clicked" : self.privArea_Cancel } wTree.signal_autoconnect( dic ) mapviewer = MapViewer(self.pytrainer_main.data_path, pytrainer_main=self.pytrainer_main, box=wTree.get_widget("mapBox")) json=None if self.options.has_key('privPolygon'): json=self.options['privPolygon'] htmlfile = Osm(data_path=self.pytrainer_main.data_path, waypoint=json, pytrainer_main=self.pytrainer_main).selectArea() mapviewer.display_map(htmlfile=htmlfile) mapviewer.moz.connect('title', self.parseTitle) self.privAreaWindow.show() except Exception as e: msg = "Could not init map selection screen, Error: " + str(e) md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg) md.set_title(_("Error")) md.run() md.destroy() return def parseTitle(self, moz): "Event fired when document title was changed -> meaning polygon was changed" if moz.get_title() != "": self.mozTitle=str(moz.get_title()) def privArea_Cancel(self,button): "Event fired when cancel button was pressed" self.privAreaWindow.destroy() def privArea_Ok(self,button): "Event fired when ok button was pressed" logging.debug(">> privArea_Ok") # save new private area polygon if changed if self.mozTitle=="": return # try parsing JSON try: # verify json is correct by deserializing and serializing it polygonString=dumps(loads(self.mozTitle)) # try saving extensionDir = self.pytrainer_main.data_path + "/extensions" + "/openstreetmap" if not os.path.isdir(extensionDir): loggin.error(str(e)) print ("Could not find extension path: " + str(extensionDir)) raise Exception("Could not find extension path: " + str(extensionDir)) # save new options self.options['privPolygon'] = polygonString # convert dictionary to a lists set savedOptions = [] for key in self.options: savedOptions.append((key,self.options[key])) # write new xml config file self.parent.setExtensionConfParams(extensionDir, savedOptions) except Exception as e: logging.error(str(e)) print "Error while saving extension configuration: " + str(e) msg = _(str(e)) md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg) md.set_title(_("Error while saving extension configuration")) md.run() md.destroy() finally: self.privAreaWindow.destroy() def multipart_encode(self, fields, files, boundary = None, buffer = None): ''' Multipart encode data for posting from examples at from http://odin.himinbi.org/MultipartPostHandler.py & http://bitworking.org/projects/httplib2/doc/html/libhttplib2.html ''' if boundary is None: boundary = mimetools.choose_boundary() if buffer is None: buffer = '' for (key, value) in fields: buffer += '--%s\r\n' % boundary buffer += 'Content-Disposition: form-data; name="%s"' % key buffer += '\r\n\r\n' + value + '\r\n' for (key, fd) in files: file_size = os.fstat(fd.fileno())[stat.ST_SIZE] filename = os.path.basename(fd.name) contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' buffer += '--%s\r\n' % boundary buffer += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename) buffer += 'Content-Type: %s\r\n' % contenttype # buffer += 'Content-Length: %s\r\n' % file_size fd.seek(0) buffer += '\r\n' + fd.read() + '\r\n' buffer += '--%s--\r\n\r\n' % boundary return boundary, buffer def make_gpx_private(self, gpx_file=None): ''' wipes out private data from gpx files converts laps to waypoints ''' logging.debug(">>") if gpx_file is None: return None filen = os.path.basename(gpx_file) tmpdir = self.pytrainer_main.profile.tmpdir anon_gpx_file = "%s/%s" % (tmpdir, filen) # get saved private area polygon pP=loads(self.options['privPolygon']) pP=pP['geometry']['coordinates'][0] # converts polygon's 2D matrix into a vector of just the lats or lons vector = lambda lonLat: [pP[i][lonLat] for i in range(len(pP))] # 0:lon, 1:lat # try reading private area's bounds, stored as [lon,lat] NE_LAT = max([pP[i][1] for i in range(len(pP))]) NE_LON = max([pP[i][0] for i in range(len(pP))]) SW_LAT = min([pP[i][1] for i in range(len(pP))]) SW_LON = min([pP[i][0] for i in range(len(pP))]) logging.info("Anonymizing Area: NE:%f,%f -> SW: %f,%f" % (NE_LON, NE_LAT, SW_LON, SW_LAT)) # Config parameters, not used yet FILTER_BOX = True ERASE_TIME = True LAP_TO_WAYPOINT = True tree = etree.parse(gpx_file) _xmlns = tree.getroot().nsmap[None] _trkpt_path = '{%s}trk/{%s}trkseg/{%s}trkpt' % (_xmlns, _xmlns, _xmlns) # namespace of gpx files NS = dict(ns='http://www.topografix.com/GPX/1/1') myroot = tree.getroot() gpxdataNS = string.Template(\ ".//{http://www.cluetrust.com/XML/GPXDATA/1/0}$tag") lapTag = gpxdataNS.substitute(tag="lap") endPointTag = gpxdataNS.substitute(tag="endPoint") triggerTag = gpxdataNS.substitute(tag="trigger") laps = tree.findall(lapTag) mygpx = tree.find('gpx') for lap in laps: trigger = lap.find(triggerTag) # Watch out for manually triggered laps if trigger.text == 'manual': endPoint = lap.find(endPointTag) lat = endPoint.get("lat") lon = endPoint.get("lon") # Create waypt if not in home box try: if not ((SW_LAT < float(lat) < NE_LAT) and (SW_LON < float(lon) < NE_LON)): etree.SubElement(myroot, 'wpt', attrib= {'lat':lat, 'lon':lon}) except: pass etree.strip_attributes(myroot, 'creator') # Wipe out home box for trkpt in tree.findall(_trkpt_path): lat = float(trkpt.attrib['lat']) lon = float(trkpt.attrib['lon']) if (lat < NE_LAT) & (lon < NE_LON) & (lat > SW_LAT) & (lon > SW_LON): par = trkpt.getparent() par.remove(trkpt) time = tree.xpath('//ns:trkpt/ns:time', namespaces=NS) for i in time: i.text = '1970-01-01T00:00:00+00:00' # osm regards